From 1fe2804714887c0a43077901d5446daeb2c75ab1 Mon Sep 17 00:00:00 2001 From: Manik Magar Date: Sun, 17 Mar 2019 11:54:11 -0400 Subject: [PATCH 0001/4969] Add JDBC custom credential support for postgres (#1293) --- .../testcontainers/jdbc/JDBCDriverTest.java | 23 +++++++++++++----- .../JdbcDatabaseContainerProvider.java | 22 +++++++++++++++++ .../containers/MariaDBContainerProvider.java | 24 ++++--------------- .../containers/MySQLContainerProvider.java | 18 +------------- .../containers/PostgisContainerProvider.java | 12 ++++++++++ .../PostgreSQLContainerProvider.java | 14 +++++++++++ 6 files changed, 70 insertions(+), 43 deletions(-) diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index f61f6276c5a..a94f0b0897b 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -50,9 +50,9 @@ public static Iterable data() { {"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, {"jdbc:tc:mysql:5.5.43://hostname/databasename", EnumSet.noneOf(Options.class)}, {"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:postgresql:9.6.8://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:postgis://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:postgis:9.6://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + {"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + {"jdbc:tc:postgis:9.6://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, {"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)}, {"jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class)}, {"jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, @@ -135,16 +135,27 @@ private void performTestForScriptedSchema(String jdbcUrl) throws SQLException { private void performTestForJDBCParamUsage(String jdbcUrl) throws SQLException { try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) { - boolean result = new QueryRunner(dataSource).query("select CURRENT_USER()", rs -> { + boolean result = new QueryRunner(dataSource).query("select CURRENT_USER", rs -> { rs.next(); String resultUser = rs.getString(1); - assertEquals("User from query param is created.", "someuser@%", resultUser); + // Not all databases (eg. Postgres) return @% at the end of user name. We just need to make sure the user name matches. + if (resultUser.endsWith("@%")) { + resultUser = resultUser.substring(0, resultUser.length() - 2); + } + assertEquals("User from query param is created.", "someuser", resultUser); return true; }); assertTrue("The database returned a record as expected", result); - result = new QueryRunner(dataSource).query("SELECT DATABASE()", rs -> { + String databaseQuery = "SELECT DATABASE()"; + // Postgres does not have Database() as a function + String databaseType = ConnectionUrl.newInstance(jdbcUrl).getDatabaseType(); + if (databaseType.equalsIgnoreCase("postgresql") || databaseType.equalsIgnoreCase("postgis")) { + databaseQuery = "SELECT CURRENT_DATABASE()"; + } + + result = new QueryRunner(dataSource).query(databaseQuery, rs -> { rs.next(); String resultDB = rs.getString(1); assertEquals("Database name from URL String is used.", "databasename", resultDB); diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java index 2a73879a572..f2ebde857c5 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java @@ -4,6 +4,8 @@ import lombok.extern.slf4j.Slf4j; +import java.util.Objects; + /** * Base class for classes that can provide a JDBC container. */ @@ -49,4 +51,24 @@ public JdbcDatabaseContainer newInstance(ConnectionUrl url) { return newInstance(); } } + + protected JdbcDatabaseContainer newInstanceFromConnectionUrl(ConnectionUrl connectionUrl, final String userParamName, final String pwdParamName) { + Objects.requireNonNull(connectionUrl, "Connection URL cannot be null"); + + final String databaseName = connectionUrl.getDatabaseName().orElse("test"); + final String user = connectionUrl.getQueryParameters().getOrDefault(userParamName, "test"); + final String password = connectionUrl.getQueryParameters().getOrDefault(pwdParamName, "test"); + + final JdbcDatabaseContainer instance; + if (connectionUrl.getImageTag().isPresent()) { + instance = newInstance(connectionUrl.getImageTag().get()); + } else { + instance = newInstance(); + } + + return instance + .withDatabaseName(databaseName) + .withUsername(user) + .withPassword(password); + } } diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java index deb1b2c5c5e..86f30ee59e5 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java @@ -8,7 +8,7 @@ * Factory for MariaDB org.testcontainers.containers. */ public class MariaDBContainerProvider extends JdbcDatabaseContainerProvider { - + private static final String USER_PARAM = "user"; private static final String PASSWORD_PARAM = "password"; @@ -27,26 +27,10 @@ public JdbcDatabaseContainer newInstance() { public JdbcDatabaseContainer newInstance(String tag) { return new MariaDBContainer(MariaDBContainer.IMAGE + ":" + tag); } - + @Override public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { - Objects.requireNonNull(connectionUrl, "Connection URL cannot be null"); - - final String databaseName = connectionUrl.getDatabaseName().orElse("test"); - final String user = connectionUrl.getQueryParameters().getOrDefault(USER_PARAM, "test"); - final String password = connectionUrl.getQueryParameters().getOrDefault(PASSWORD_PARAM, "test"); - - final JdbcDatabaseContainer instance; - if (connectionUrl.getImageTag().isPresent()) { - instance = newInstance(connectionUrl.getImageTag().get()); - } else { - instance = newInstance(); - } - - return instance - .withDatabaseName(databaseName) - .withUsername(user) - .withPassword(password); + return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); } - + } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java index cfc072707da..7d4919f4b26 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java @@ -34,23 +34,7 @@ public JdbcDatabaseContainer newInstance(String tag) { @Override public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { - Objects.requireNonNull(connectionUrl, "Connection URL cannot be null"); - - final String databaseName = connectionUrl.getDatabaseName().orElse("test"); - final String user = connectionUrl.getQueryParameters().getOrDefault(USER_PARAM, "test"); - final String password = connectionUrl.getQueryParameters().getOrDefault(PASSWORD_PARAM, "test"); - - final JdbcDatabaseContainer instance; - if (connectionUrl.getImageTag().isPresent()) { - instance = newInstance(connectionUrl.getImageTag().get()); - } else { - instance = newInstance(); - } - - return instance - .withDatabaseName(databaseName) - .withUsername(user) - .withPassword(password); + return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); } } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java index 644a5ef8c84..83f15e3fd6f 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java @@ -1,5 +1,9 @@ package org.testcontainers.containers; +import org.testcontainers.jdbc.ConnectionUrl; + +import java.util.Objects; + /** * Factory for PostGIS containers, which are a special flavour of PostgreSQL. */ @@ -8,6 +12,9 @@ public class PostgisContainerProvider extends JdbcDatabaseContainerProvider { private static final String NAME = "postgis"; private static final String DEFAULT_TAG = "10"; private static final String DEFAULT_IMAGE = "mdillon/postgis"; + public static final String USER_PARAM = "user"; + public static final String PASSWORD_PARAM = "password"; + @Override public boolean supports(String databaseType) { @@ -23,4 +30,9 @@ public JdbcDatabaseContainer newInstance() { public JdbcDatabaseContainer newInstance(String tag) { return new PostgreSQLContainer(DEFAULT_IMAGE + ":" + tag); } + + @Override + public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { + return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); + } } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java index 394fd5d49b8..77a0329c22c 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java @@ -1,9 +1,17 @@ package org.testcontainers.containers; +import org.testcontainers.jdbc.ConnectionUrl; + +import java.util.Objects; + /** * Factory for PostgreSQL containers. */ public class PostgreSQLContainerProvider extends JdbcDatabaseContainerProvider { + + public static final String USER_PARAM = "user"; + public static final String PASSWORD_PARAM = "password"; + @Override public boolean supports(String databaseType) { return databaseType.equals(PostgreSQLContainer.NAME); @@ -18,4 +26,10 @@ public JdbcDatabaseContainer newInstance() { public JdbcDatabaseContainer newInstance(String tag) { return new PostgreSQLContainer(PostgreSQLContainer.IMAGE + ":" + tag); } + + @Override + public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { + return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); + } + } From e326e3ec42052bb6424cb0193c178b85fd1d1457 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sun, 17 Mar 2019 15:55:54 +0000 Subject: [PATCH 0002/4969] Bump mockito-core from 2.24.5 to 2.25.0 in /core (#1294) Bumps [mockito-core](https://github.com/mockito/mockito) from 2.24.5 to 2.25.0.
Release notes *Sourced from [mockito-core's releases](https://github.com/mockito/mockito/releases).* > ## v2.25.0 > *Release notes were automatically generated by [Shipkit](http://shipkit.org/)* > > #### 2.25.0 > - 2019-03-05 - [11 commits](https://github.com/mockito/mockito/compare/v2.24.10...v2.25.0) by [Szczepan Faber](https://github.com/mockitoguy) (10), Garfield Tan (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.25.0-green.svg)](https://bintray.com/mockito/maven/mockito/2.25.0) > - New API to clean up all inline mocks after test [([#1619](https://github-redirect.dependabot.com/mockito/mockito/issues/1619))](https://github-redirect.dependabot.com/mockito/mockito/pull/1619) > - Memory leak in mockito-inline calling method on mock with at least a mock as parameter [([#1614](https://github-redirect.dependabot.com/mockito/mockito/issues/1614))](https://github-redirect.dependabot.com/mockito/mockito/issues/1614) > - Cross-references and a single spy cause memory leak [([#1533](https://github-redirect.dependabot.com/mockito/mockito/issues/1533))](https://github-redirect.dependabot.com/mockito/mockito/issues/1533) > - Nested spies cause memory leaks [([#1532](https://github-redirect.dependabot.com/mockito/mockito/issues/1532))](https://github-redirect.dependabot.com/mockito/mockito/issues/1532) > > ## v2.24.10 > *Release notes were automatically generated by [Shipkit](http://shipkit.org/)* > > #### 2.24.10 > - 2019-03-05 - [4 commits](https://github.com/mockito/mockito/compare/v2.24.9...v2.24.10) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.10-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.10) > - Prevent NPE in findTypeFromGenericInArguments [([#1648](https://github-redirect.dependabot.com/mockito/mockito/issues/1648))](https://github-redirect.dependabot.com/mockito/mockito/pull/1648) > > ## v2.24.9 > *Release notes were automatically generated by [Shipkit](http://shipkit.org/)* > > #### 2.24.9 > - 2019-03-04 - [12 commits](https://github.com/mockito/mockito/compare/v2.24.7...v2.24.9) by 6 authors - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.9-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.9) > - Commits: [Brice Dutheil](https://github.com/bric3) (5), [Tim van der Lippe](https://github.com/TimvdLippe) (3), [epeee](https://github.com/epeee) (1), [Fr Jeremy Krieg](https://github.com/kriegfrj) (1), [PaweB PamuBa](https://github.com/PawelPamula) (1), shipkit-org (1) > - [Java 9 support] ClassCastExceptions with JDK9 javac [([#357](https://github-redirect.dependabot.com/mockito/mockito/issues/357))](https://github-redirect.dependabot.com/mockito/mockito/issues/357) > - [Bugfixes] RETURNS_DEEP_STUBS causes "Raw extraction not supported for : 'null'" in some cases [([#1621](https://github-redirect.dependabot.com/mockito/mockito/issues/1621))](https://github-redirect.dependabot.com/mockito/mockito/issues/1621) > - Update shipkit plugin (v2.1.6) [([#1647](https://github-redirect.dependabot.com/mockito/mockito/issues/1647))](https://github-redirect.dependabot.com/mockito/mockito/pull/1647) > - VerificationCollector to handle non-matching args and other assertions [([#1644](https://github-redirect.dependabot.com/mockito/mockito/issues/1644))](https://github-redirect.dependabot.com/mockito/mockito/pull/1644) > - VerificationCollector doesn't work for invocations with non-matching args [([#1642](https://github-redirect.dependabot.com/mockito/mockito/issues/1642))](https://github-redirect.dependabot.com/mockito/mockito/issues/1642) > - Fix returns mocks for final classes [([#1641](https://github-redirect.dependabot.com/mockito/mockito/issues/1641))](https://github-redirect.dependabot.com/mockito/mockito/pull/1641) > - Removes inaccessible links from javadocs in Mockito.java [([#1639](https://github-redirect.dependabot.com/mockito/mockito/issues/1639))](https://github-redirect.dependabot.com/mockito/mockito/pull/1639) > - Mockito.java contains inaccessible links to articles. [([#1638](https://github-redirect.dependabot.com/mockito/mockito/issues/1638))](https://github-redirect.dependabot.com/mockito/mockito/issues/1638) > - Handle terminal type var with bounds [([#1624](https://github-redirect.dependabot.com/mockito/mockito/issues/1624))](https://github-redirect.dependabot.com/mockito/mockito/pull/1624) > - Return null instead of causing a CCE [([#1612](https://github-redirect.dependabot.com/mockito/mockito/issues/1612))](https://github-redirect.dependabot.com/mockito/mockito/pull/1612) > > ## v2.24.8 > *Release notes were automatically generated by [Shipkit](http://shipkit.org/)* > > #### 2.24.8 > - 2019-03-01 - [2 commits](https://github.com/mockito/mockito/compare/v2.24.7...v2.24.8) by [PaweB PamuBa](https://github.com/PawelPamula) (1), [shipkit-org](https://github.com/shipkit-org) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.8-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.8) > - Removes inaccessible links from javadocs in Mockito.java [([#1639](https://github-redirect.dependabot.com/mockito/mockito/issues/1639))](https://github-redirect.dependabot.com/mockito/mockito/pull/1639) > - Mockito.java contains inaccessible links to articles. [([#1638](https://github-redirect.dependabot.com/mockito/mockito/issues/1638))](https://github-redirect.dependabot.com/mockito/mockito/issues/1638) > > ## v2.24.7 > *Release notes were automatically generated by [Shipkit](http://shipkit.org/)* > > #### 2.24.7 > - 2019-02-28 - [2 commits](https://github.com/mockito/mockito/compare/v2.24.6...v2.24.7) by [shipkit-org](https://github.com/shipkit-org) (1), [Tim van der Lippe](https://github.com/TimvdLippe) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.7-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.7) > - Fix handling of generics in ReturnsMocks [([#1635](https://github-redirect.dependabot.com/mockito/mockito/issues/1635))](https://github-redirect.dependabot.com/mockito/mockito/pull/1635) > > ## v2.24.6 > ... (truncated)
Commits - [`70c6fa4`](https://github.com/mockito/mockito/commit/70c6fa4a056e5bf6ce1c464d5e4c5bd6431a2828) 2.25.0 release (previous 2.24.10) + release notes updated by CI build 3956 - [`a7ee084`](https://github.com/mockito/mockito/commit/a7ee084e8501b29d74466213c869f9acbd26635c) Merge pull request [#1619](https://github-redirect.dependabot.com/mockito/mockito/issues/1619) from ttanxu/release/2.x - [`959cba4`](https://github.com/mockito/mockito/commit/959cba41910f7bf215fe66d2932bf3b348d83014) Merge branch 'release/2.x' into release/2.x - [`1641868`](https://github.com/mockito/mockito/commit/1641868a4651bf5c020f7afeb50fc728c3e38d27) Javadoc - [`d61a8be`](https://github.com/mockito/mockito/commit/d61a8beb9a4bb8234e3685c9c55dff05de8d2673) Added missing coverage - [`af2d33b`](https://github.com/mockito/mockito/commit/af2d33be7fbfecad172cef4da2127b8d9a6fbe31) 2.24.10 release (previous 2.24.9) + release notes updated by CI build 3953 - [`1183d1f`](https://github.com/mockito/mockito/commit/1183d1fa72311ef82998cd91ee5f4bb5182c96d5) Merge pull request [#1648](https://github-redirect.dependabot.com/mockito/mockito/issues/1648) from mockito/TimvdLippe-patch-1 - [`2894895`](https://github.com/mockito/mockito/commit/2894895746950be644af81055bf7543ff4e9f832) Fix checkstyle warnings - [`2d21a5a`](https://github.com/mockito/mockito/commit/2d21a5abc744084646d9939d5ed9d1825695af9a) Add regression test - [`b5e9400`](https://github.com/mockito/mockito/commit/b5e9400b01f8bfbda436c79ce5f857b3dc613657) Prevent NPE in findTypeFromGenericInArguments - Additional commits viewable in [compare view](https://github.com/mockito/mockito/compare/v2.24.5...v2.25.0)

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.mockito:mockito-core&package-manager=gradle&previous-version=2.24.5&new-version=2.25.0)](https://dependabot.com/compatibility-score.html?dependency-name=org.mockito:mockito-core&package-manager=gradle&previous-version=2.24.5&new-version=2.25.0) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index bea5b94da63..19edabfb813 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -120,7 +120,7 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.6.0' testCompile 'org.mongodb:mongo-java-driver:3.10.1' - testCompile ('org.mockito:mockito-core:2.24.5') { + testCompile ('org.mockito:mockito-core:2.25.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From b1b8cf354a0fc15af23d1bd082f817039b89bfab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sun, 17 Mar 2019 15:56:08 +0000 Subject: [PATCH 0003/4969] Bump transport from 6.6.1 to 6.6.2 in /modules/elasticsearch (#1302) Bumps [transport](https://github.com/elastic/elasticsearch) from 6.6.1 to 6.6.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v6.6.1...v6.6.2) Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index a41455f76aa..7d8f0f5eb1a 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.6.1" - testCompile "org.elasticsearch.client:transport:6.6.1" + testCompile "org.elasticsearch.client:transport:6.6.2" } From 5a3c9f395043ef2c5d3ff123dfaeb7771b0234fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sun, 17 Mar 2019 15:56:43 +0000 Subject: [PATCH 0004/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#1301) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 6.6.1 to 6.6.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v6.6.1...v6.6.2) Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 7d8f0f5eb1a..78d8c96a4be 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.6.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.6.2" testCompile "org.elasticsearch.client:transport:6.6.2" } From 604fd0ee0e8aba424c8ea63e887b4b941bb533d5 Mon Sep 17 00:00:00 2001 From: Gerasimov Gennady Date: Sun, 17 Mar 2019 23:14:51 +0300 Subject: [PATCH 0005/4969] #1256 Added fsync=off option by default (#1280) --- .../org/testcontainers/containers/PostgreSQLContainer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 232daa89284..13c5b49efc7 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -22,6 +22,8 @@ public class PostgreSQLContainer> extends private String username = "test"; private String password = "test"; + private static final String FSYNC_OFF_OPTION = "fsync=off"; + public PostgreSQLContainer() { this(IMAGE + ":" + DEFAULT_TAG); } @@ -47,7 +49,7 @@ protected void configure() { addEnv("POSTGRES_DB", databaseName); addEnv("POSTGRES_USER", username); addEnv("POSTGRES_PASSWORD", password); - setCommand("postgres"); + setCommand("postgres", "-c", FSYNC_OFF_OPTION); } @Override From 43e971f43a87f25a75c4410d3199cf576d157c92 Mon Sep 17 00:00:00 2001 From: Dan Markhasin Date: Mon, 18 Mar 2019 17:53:47 +0200 Subject: [PATCH 0006/4969] get exitcode from inspectExecCmd (#1318) * get exitcode from inspectExecCmd * Update core/src/main/java/org/testcontainers/containers/Container.java Co-Authored-By: dmarkhas * Update core/src/main/java/org/testcontainers/containers/Container.java Co-Authored-By: dmarkhas * Update core/src/main/java/org/testcontainers/containers/Container.java Co-Authored-By: dmarkhas * Use Lombok's `@Value` in `ExecResult` * Update Container.java --- .../testcontainers/containers/Container.java | 30 +++++++++---------- .../containers/ExecInContainerPattern.java | 2 ++ .../InternalCommandPortListeningCheck.java | 10 +++---- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index 6c5e547f7fa..ca327149ab5 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -3,7 +3,10 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Info; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.NonNull; +import lombok.Value; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; @@ -36,24 +39,21 @@ default SELF self() { } /** - * Class to hold results from a "docker exec" command. Note that, due to the limitations of the - * docker API, there's no easy way to get the result code from the process we ran. + * Class to hold results from a "docker exec" command */ + @Value + @AllArgsConstructor(access = AccessLevel.MODULE) class ExecResult { - private final String stdout; - private final String stderr; - + int exitCode; + String stdout; + String stderr; + + /** + * @deprecated should not be instantiated outside of the library, please migrate + */ + @Deprecated public ExecResult(String stdout, String stderr) { - this.stdout = stdout; - this.stderr = stderr; - } - - public String getStdout() { - return stdout; - } - - public String getStderr() { - return stderr; + this(-1, stdout, stderr); } } diff --git a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java index af1e7e8d503..3d0f4c2c360 100644 --- a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java +++ b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java @@ -82,8 +82,10 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn callback.addConsumer(OutputFrame.OutputType.STDERR, stderrConsumer); dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(callback).awaitCompletion(); + Integer exitCode = dockerClient.inspectExecCmd(execCreateCmdResponse.getId()).exec().getExitCode(); final Container.ExecResult result = new Container.ExecResult( + exitCode, stdoutConsumer.toString(outputCharset), stderrConsumer.toString(outputCharset)); diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index a4ba013b9d7..bad30fef653 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -14,8 +14,6 @@ @RequiredArgsConstructor public class InternalCommandPortListeningCheck implements java.util.concurrent.Callable { - private static final String SUCCESS_MARKER = "TESTCONTAINERS_SUCCESS"; - private final WaitStrategyTarget waitStrategyTarget; private final Set internalPorts; @@ -30,14 +28,14 @@ public Boolean call() { private void tryPort(Integer internalPort) { String[][] commands = { - {"/bin/sh", "-c", format("cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%x && echo %s", internalPort, SUCCESS_MARKER)}, - {"/bin/sh", "-c", format("nc -vz -w 1 localhost %d && echo %s", internalPort, SUCCESS_MARKER)}, - {"/bin/bash", "-c", format(" Date: Mon, 18 Mar 2019 21:18:21 +0100 Subject: [PATCH 0007/4969] CredsStore validation for RegistryAuthLocator (#1303) ## Fixes `RegistryAuthLocator` : Add additional validation for existing key `credsStore` but empty value ## Purpose Define behaviour for RegistryAuthLocator on empty values in config Offer: - fail on empty value - ignore field with empty value & log -> return null; ## Background Context Currently experienced problems using testcontainers, I found existing issue for my problem and decided to help. Potentially, put checks for all existing `keys` with empty strings ## References ref: #921 --- .../testcontainers/utility/RegistryAuthLocator.java | 4 ++++ .../utility/RegistryAuthLocatorTest.java | 10 ++++++++++ .../resources/auth-config/config-with-store-empty.json | 9 +++++++++ 3 files changed, 23 insertions(+) create mode 100644 core/src/test/resources/auth-config/config-with-store-empty.json diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index efe7303d581..402a15d58b4 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -183,6 +183,10 @@ private AuthConfig authConfigUsingStore(final JsonNode config, final String repo final JsonNode credsStoreNode = config.get("credsStore"); if (credsStoreNode != null && !credsStoreNode.isMissingNode() && credsStoreNode.isTextual()) { final String credsStore = credsStoreNode.asText(); + if (isBlank(credsStore)) { + log.warn("Docker auth config credsStore field will be ignored, because value is blank"); + return null; + } return runCredentialProvider(reposName, credsStore); } return null; diff --git a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java index fa1770df4f1..938505c0212 100644 --- a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java +++ b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java @@ -101,6 +101,16 @@ public void lookupAuthConfigWithCredentialsNotFound() throws URISyntaxException discoveredMessage); } + @Test + public void lookupAuthConfigWithCredStoreEmpty() throws URISyntaxException { + final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-store-empty.json"); + + DockerImageName dockerImageName = new DockerImageName("registry2.example.com/org/repo"); + final AuthConfig authConfig = authLocator.lookupAuthConfig(dockerImageName, new AuthConfig()); + + assertNull("CredStore field will be ignored, because value is blank", authConfig.getAuth()); + } + @NotNull private RegistryAuthLocator createTestAuthLocator(String configName) throws URISyntaxException { return createTestAuthLocator(configName, new HashMap<>()); diff --git a/core/src/test/resources/auth-config/config-with-store-empty.json b/core/src/test/resources/auth-config/config-with-store-empty.json new file mode 100644 index 00000000000..4106187ff1e --- /dev/null +++ b/core/src/test/resources/auth-config/config-with-store-empty.json @@ -0,0 +1,9 @@ +{ + "auths": { + "registry.example.com": {} + }, + "HttpHeaders": { + "User-Agent": "Docker-Client/18.03.0-ce (darwin)" + }, + "credsStore": "" +} From 21f64ea8accd77f669711d09d0cfc8798cd366b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:19:24 +0000 Subject: [PATCH 0008/4969] Bump junit-jupiter-api from 5.4.0 to 5.4.1 in /modules/junit-jupiter (#1311) Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.4.0 to 5.4.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.4.0...r5.4.1) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index fff8099606d..17f8fbc419b 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.4.0' + compile 'org.junit.jupiter:junit-jupiter-api:5.4.1' testCompile project(':mysql') testCompile project(':postgresql') From 42a25cba65aa09045dbbe6ae47d80ea2678cc1c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:28:22 +0000 Subject: [PATCH 0009/4969] Bump assertj-core from 3.12.1 to 3.12.2 in /modules/pulsar (#1312) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.12.1 to 3.12.2.
Commits - [`5dd7fac`](https://github.com/joel-costigliola/assertj-core/commit/5dd7facdfb3e3a17e5dbbc213ab9ac6656987186) [maven-release-plugin] prepare release assertj-core-3.12.2 - [`d427863`](https://github.com/joel-costigliola/assertj-core/commit/d42786341730e51ee9203d5eacfddb2ea59f5592) Update Guava test dependency to version 27.1-jre. - [`cb5b285`](https://github.com/joel-costigliola/assertj-core/commit/cb5b285ac7e0e74fc6059cf8606fc0a82a8deb12) anySatisfy (Maps): do not continue evaluating elements once we found a match ... - [`8d83c41`](https://github.com/joel-costigliola/assertj-core/commit/8d83c419f34f7dab982cd84d438480cf74e3b17a) Ignore static methods when finding property accessors. Fixes [#1458](https://github-redirect.dependabot.com/joel-costigliola/assertj-core/issues/1458) - [`b600f5b`](https://github.com/joel-costigliola/assertj-core/commit/b600f5be7e49efff47199bc02e2bca3d02466354) Use URI#create (which does not throw a checked Exception) in tests. - [`91af5c9`](https://github.com/joel-costigliola/assertj-core/commit/91af5c9838a05b8b3d7dc7c2e0fdaf0d25712533) [maven-release-plugin] prepare for next development iteration - See full diff in [compare view](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.12.1...assertj-core-3.12.2)

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.assertj:assertj-core&package-manager=gradle&previous-version=3.12.1&new-version=3.12.2)](https://dependabot.com/compatibility-score.html?dependency-name=org.assertj:assertj-core&package-manager=gradle&previous-version=3.12.1&new-version=3.12.2) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index eaddd4a3862..a67c83cc923 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,5 +4,5 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.0' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.1' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.2' } From 4c6518fa8c974996d2801aec45d01c591d0f10eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:28:37 +0000 Subject: [PATCH 0010/4969] Bump mockito-core from 2.25.0 to 2.25.1 in /core (#1313) Bumps [mockito-core](https://github.com/mockito/mockito) from 2.25.0 to 2.25.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v2.25.0...v2.25.1) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 19edabfb813..be95690bc1e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -120,7 +120,7 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.6.0' testCompile 'org.mongodb:mongo-java-driver:3.10.1' - testCompile ('org.mockito:mockito-core:2.25.0') { + testCompile ('org.mockito:mockito-core:2.25.1') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 5a7924ac3093d31452b1a84e28375fe7d7bcc0c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:28:49 +0000 Subject: [PATCH 0011/4969] Bump junit-jupiter-engine from 5.4.0 to 5.4.1 in /modules/junit-jupiter (#1310) Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.4.0 to 5.4.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.4.0...r5.4.1) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 17f8fbc419b..9ab71fe7c43 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -11,7 +11,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.15' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.0' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.1' } test { From a69662d1cb7667cc001e6a6704cb8e44509b4387 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:29:01 +0000 Subject: [PATCH 0012/4969] Bump assertj-core from 3.12.1 to 3.12.2 in /modules/kafka (#1316) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.12.1 to 3.12.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.12.1...assertj-core-3.12.2) Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index ad781298deb..6985f7a89a6 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.1.1' - testCompile 'org.assertj:assertj-core:3.12.1' + testCompile 'org.assertj:assertj-core:3.12.2' testCompile 'com.google.guava:guava:23.0' } From f23dbdf37493a77f80c09dddd57007ee31897845 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:29:34 +0000 Subject: [PATCH 0013/4969] Bump assertj-core from 3.12.1 to 3.12.2 in /core (#1314) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ If you make any changes to it yourself then they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.12.1 to 3.12.2.
Commits - [`5dd7fac`](https://github.com/joel-costigliola/assertj-core/commit/5dd7facdfb3e3a17e5dbbc213ab9ac6656987186) [maven-release-plugin] prepare release assertj-core-3.12.2 - [`d427863`](https://github.com/joel-costigliola/assertj-core/commit/d42786341730e51ee9203d5eacfddb2ea59f5592) Update Guava test dependency to version 27.1-jre. - [`cb5b285`](https://github.com/joel-costigliola/assertj-core/commit/cb5b285ac7e0e74fc6059cf8606fc0a82a8deb12) anySatisfy (Maps): do not continue evaluating elements once we found a match ... - [`8d83c41`](https://github.com/joel-costigliola/assertj-core/commit/8d83c419f34f7dab982cd84d438480cf74e3b17a) Ignore static methods when finding property accessors. Fixes [#1458](https://github-redirect.dependabot.com/joel-costigliola/assertj-core/issues/1458) - [`b600f5b`](https://github.com/joel-costigliola/assertj-core/commit/b600f5be7e49efff47199bc02e2bca3d02466354) Use URI#create (which does not throw a checked Exception) in tests. - [`91af5c9`](https://github.com/joel-costigliola/assertj-core/commit/91af5c9838a05b8b3d7dc7c2e0fdaf0d25712533) [maven-release-plugin] prepare for next development iteration - See full diff in [compare view](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.12.1...assertj-core-3.12.2)

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.assertj:assertj-core&package-manager=gradle&previous-version=3.12.1&new-version=3.12.2)](https://dependabot.com/compatibility-score.html?dependency-name=org.assertj:assertj-core&package-manager=gradle&previous-version=3.12.1&new-version=3.12.2) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index be95690bc1e..4f0a0a7392d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -129,6 +129,6 @@ dependencies { jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' - jarFileTestCompile 'org.assertj:assertj-core:3.12.1' + jarFileTestCompile 'org.assertj:assertj-core:3.12.2' jarFileTestCompile 'org.ow2.asm:asm-debug-all:5.2' } From b12c9470b18beca6c072a7afa38fd9c59f0f983f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:29:46 +0000 Subject: [PATCH 0014/4969] Bump assertj-core from 3.12.1 to 3.12.2 in /modules/neo4j (#1315) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.12.1 to 3.12.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.12.1...assertj-core-3.12.2) Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index abdd5044cdc..092cb3a6889 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -30,5 +30,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.3" - testCompile 'org.assertj:assertj-core:3.12.1' + testCompile 'org.assertj:assertj-core:3.12.2' } From 34a2347055f232a98cce15dc7cd148690e699106 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 18 Mar 2019 20:29:58 +0000 Subject: [PATCH 0015/4969] Bump mariadb-java-client from 2.4.0 to 2.4.1 in /modules/mariadb (#1317) Bumps [mariadb-java-client](https://github.com/MariaDB/mariadb-connector-j) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/MariaDB/mariadb-connector-j/releases) - [Commits](https://github.com/MariaDB/mariadb-connector-j/commits) Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 3cebd55943d..110e63f2444 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.0' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.1' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.16' From 9c651fe3052cb2f68d6faca887d1efe9e5e5e7b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 19 Mar 2019 09:28:33 +0000 Subject: [PATCH 0016/4969] Bump tomcat-jdbc from 9.0.16 to 9.0.17 in /modules/mysql (#1321) Bumps tomcat-jdbc from 9.0.16 to 9.0.17. [![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.apache.tomcat:tomcat-jdbc&package-manager=gradle&previous-version=9.0.16&new-version=9.0.17)](https://dependabot.com/compatibility-score.html?dependency-name=org.apache.tomcat:tomcat-jdbc&package-manager=gradle&previous-version=9.0.16&new-version=9.0.17) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index deaf441f633..0703b29ad3a 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.14' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.16' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.17' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From 50db30a9d36a21d83b81314216cc2419325140ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 19 Mar 2019 09:28:52 +0000 Subject: [PATCH 0017/4969] Bump tomcat-jdbc from 9.0.16 to 9.0.17 in /modules/mariadb (#1322) Bumps tomcat-jdbc from 9.0.16 to 9.0.17. Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 110e63f2444..1f679b7a592 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.1' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.16' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.17' testCompile 'org.vibur:vibur-dbcp:22.2' } From 5109f4c1f4f04460fe5f1b965d974125ec4c0b57 Mon Sep 17 00:00:00 2001 From: Dan Markhasin Date: Tue, 19 Mar 2019 11:53:19 +0200 Subject: [PATCH 0018/4969] updated docs with exitCode (#1319) --- docs/examples/src/test/java/generic/ExecTest.java | 2 ++ docs/features/commands.md | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/examples/src/test/java/generic/ExecTest.java b/docs/examples/src/test/java/generic/ExecTest.java index 3ff67956d39..e160390c293 100644 --- a/docs/examples/src/test/java/generic/ExecTest.java +++ b/docs/examples/src/test/java/generic/ExecTest.java @@ -24,7 +24,9 @@ public void testSimpleExec() throws IOException, InterruptedException { // execReadingStdout { Container.ExecResult lsResult = container.execInContainer("ls", "-al", "/"); String stdout = lsResult.getStdout(); + int exitCode = lsResult.getExitCode(); assertTrue(stdout.contains("somefile.txt")); + assertTrue(exitCode == 0); // } } } diff --git a/docs/features/commands.md b/docs/features/commands.md index 238c140765e..197871ebe02 100644 --- a/docs/features/commands.md +++ b/docs/features/commands.md @@ -16,14 +16,12 @@ Your test can execute a command inside a running container, similar to a `docker [Executing a command inside a running container](../examples/src/test/java/generic/ExecTest.java) inside_block:standaloneExec -This can be useful for software that has a command line administration tool. You can also get the output (stdout/stderr) from the command - for example: +This can be useful for software that has a command line administration tool. You can also get the output (stdout/stderr) and exit code from the command - for example: [Executing a command inside a running container and reading the result](../examples/src/test/java/generic/ExecTest.java) inside_block:execReadingStdout -Note that there is no way to get the return code of the executed command, only stdout/stderr. - ## Environment variables To add environment variables to the container, use `withEnv`: From 99e2c1ce00b00c4758cfa4247fc7104475ecae26 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 19 Mar 2019 11:00:07 +0100 Subject: [PATCH 0019/4969] Remove netty transport, rework shading (#1307) * Remove Netty transport from docker-java * Remove Netty transport from docker-java, rework the shading config * exclude public API dependencies from the shaded ones * encode filter's key, remove `okhttp` stage * fix the jupiter tests * fix the spock tests --- build.gradle | 33 +- core/build.gradle | 46 +-- .../testcontainers/JarFileShadingTest.java | 8 +- .../dockerjava/core/util/FiltersEncoder.java | 27 ++ .../DockerClientProviderStrategy.java | 4 - .../TestcontainersDockerCmdExecFactory.java | 317 ------------------ .../utility/ResourceReaper.java | 19 +- .../core/util/FiltersEncoderTest.java | 28 ++ modules/junit-jupiter/build.gradle | 1 + modules/spock/build.gradle | 3 +- 10 files changed, 94 insertions(+), 392 deletions(-) create mode 100644 core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/transport/TestcontainersDockerCmdExecFactory.java create mode 100644 core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java diff --git a/build.gradle b/build.gradle index 318562a8936..75977bd540f 100644 --- a/build.gradle +++ b/build.gradle @@ -56,32 +56,17 @@ subprojects { configurations = [] classifier = null - relocate('META-INF/native/libnetty', 'META-INF/native/liborg-testcontainers-shaded-netty') - - [ - "org.apache.http", - "org.apache.commons.lang", - "org.apache.commons.io", - "org.apache.commons.codec", - "org.glassfish", - "org.aopalliance", - "org.jvnet", - "javax.annotation", - "javax.inject", - "javax.ws.rs", - "com.fasterxml.jackson", - "jersey.repackaged", - "com.google", - "io.netty", - "org.bouncycastle", - "org.zeroturnaround", - "okhttp3", - "okio", - "org.scalasbt.ipcsocket", - "com.trilead.ssh2", - ].each { relocate(it, "org.testcontainers.shaded.$it") } + // Keep docker-java's package inside the final jar + relocate("com.github.dockerjava", "com.github.dockerjava") } + task relocateShadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation) { + target = tasks.shadowJar + prefix = "org.testcontainers.shaded" + } + + tasks.shadowJar.dependsOn tasks.relocateShadowJar + publishing { publications { mavenJava(MavenPublication) { publication -> diff --git a/core/build.gradle b/core/build.gradle index 4f0a0a7392d..1e3083c4542 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -21,7 +21,6 @@ shadowJar { exclude 'org/newsclub/**' [ - 'META-INF/io.netty.versions.properties', 'META-INF/NOTICE', 'META-INF/NOTICE.txt', 'META-INF/LICENSE', @@ -33,31 +32,16 @@ shadowJar { 'META-INF/services/com.fasterxml.jackson.core.*', 'META-INF/services/com.github.dockerjava.api.command.*', 'META-INF/services/javax.ws.rs.ext.*', - 'META-INF/services/org.glassfish.hk2.extension.*', - 'META-INF/services/org.jvnet.hk2.external.generator.*', - 'META-INF/services/org.glassfish.jersey.internal.spi.*', 'META-INF/services/java.security.Provider', 'mozilla/public-suffix-list.txt', ].each { exclude(it) } - dependencies { - include(dependency('org.apache.httpcomponents:.*')) - include(dependency('org.glassfish.*:.*')) - include(dependency('org.aopalliance.*:.*')) - include(dependency('javax.ws.rs:.*')) - include(dependency('com.fasterxml.*:.*')) - include(dependency('com.github.docker-java:.*')) - include(dependency('com.google.guava:.*')) - include(dependency('io.netty:.*')) - include(dependency('org.bouncycastle:.*')) - include(dependency('org.zeroturnaround:zt-exec')) - include(dependency('commons-lang:commons-lang')) - include(dependency('commons-io:commons-io')) - include(dependency('commons-codec:commons-codec')) - include(dependency('com.squareup.okhttp3:.*')) - include(dependency('com.squareup.okio:.*')) - include(dependency('org.scala-sbt.ipcsocket:ipcsocket')) - include(dependency('org.glassfish.main.external:trilead-ssh2-repackaged')) + project.afterEvaluate { + dependencies { + for (id in project.configurations.compile.resolvedConfiguration.resolvedArtifacts*.moduleVersion*.id) { + exclude(dependency("${id.group}:${id.name}")) + } + } } } @@ -98,25 +82,25 @@ dependencies { shaded ('com.github.docker-java:docker-java:3.1.0-rc-4') { exclude(group: 'org.glassfish.jersey.core') exclude(group: 'org.glassfish.jersey.connectors') + exclude(group: 'org.glassfish.jersey.inject') exclude(group: 'log4j') exclude(group: 'com.google.code.findbug') exclude(group: 'com.kohlschutter.junixsocket') + exclude(group: 'io.netty') + exclude(group: 'org.apache.httpcomponents') + exclude(group: 'org.slf4j') + exclude(group: 'org.apache.commons', module: 'commons-compress') } + shaded 'com.squareup.okhttp3:okhttp:3.12.1' shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' - shaded 'javax.ws.rs:javax.ws.rs-api:2.0.1' - shaded 'org.zeroturnaround:zt-exec:1.10' - shaded 'commons-lang:commons-lang:2.6' - shaded 'commons-io:commons-io:2.6' - shaded 'commons-codec:commons-codec:1.12' - // docker-java uses SslConfigurator from jersey-common for TLS - shaded ('org.glassfish.jersey.core:jersey-common:2.27') { - // SslConfigurator doesn't use classes from dependencies - exclude(module: '*') + shaded 'org.zeroturnaround:zt-exec:1.10', { + exclude(group: 'org.slf4j') } + testCompile 'org.apache.httpcomponents:httpclient:4.5.7' testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.6.0' testCompile 'org.mongodb:mongo-java-driver:3.10.1' diff --git a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java index ee950f4698c..cf807087d55 100644 --- a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java +++ b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java @@ -37,13 +37,7 @@ public void testPackages() throws Exception { public void testMetaInf() throws Exception { assertThatFileList(root.resolve("META-INF")).containsOnly( "MANIFEST.MF", - "services", - "native" - ); - - assertThatFileList(root.resolve("META-INF").resolve("native")).containsOnly( - "liborg-testcontainers-shaded-netty_transport_native_epoll_x86_64.so", - "liborg-testcontainers-shaded-netty_transport_native_kqueue_x86_64.jnilib" + "services" ); } diff --git a/core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java b/core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java new file mode 100644 index 00000000000..2a6f185462e --- /dev/null +++ b/core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java @@ -0,0 +1,27 @@ +package com.github.dockerjava.core.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.List; +import java.util.Map; + +/** + * Monkey patched {@link FiltersEncoder} to avoid a use of jaxrs. + * See https://github.com/docker-java/docker-java/issues/1176 + */ +public class FiltersEncoder { + + private FiltersEncoder() { + } + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + public static String jsonEncode(Map> filters) { + try { + return OBJECT_MAPPER.writeValueAsString(filters); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 186fd194131..a9321276fd6 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -13,7 +13,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.dockerclient.auth.AuthDelegatingDockerClientConfig; -import org.testcontainers.dockerclient.transport.TestcontainersDockerCmdExecFactory; import org.testcontainers.dockerclient.transport.okhttp.OkHttpDockerCmdExecFactory; import org.testcontainers.utility.TestcontainersConfiguration; @@ -173,9 +172,6 @@ protected DockerClient getClientForConfig(DockerClientConfig config) { if ("okhttp".equals(transportType)) { clientBuilder .withDockerCmdExecFactory(new OkHttpDockerCmdExecFactory()); - } else if ("netty".equals(transportType)) { - clientBuilder - .withDockerCmdExecFactory(new TestcontainersDockerCmdExecFactory()); } else { throw new IllegalArgumentException("Unknown transport type: " + transportType); } diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/TestcontainersDockerCmdExecFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/TestcontainersDockerCmdExecFactory.java deleted file mode 100644 index 1ec43e2b251..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/TestcontainersDockerCmdExecFactory.java +++ /dev/null @@ -1,317 +0,0 @@ -package org.testcontainers.dockerclient.transport; - -import com.github.dockerjava.api.command.DockerCmdExecFactory; -import com.github.dockerjava.core.AbstractDockerCmdExecFactory; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.core.SSLConfig; -import com.github.dockerjava.core.WebTarget; -import com.github.dockerjava.netty.NettyWebTarget; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.*; -import io.netty.channel.epoll.EpollDomainSocketChannel; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.kqueue.KQueueDomainSocketChannel; -import io.netty.channel.kqueue.KQueueEventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.DuplexChannel; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.channel.unix.DomainSocketAddress; -import io.netty.channel.unix.UnixChannel; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpContentDecompressor; -import io.netty.handler.ssl.SslHandler; -import io.netty.handler.timeout.IdleState; -import io.netty.handler.timeout.IdleStateEvent; -import io.netty.handler.timeout.IdleStateHandler; -import io.netty.util.concurrent.DefaultThreadFactory; -import org.apache.commons.lang.SystemUtils; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.testcontainers.DockerClientFactory; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLParameters; -import java.io.IOException; -import java.net.SocketTimeoutException; -import java.security.Security; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -/** - * This class is a modified version of docker-java's NettyDockerCmdExecFactory v3.1.0-rc-2 - * Changes: - * - daemonized thread factory - * - thread group - * - the logging handler removed - * - - */ -public class TestcontainersDockerCmdExecFactory extends AbstractDockerCmdExecFactory implements DockerCmdExecFactory { - - private static final String THREAD_PREFIX = "testcontainers-netty"; - - /* - * useful links: - * - * http://stackoverflow.com/questions/33296749/netty-connect-to-unix-domain-socket-failed - * http://netty.io/wiki/native-transports.html - * https://github.com/netty/netty/blob/master/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClient.java - * https://github.com/slandelle/netty-request-chunking/blob/master/src/test/java/slandelle/ChunkingTest.java - */ - - private Bootstrap bootstrap; - - private EventLoopGroup eventLoopGroup; - - private NettyInitializer nettyInitializer; - - private WebTarget baseResource; - - private Integer connectTimeout = null; - - private Integer readTimeout = null; - - @Override - public void init(DockerClientConfig dockerClientConfig) { - super.init(dockerClientConfig); - - bootstrap = new Bootstrap(); - - String scheme = dockerClientConfig.getDockerHost().getScheme(); - String host = ""; - - if ("unix".equals(scheme)) { - nettyInitializer = new UnixDomainSocketInitializer(); - host = "DUMMY"; - } else if ("tcp".equals(scheme)) { - nettyInitializer = new InetSocketInitializer(); - host = dockerClientConfig.getDockerHost().getHost() + ":" - + Integer.toString(dockerClientConfig.getDockerHost().getPort()); - } - - eventLoopGroup = nettyInitializer.init(bootstrap, dockerClientConfig); - - baseResource = new NettyWebTarget(this::connect, host) - .path(dockerClientConfig.getApiVersion().asWebPathPart()); - } - - private DuplexChannel connect() { - checkState(!eventLoopGroup.isShuttingDown(), "EventLoop is shutting down"); - - try { - return connect(bootstrap); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - private DuplexChannel connect(final Bootstrap bootstrap) throws InterruptedException { - return nettyInitializer.connect(bootstrap); - } - - private interface NettyInitializer { - EventLoopGroup init(final Bootstrap bootstrap, DockerClientConfig dockerClientConfig); - - DuplexChannel connect(final Bootstrap bootstrap) throws InterruptedException; - } - - private ThreadFactory createThreadFactory() { - return new DefaultThreadFactory(THREAD_PREFIX, true, Thread.NORM_PRIORITY, DockerClientFactory.TESTCONTAINERS_THREAD_GROUP); - } - - private class UnixDomainSocketInitializer implements NettyInitializer { - @Override - public EventLoopGroup init(Bootstrap bootstrap, DockerClientConfig dockerClientConfig) { - if (SystemUtils.IS_OS_LINUX) { - return epollGroup(); - } else if (SystemUtils.IS_OS_MAC_OSX) { - return kqueueGroup(); - } - throw new RuntimeException("Unsupported OS"); - } - - public EventLoopGroup epollGroup() { - EventLoopGroup epollEventLoopGroup = new EpollEventLoopGroup(0, createThreadFactory()); - - ChannelFactory factory = () -> configure(new EpollDomainSocketChannel()); - - bootstrap.group(epollEventLoopGroup).channelFactory(factory).handler(new ChannelInitializer() { - @Override - protected void initChannel(final UnixChannel channel) throws Exception { - channel.pipeline().addLast(new HttpClientCodec()); - channel.pipeline().addLast(new HttpContentDecompressor()); - } - }); - return epollEventLoopGroup; - } - - public EventLoopGroup kqueueGroup() { - EventLoopGroup nioEventLoopGroup = new KQueueEventLoopGroup(0, createThreadFactory()); - - bootstrap.group(nioEventLoopGroup).channel(KQueueDomainSocketChannel.class) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(final KQueueDomainSocketChannel channel) throws Exception { - channel.pipeline().addLast(new HttpClientCodec()); - channel.pipeline().addLast(new HttpContentDecompressor()); - } - }); - - return nioEventLoopGroup; - } - - @Override - public DuplexChannel connect(Bootstrap bootstrap) throws InterruptedException { - String socketPath = getDockerClientConfig().getDockerHost().getPath(); - return (DuplexChannel) bootstrap.connect(new DomainSocketAddress(socketPath)).sync().channel(); - } - } - - private class InetSocketInitializer implements NettyInitializer { - @Override - public EventLoopGroup init(Bootstrap bootstrap, final DockerClientConfig dockerClientConfig) { - EventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(0, createThreadFactory()); - - // TODO do we really need BouncyCastle? - Security.addProvider(new BouncyCastleProvider()); - - ChannelFactory factory = () -> configure(new NioSocketChannel()); - - bootstrap.group(nioEventLoopGroup).channelFactory(factory) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(final SocketChannel channel) throws Exception { - channel.pipeline().addLast(new HttpClientCodec()); - channel.pipeline().addLast(new HttpContentDecompressor()); - } - }); - - return nioEventLoopGroup; - } - - @Override - public DuplexChannel connect(Bootstrap bootstrap) throws InterruptedException { - DockerClientConfig dockerClientConfig = getDockerClientConfig(); - String host = dockerClientConfig.getDockerHost().getHost(); - int port = dockerClientConfig.getDockerHost().getPort(); - - if (port == -1) { - throw new RuntimeException("no port configured for " + host); - } - - DuplexChannel channel = (DuplexChannel) bootstrap.connect(host, port).sync().channel(); - - final SslHandler ssl = initSsl(dockerClientConfig); - - if (ssl != null) { - channel.pipeline().addFirst(ssl); - } - - return channel; - } - - private SslHandler initSsl(DockerClientConfig dockerClientConfig) { - SslHandler ssl = null; - - try { - String host = dockerClientConfig.getDockerHost().getHost(); - int port = dockerClientConfig.getDockerHost().getPort(); - - final SSLConfig sslConfig = dockerClientConfig.getSSLConfig(); - - if (sslConfig != null && sslConfig.getSSLContext() != null) { - - SSLEngine engine = sslConfig.getSSLContext().createSSLEngine(host, port); - engine.setUseClientMode(true); - engine.setSSLParameters(enableHostNameVerification(engine.getSSLParameters())); - - // in the future we may use HostnameVerifier like here: - // https://github.com/AsyncHttpClient/async-http-client/blob/1.8.x/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java#L76 - - ssl = new SslHandler(engine); - } - - } catch (Exception e) { - throw new RuntimeException(e); - } - - return ssl; - } - } - - public SSLParameters enableHostNameVerification(SSLParameters sslParameters) { - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - return sslParameters; - } - - @Override - public void close() throws IOException { - checkNotNull(eventLoopGroup, "Factory not initialized. You probably forgot to call init()!"); - - eventLoopGroup.shutdownGracefully(); - } - - /** - * Configure connection timeout in milliseconds - */ - public TestcontainersDockerCmdExecFactory withConnectTimeout(Integer connectTimeout) { - this.connectTimeout = connectTimeout; - return this; - } - - /** - * Configure read timeout in milliseconds - */ - public TestcontainersDockerCmdExecFactory withReadTimeout(Integer readTimeout) { - this.readTimeout = readTimeout; - return this; - } - - private T configure(T channel) { - ChannelConfig channelConfig = channel.config(); - - if (connectTimeout != null) { - channelConfig.setConnectTimeoutMillis(connectTimeout); - } - if (readTimeout != null) { - channel.pipeline().addLast("readTimeoutHandler", new ReadTimeoutHandler()); - } - - return channel; - } - - private final class ReadTimeoutHandler extends IdleStateHandler { - private boolean alreadyTimedOut; - - ReadTimeoutHandler() { - super(readTimeout, 0, 0, TimeUnit.MILLISECONDS); - } - - /** - * Called when a read timeout was detected. - */ - @Override - protected synchronized void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception { - assert evt.state() == IdleState.READER_IDLE; - final Channel channel = ctx.channel(); - if (channel == null || !channel.isActive() || alreadyTimedOut) { - return; - } - DockerClientConfig dockerClientConfig = getDockerClientConfig(); - final Object dockerAPIEndpoint = dockerClientConfig.getDockerHost(); - final String msg = "Read timed out: No data received within " + readTimeout - + "ms. Perhaps the docker API (" + dockerAPIEndpoint - + ") is not responding normally, or perhaps you need to increase the readTimeout value."; - final Exception ex = new SocketTimeoutException(msg); - ctx.fireExceptionCaught(ex); - alreadyTimedOut = true; - } - } - - protected WebTarget getBaseResource() { - checkNotNull(baseResource, "Factory not initialized, baseResource not set. You probably forgot to call init()!"); - return baseResource; - } -} diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 717ba2635a8..46550dc0af7 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -14,8 +14,6 @@ import com.google.common.annotations.VisibleForTesting; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; @@ -25,7 +23,9 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; import java.net.Socket; +import java.net.URLEncoder; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; @@ -365,12 +365,15 @@ static class FilterRegistry { * @throws IOException if communication with Ryuk fails */ protected boolean register(List> filters) throws IOException { - String query = URLEncodedUtils.format( - filters.stream() - .map(it -> new BasicNameValuePair(it.getKey(), it.getValue())) - .collect(Collectors.toList()), - (String) null - ); + String query = filters.stream() + .map(it -> { + try { + return URLEncoder.encode(it.getKey(), "UTF-8") + "=" + URLEncoder.encode(it.getValue(), "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.joining("&")); log.debug("Sending '{}' to Ryuk", query); out.write(query.getBytes()); diff --git a/core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java b/core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java new file mode 100644 index 00000000000..353133ae148 --- /dev/null +++ b/core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java @@ -0,0 +1,28 @@ +package com.github.dockerjava.core.util; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Image; +import org.junit.Test; +import org.rnorth.visibleassertions.VisibleAssertions; +import org.testcontainers.DockerClientFactory; + +import java.util.List; +import java.util.UUID; + +/** + * This test checks that our custom monkey-patched version works + * and does not throw {@link ClassNotFoundException}. + */ +public class FiltersEncoderTest { + + @Test + public void filtersShouldWork() throws Exception { + DockerClient client = DockerClientFactory.instance().client(); + + List images = client.listImagesCmd() + .withLabelFilter("com.example=" + UUID.randomUUID().toString()) + .exec(); + + VisibleAssertions.assertTrue("List is empty", images.isEmpty()); + } +} diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 9ab71fe7c43..ba9a2db096e 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,6 +8,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'redis.clients:jedis:3.0.1' + testCompile 'org.apache.httpcomponents:httpclient:4.5.7' testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.15' diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index d891e179a94..1280fb4a818 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -11,7 +11,8 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' + testCompile 'org.apache.httpcomponents:httpclient:4.5.7' testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.15' -} \ No newline at end of file +} From 541dbf4dbb885af866bcb729d8a599c095b114cb Mon Sep 17 00:00:00 2001 From: Alexander Sparkowsky Date: Tue, 19 Mar 2019 14:07:59 +0100 Subject: [PATCH 0020/4969] Update BrowserWebDriverContainer to honor existing no_proxy setting (#929) Fixes #928 --- .../containers/BrowserWebDriverContainer.java | 8 +++- .../junit/BrowserWebDriverContainerTest.java | 42 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 94374235cbb..b92a4877cd2 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -48,6 +48,8 @@ public class BrowserWebDriverContainer Date: Tue, 19 Mar 2019 22:08:07 +0100 Subject: [PATCH 0021/4969] Cassandra: Add support for creating Cluster objects without JMX reporting (#1199) --- .../containers/CassandraContainer.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index dbb3316158f..a78d23e4b4b 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -32,6 +32,7 @@ public class CassandraContainer> extends G private String configLocation; private String initScriptPath; + private boolean enableJmxReporting; public CassandraContainer() { this(IMAGE + ":3.11.2"); @@ -41,6 +42,7 @@ public CassandraContainer(String dockerImageName) { super(dockerImageName); addExposedPort(CQL_PORT); setStartupAttempts(3); + this.enableJmxReporting = false; } @Override @@ -116,6 +118,14 @@ public SELF withInitScript(String initScriptPath) { return self(); } + /** + * Initialize Cassandra client with JMX reporting enabled or disabled + */ + public SELF withJmxReporting(boolean enableJmxReporting) { + this.enableJmxReporting = enableJmxReporting; + return self(); + } + /** * Get username * @@ -146,14 +156,21 @@ public String getPassword() { * Can be used to obtain connections to Cassandra in the container */ public Cluster getCluster() { - return getCluster(this); + return getCluster(this, enableJmxReporting); } - public static Cluster getCluster(ContainerState containerState) { - return Cluster.builder() + public static Cluster getCluster(ContainerState containerState, boolean enableJmxReporting) { + final Cluster.Builder builder = Cluster.builder() .addContactPoint(containerState.getContainerIpAddress()) - .withPort(containerState.getMappedPort(CQL_PORT)) - .build(); + .withPort(containerState.getMappedPort(CQL_PORT)); + if (!enableJmxReporting) { + builder.withoutJMXReporting(); + } + return builder.build(); + } + + public static Cluster getCluster(ContainerState containerState) { + return getCluster(containerState, false); } private DatabaseDelegate getDatabaseDelegate() { From f3ae35ef8379bdc248e71768956b73048216e456 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 20 Mar 2019 22:00:47 +0000 Subject: [PATCH 0022/4969] Allow TC_INITSCRIPT to support absolute/relative path via file: URI (#1329) * TC_INITSCRIPT support absolute/relative path * TC_INITSCRIPT remove absolute path,relative project path use file: prefix * into a constant and use FILE_PATH_PREFIX * Simplify implementation by using URL directly * Update docs * Update modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java Co-Authored-By: rnorth --- docs/modules/databases/index.md | 8 +++++++- modules/jdbc-test/sql/init_mysql.sql | 5 +++++ .../java/org/testcontainers/jdbc/JDBCDriverTest.java | 1 + .../testcontainers/jdbc/ContainerDatabaseDriver.java | 11 +++++++++-- 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 modules/jdbc-test/sql/init_mysql.sql diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index 4fd498b7248..aaef47a44ef 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -64,7 +64,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database `jdbc:tc:postgis:9.6://hostname/databasename` -## Using an init script +## Using a classpath init script Testcontainers can run an initscript after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: @@ -72,6 +72,12 @@ Testcontainers can run an initscript after the database container is started, bu This is useful if you have a fixed script for setting up database schema, etc. +## Using an init script from a file + +If the init script path is prefixed `file:`, it will be loaded from a file (relative to the working directory, which will usually be the project root). + +`jdbc:tc:mysql:5.7.22://hostname/databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql` + #### Using an init function Instead of running a fixed script for DB setup, it may be useful to call a Java function that you define. This is intended to allow you to trigger database schema migration tools. To do this, add TC_INITFUNCTION to the URL as follows, passing a full path to the class name and method: diff --git a/modules/jdbc-test/sql/init_mysql.sql b/modules/jdbc-test/sql/init_mysql.sql new file mode 100644 index 00000000000..2b00ee968b0 --- /dev/null +++ b/modules/jdbc-test/sql/init_mysql.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + foo VARCHAR(255) +); + +INSERT INTO bar (foo) VALUES ('hello world'); \ No newline at end of file diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index a94f0b0897b..4eb55b38e24 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -46,6 +46,7 @@ public static Iterable data() { {"jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, {"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, {"jdbc:tc:mysql:5.5.43://hostname/databasename", EnumSet.noneOf(Options.class)}, diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java index 163c67f486d..0f470e36979 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java @@ -41,6 +41,7 @@ public class ContainerDatabaseDriver implements Driver { private static final Map> containerConnections = new HashMap<>(); private static final Map jdbcUrlContainerCache = new HashMap<>(); private static final Set initializedContainers = new HashSet<>(); + private static final String FILE_PATH_PREFIX = "file:"; static { load(); @@ -177,8 +178,14 @@ private void runInitScriptIfRequired(final ConnectionUrl connectionUrl, Database if (connectionUrl.getInitScriptPath().isPresent()) { String initScriptPath = connectionUrl.getInitScriptPath().get(); try { - URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath); - + URL resource; + if (initScriptPath.startsWith(FILE_PATH_PREFIX)) { + //relative workdir path + resource = new URL(initScriptPath); + } else { + //classpath resource + resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath); + } if (resource == null) { LOGGER.warn("Could not load classpath init script: {}", initScriptPath); throw new SQLException("Could not load classpath init script: " + initScriptPath + ". Resource not found."); From 2fc7c21772b57ee9afcf92a028a20c35baca2062 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 20 Mar 2019 22:14:13 +0000 Subject: [PATCH 0023/4969] Update latest version number --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 0aad56f0314..aee5d80e340 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -76,4 +76,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.10.6 + latest_version: 1.10.7 From 31b361084257e8c751bbeef3bded0ffe41fe7e00 Mon Sep 17 00:00:00 2001 From: Frederic Tardif Date: Thu, 21 Mar 2019 13:32:20 -0400 Subject: [PATCH 0024/4969] start ambassador only if mapping configured (#1328) --- .../org/testcontainers/containers/DockerComposeContainer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index d2958129e90..ae10c3096fa 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -239,7 +239,9 @@ private List listChildContainers() { } private void startAmbassadorContainers() { - ambassadorContainer.start(); + if (!ambassadorPortMappings.isEmpty()) { + ambassadorContainer.start(); + } } private Logger logger() { From 41987efdc1c465c79b075e77ff79501c709ad5a7 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 22 Mar 2019 20:25:30 +0000 Subject: [PATCH 0025/4969] Add Toxiproxy module (#1330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on https://gist.github.com/rnorth/4c3666d62fa93bf0daa813b282e4ebff, in turn based on [hotels.com’s blog post](https://medium.com/hotels-com-technology/i-dont-know-about-resilience-testing-and-so-can-you-b3c59d80012d) where they show use of Testcontainers with Toxiproxy. Having seen Toxiproxy and experimented with it, I'm inclined to go with this and suggest that we not move forward with #283 (which is a great PR, but we've unfortunately failed to land after quite a long time). While Pumba may be nice and transparent, there are a lot of moving parts and complexity under the covers, vs Toxiproxy, which is a bit less magical but easier to understand. --- .travis.yml | 4 - docs/modules/toxiproxy.md | 76 ++++++++++ mkdocs.yml | 1 + modules/toxiproxy/build.gradle | 9 ++ .../containers/ToxiproxyContainer.java | 130 ++++++++++++++++++ .../containers/ToxiproxyTest.java | 102 ++++++++++++++ 6 files changed, 318 insertions(+), 4 deletions(-) create mode 100644 docs/modules/toxiproxy.md create mode 100644 modules/toxiproxy/build.gradle create mode 100644 modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java create mode 100644 modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java diff --git a/.travis.yml b/.travis.yml index 924b31b4f8d..571c078730d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,6 @@ language: java jdk: - oraclejdk8 -branches: - only: - - master - sudo: required services: - docker diff --git a/docs/modules/toxiproxy.md b/docs/modules/toxiproxy.md new file mode 100644 index 00000000000..5df65e232ff --- /dev/null +++ b/docs/modules/toxiproxy.md @@ -0,0 +1,76 @@ +# Toxiproxy Module + +Testcontainers module for Shopify's [Toxiproxy](https://github.com/Shopify/toxiproxy). +This TCP proxy can be used to simulate network failure conditions in between tests and containers. + +[toxiproxy-java](https://github.com/trekawek/toxiproxy-java) is used as a client. + +## Usage example + +A Toxiproxy container can be placed in between test code and a container, or in between containers. +In either scenario, it is necessary to create a `ToxiproxyContainer` instance on the same Docker network, as follows: + + +[Creating a Toxiproxy container](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:creatingProxy + + +Next, it is necessary to instruct Toxiproxy to start proxying connections. +Each `ToxiproxyContainer` can proxy to many target containers if necessary. + +We do this as follows: + + +[Starting proxying connections to a target container](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:obtainProxyObject + + +Then, to establish a connection via Toxiproxy, we obtain **Toxiproxy's** proxy host IP and port: + + +[Obtaining proxied host and port](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:obtainProxiedHostAndPort + + +Code under test, or other containers, should connect to this proxied host IP and port. + +Having done this, it is possible to trigger failure conditions ('Toxics') through the `proxy.toxics()` object: + +* `bandwidth` - Limit a connection to a maximum number of kilobytes per second. +* `latency` - Add a delay to all data going through the proxy. The delay is equal to `latency +/- jitter`. +* `slicer` - Slices TCP data up into small bits, optionally adding a delay between each sliced "packet". +* `slowClose` - Delay the TCP socket from closing until `delay` milliseconds has elapsed. +* `timeout` - Stops all data from getting through, and closes the connection after `timeout`. If `timeout` is `0`, the connection won't close, and data will be delayed until the toxic is removed. +* `limitData` - Closes connection when transmitted data exceeded limit. + +Please see the [Toxiproxy documentation](https://github.com/Shopify/toxiproxy#toxics) for full details on the available Toxics. + +As one example, we can introduce latency and random jitter to proxied connections as follows: + + +[Adding latency to a connection](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:addingLatency + + +Additionally we can disable the proxy to simulate a complete interruption to the network connection: + + +[Cutting a connection](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:disableProxy + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:toxiproxy:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + toxiproxy + {{latest_version}} + test + +``` + +## Acknowledgements + +This module was inspired by a [hotels.com blog post](https://medium.com/hotels-com-technology/i-dont-know-about-resilience-testing-and-so-can-you-b3c59d80012d). diff --git a/mkdocs.yml b/mkdocs.yml index aee5d80e340..1b7d3f1852e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,6 +56,7 @@ nav: - modules/pulsar.md - modules/localstack.md - modules/mockserver.md + - modules/toxiproxy.md - modules/nginx.md - modules/vault.md - Test framework integration: diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle new file mode 100644 index 00000000000..0d004fd32bf --- /dev/null +++ b/modules/toxiproxy/build.gradle @@ -0,0 +1,9 @@ +description = "Testcontainers :: Toxiproxy" + +dependencies { + compile project(':testcontainers') + compile 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.3' + + testCompile 'redis.clients:jedis:3.0.1' + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' +} diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java new file mode 100644 index 00000000000..cce6a0dca22 --- /dev/null +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -0,0 +1,130 @@ +package org.testcontainers.containers; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import eu.rekawek.toxiproxy.Proxy; +import eu.rekawek.toxiproxy.ToxiproxyClient; +import eu.rekawek.toxiproxy.model.ToxicDirection; +import eu.rekawek.toxiproxy.model.ToxicList; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Container for resiliency testing using Toxiproxy. + */ +public class ToxiproxyContainer extends GenericContainer { + + private static final String IMAGE_NAME = "shopify/toxiproxy:2.1.0"; + private static final int TOXIPROXY_CONTROL_PORT = 8474; + private static final int FIRST_PROXIED_PORT = 8666; + private static final int LAST_PROXIED_PORT = 8666 + 31; + + private ToxiproxyClient client; + private final Map proxies = new HashMap<>(); + private final AtomicInteger nextPort = new AtomicInteger(FIRST_PROXIED_PORT); + + public ToxiproxyContainer() { + this(IMAGE_NAME); + } + + public ToxiproxyContainer(String imageName) { + super(imageName); + addExposedPorts(TOXIPROXY_CONTROL_PORT); + setWaitStrategy(new HttpWaitStrategy().forPath("/version").forPort(TOXIPROXY_CONTROL_PORT)); + + // allow up to 32 ports to be proxied (arbitrary value). Here we make the ports exposed; whether or not + // Toxiproxy will listen is controlled at runtime using getProxy(...) + for (int i = FIRST_PROXIED_PORT; i <= LAST_PROXIED_PORT; i++) { + addExposedPort(i); + } + } + + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + client = new ToxiproxyClient(getContainerIpAddress(), getMappedPort(TOXIPROXY_CONTROL_PORT)); + } + + /** + * Obtain a {@link ContainerProxy} instance for target container that is managed by Testcontainers. The target + * container should be routable from this from this {@link ToxiproxyContainer} instance (e.g. on the same + * Docker {@link Network}). + * + * @param container target container + * @param port port number on the target service that should be proxied + * @return a {@link ContainerProxy} instance + */ + public ContainerProxy getProxy(GenericContainer container, int port) { + return this.getProxy(container.getNetworkAliases().get(0), port); + } + + /** + * Obtain a {@link ContainerProxy} instance for a specific hostname and port, which can be for any host + * that is routable from this {@link ToxiproxyContainer} instance (e.g. on the same + * Docker {@link Network} or on routable from the Docker host). + * + *

It is expected that {@link ToxiproxyContainer#getProxy(GenericContainer, int)} will be more + * useful in most scenarios, but this method is present to allow use of Toxiproxy in front of containers + * or external servers that are not managed by Testcontainers.

+ * + * @param hostname hostname of target server to be proxied + * @param port port number on the target server that should be proxied + * @return a {@link ContainerProxy} instance + */ + public ContainerProxy getProxy(String hostname, int port) { + String upstream = hostname + ":" + port; + + return proxies.computeIfAbsent(upstream, __ -> { + try { + final int toxiPort = nextPort.getAndIncrement(); + if (toxiPort > LAST_PROXIED_PORT) { + throw new IllegalStateException("Maximum number of proxies exceeded"); + } + + final Proxy proxy = client.createProxy("name", "0.0.0.0:" + toxiPort, upstream); + return new ContainerProxy(proxy, getContainerIpAddress(), getMappedPort(toxiPort)); + } catch (IOException e) { + throw new RuntimeException("Proxy could not be created", e); + } + }); + } + + @RequiredArgsConstructor(access = AccessLevel.PROTECTED) + public static class ContainerProxy { + private static final String CUT_CONNECTION_DOWNSTREAM = "CUT_CONNECTION_DOWNSTREAM"; + private static final String CUT_CONNECTION_UPSTREAM = "CUT_CONNECTION_UPSTREAM"; + private final Proxy toxi; + @Getter private final String containerIpAddress; + @Getter private final int proxyPort; + private boolean isCurrentlyCut; + + public ToxicList toxics() { + return toxi.toxics(); + } + + /** + * Cuts the connection by setting bandwidth in both directions to zero. + * @param shouldCutConnection true if the connection should be cut, or false if it should be re-enabled + */ + public void setConnectionCut(boolean shouldCutConnection) { + try { + if (shouldCutConnection) { + toxics().bandwidth(CUT_CONNECTION_DOWNSTREAM, ToxicDirection.DOWNSTREAM, 0); + toxics().bandwidth(CUT_CONNECTION_UPSTREAM, ToxicDirection.UPSTREAM, 0); + isCurrentlyCut = true; + } else if (isCurrentlyCut) { + toxics().get(CUT_CONNECTION_DOWNSTREAM).remove(); + toxics().get(CUT_CONNECTION_UPSTREAM).remove(); + isCurrentlyCut = false; + } + } catch (IOException e) { + throw new RuntimeException("Could not control proxy", e); + } + } + } +} diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java new file mode 100644 index 00000000000..fbcfa124f80 --- /dev/null +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -0,0 +1,102 @@ +package org.testcontainers.containers; + +import eu.rekawek.toxiproxy.model.ToxicDirection; +import org.junit.Rule; +import org.junit.Test; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.exceptions.JedisConnectionException; + +import java.io.IOException; + +import static java.lang.String.format; +import static org.rnorth.visibleassertions.VisibleAssertions.*; + +public class ToxiproxyTest { + + // creatingProxy { + // Create a common docker network so that containers can communicate + @Rule + public Network network = Network.newNetwork(); + + // the target container - this could be anything + @Rule + public GenericContainer redis = new GenericContainer("redis:5.0.4") + .withExposedPorts(6379) + .withNetwork(network); + + // Toxiproxy container, which will be used as a TCP proxy + @Rule + public ToxiproxyContainer toxiproxy = new ToxiproxyContainer() + .withNetwork(network); + // } + + @Test + public void testDirect() { + final Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getFirstMappedPort()); + jedis.set("somekey", "somevalue"); + + final String s = jedis.get("somekey"); + assertEquals("direct access to the container works OK", "somevalue", s); + } + + @Test + public void testLatencyViaProxy() throws IOException { + // obtainProxyObject { + final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); + // } + + // obtainProxiedHostAndPort { + final String ipAddressViaToxiproxy = proxy.getContainerIpAddress(); + final int portViaToxiproxy = proxy.getProxyPort(); + // } + + final Jedis jedis = new Jedis(ipAddressViaToxiproxy, portViaToxiproxy); + jedis.set("somekey", "somevalue"); + + checkCallWithLatency(jedis, "without interference", 0, 250); + + // addingLatency { + proxy.toxics() + .latency("latency", ToxicDirection.DOWNSTREAM, 1_100) + .setJitter(100); + // from now on the connection latency should be from 1000-1200 ms. + // } + + checkCallWithLatency(jedis, "with interference", 1_000, 1_500); + } + + @Test + public void testConnectionCut() { + final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); + final Jedis jedis = new Jedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); + jedis.set("somekey", "somevalue"); + + assertEquals("access to the container works OK before cutting the connection", "somevalue", jedis.get("somekey")); + + // disableProxy { + proxy.setConnectionCut(true); + + // for example, expect failure when the connection is cut + assertThrows("calls fail when the connection is cut", + JedisConnectionException.class, () -> { + jedis.get("somekey"); + }); + + proxy.setConnectionCut(false); + + // and with the connection re-established, expect success + assertEquals("access to the container works OK after re-establishing the connection", "somevalue", jedis.get("somekey")); + // } + } + + private void checkCallWithLatency(Jedis jedis, final String description, int expectedMinLatency, long expectedMaxLatency) { + final long start = System.currentTimeMillis(); + String s = jedis.get("somekey"); + final long end = System.currentTimeMillis(); + final long duration = end - start; + + assertEquals(format("access to the container %s works OK", description), "somevalue", s); + assertTrue(format("%s there is at least %dms latency", description, expectedMinLatency), duration >= expectedMinLatency); + assertTrue(format("%s there is no more than %dms latency", description, expectedMaxLatency), duration < expectedMaxLatency); + } +} From cb27c41d535f2550bb94cba98b83495fee67f948 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 23 Mar 2019 08:44:31 +0000 Subject: [PATCH 0026/4969] Update latest version number --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 1b7d3f1852e..31938bb99f7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,4 +77,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.10.7 + latest_version: 1.11.0 From bb5c6fc2fe926228b1dae33f7e2457f9b5c9a753 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 23 Mar 2019 09:12:19 +0000 Subject: [PATCH 0027/4969] Add extra background to toxiproxy module docs --- docs/modules/toxiproxy.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/modules/toxiproxy.md b/docs/modules/toxiproxy.md index 5df65e232ff..9e09d8b387b 100644 --- a/docs/modules/toxiproxy.md +++ b/docs/modules/toxiproxy.md @@ -1,10 +1,16 @@ # Toxiproxy Module Testcontainers module for Shopify's [Toxiproxy](https://github.com/Shopify/toxiproxy). -This TCP proxy can be used to simulate network failure conditions in between tests and containers. - -[toxiproxy-java](https://github.com/trekawek/toxiproxy-java) is used as a client. +This TCP proxy can be used to simulate network failure conditions. + +You can simulate network failures: + +* between Java code and containers, ideal for testing resilience features of client code +* between containers, for testing resilience and emergent behaviour of multi-container systems +* if desired, between Java code/containers and external resources (non-Dockerized!), for scenarios where not all dependencies can be/have been dockerized +Testcontainers Toxiproxy support allows resilience features to be easily verified as part of isolated dev/CI testing. This allows earlier testing of resilience features, and broader sets of failure conditions to be covered. + ## Usage example A Toxiproxy container can be placed in between test code and a container, or in between containers. @@ -74,3 +80,6 @@ testCompile "org.testcontainers:toxiproxy:{{latest_version}}" ## Acknowledgements This module was inspired by a [hotels.com blog post](https://medium.com/hotels-com-technology/i-dont-know-about-resilience-testing-and-so-can-you-b3c59d80012d). + +[toxiproxy-java](https://github.com/trekawek/toxiproxy-java) is used to help control failure conditions. + From f2fc02c49afc4c183bd22a09f340c0a23fb3cf03 Mon Sep 17 00:00:00 2001 From: worldtiki Date: Sun, 24 Mar 2019 08:19:53 +0000 Subject: [PATCH 0028/4969] Toxiproxy: Fix multi-proxy use case (remove static "name" argument) (#1335) * Use hostname instead of hardcoded string to allow for multiple proxies to be created * Update modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java Co-Authored-By: worldtiki * Add a test covering creation of multiple proxies --- .../containers/ToxiproxyContainer.java | 2 +- .../containers/ToxiproxyTest.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index cce6a0dca22..df4bf6e688d 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -86,7 +86,7 @@ public ContainerProxy getProxy(String hostname, int port) { throw new IllegalStateException("Maximum number of proxies exceeded"); } - final Proxy proxy = client.createProxy("name", "0.0.0.0:" + toxiPort, upstream); + final Proxy proxy = client.createProxy(upstream, "0.0.0.0:" + toxiPort, upstream); return new ContainerProxy(proxy, getContainerIpAddress(), getMappedPort(toxiPort)); } catch (IOException e) { throw new RuntimeException("Proxy could not be created", e); diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index fbcfa124f80..34861f68f7a 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -89,6 +89,34 @@ public void testConnectionCut() { // } } + @Test + public void testMultipleProxiesCanBeCreated() { + try (GenericContainer secondRedis = new GenericContainer("redis:5.0.4") + .withExposedPorts(6379) + .withNetwork(network)) { + + secondRedis.start(); + + final ToxiproxyContainer.ContainerProxy firstProxy = toxiproxy.getProxy(redis, 6379); + final ToxiproxyContainer.ContainerProxy secondProxy = toxiproxy.getProxy(secondRedis, 6379); + + final Jedis firstJedis = new Jedis(firstProxy.getContainerIpAddress(), firstProxy.getProxyPort()); + final Jedis secondJedis = new Jedis(secondProxy.getContainerIpAddress(), secondProxy.getProxyPort()); + + firstJedis.set("somekey", "somevalue"); + secondJedis.set("somekey", "somevalue"); + + firstProxy.setConnectionCut(true); + + assertThrows("calls fail when the connection is cut, for only the relevant proxy", + JedisConnectionException.class, () -> { + firstJedis.get("somekey"); + }); + + assertEquals("access via a different proxy is OK", "somevalue", secondJedis.get("somekey")); + } + } + private void checkCallWithLatency(Jedis jedis, final String description, int expectedMinLatency, long expectedMaxLatency) { final long start = System.currentTimeMillis(); String s = jedis.get("somekey"); From 672523057bd2f2a7ad716e9648dde7a526dd64ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sun, 24 Mar 2019 09:21:28 +0100 Subject: [PATCH 0029/4969] Bump spock-core from 1.0-groovy-2.4 to 1.3-groovy-2.5 in /modules/spock (#1291) Bumps spock-core from 1.0-groovy-2.4 to 1.3-groovy-2.5. Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 1280fb4a818..2e8b175e303 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -6,7 +6,7 @@ description = "Testcontainers :: Spock-Extension" dependencies { compile project(':testcontainers') - compile 'org.spockframework:spock-core:1.0-groovy-2.4' + compile 'org.spockframework:spock-core:1.3-groovy-2.5' testCompile project(':mysql') testCompile project(':postgresql') From 2c5f274d73317257efa99d359357856c076c24b7 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 24 Mar 2019 21:16:19 +0000 Subject: [PATCH 0030/4969] Add getLogs() to GenericContainer, allowing all logs to be retrieved (#1206) Fixes #1205 --- .travis.yml | 2 +- .../containers/ContainerState.java | 18 +++++ .../containers/GenericContainer.java | 29 +++---- .../containers/output/WaitingConsumer.java | 9 ++- .../org/testcontainers/utility/LogUtils.java | 81 ++++++++++++++++--- .../containers/output/ContainerLogsTest.java | 72 +++++++++++++++++ .../junit/WorkingDirectoryTest.java | 14 +--- .../utility/DirectoryTarResourceTest.java | 43 +++------- docs/features/container_logs.md | 34 ++++++-- 9 files changed, 216 insertions(+), 86 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java diff --git a/.travis.yml b/.travis.yml index 571c078730d..575aa50b208 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ jobs: - stage: test env: [ NAME=core ] - jdk: openjdk-ea + jdk: openjdk12 script: ./gradlew testcontainers:check --scan --no-daemon - env: [ NAME=selenium ] diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 26eec8c4ebe..2066fe72157 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -7,6 +7,8 @@ import com.github.dockerjava.api.model.Ports; import com.google.common.base.Preconditions; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.utility.LogUtils; import java.util.ArrayList; import java.util.List; @@ -149,6 +151,22 @@ default List getBoundPortNumbers() { .collect(Collectors.toList()); } + + /** + * @return all log output from the container from start until the current instant (both stdout and stderr) + */ + default String getLogs() { + return LogUtils.getOutput(DockerClientFactory.instance().client(), getContainerId()); + } + + /** + * @param types log types to return + * @return all log output from the container from start until the current instant + */ + default String getLogs(OutputFrame.OutputType... types) { + return LogUtils.getOutput(DockerClientFactory.instance().client(), getContainerId(), types); + } + /** * @return the id of the container */ diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index b00061b3d97..936d880d1a8 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -20,9 +20,7 @@ import org.rnorth.visibleassertions.VisibleAssertions; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.output.FrameConsumerResultCallback; import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.containers.startupcheck.IsRunningStartupCheckStrategy; import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; @@ -50,8 +48,6 @@ import java.util.stream.Stream; import static com.google.common.collect.Lists.newArrayList; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; import static org.testcontainers.utility.CommandLine.runShellCommand; /** @@ -242,24 +238,24 @@ private void tryStart() { logger().info("Starting container with ID: {}", containerId); dockerClient.startContainerCmd(containerId).exec(); + logger().info("Container {} is starting: {}", dockerImageName, containerId); + // For all registered output consumers, start following as close to container startup as possible this.logConsumers.forEach(this::followOutput); - logger().info("Container {} is starting: {}", dockerImageName, containerId); - // Tell subclasses that we're starting containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); containerName = containerInfo.getName(); containerIsStarting(containerInfo); - // Wait until the container is running (may not be fully started) - + // Wait until the container has reached the desired running state if (!this.startupCheckStrategy.waitUntilStartupSuccessful(dockerClient, containerId)) { // Bail out, don't wait for the port to start listening. // (Exception thrown here will be caught below and wrapped) throw new IllegalStateException("Container did not start correctly."); } + // Wait until the process within the container has become ready for use (e.g. listening on network, log message emitted, etc). waitUntilContainerStarted(); logger().info("Container {} started", dockerImageName); @@ -269,17 +265,12 @@ private void tryStart() { if (containerId != null) { // Log output if startup failed, either due to a container failure or exception (including timeout) - logger().error("Container log output (if any) will follow:"); - FrameConsumerResultCallback resultCallback = new FrameConsumerResultCallback(); - resultCallback.addConsumer(STDOUT, new Slf4jLogConsumer(logger())); - resultCallback.addConsumer(STDERR, new Slf4jLogConsumer(logger())); - dockerClient.logContainerCmd(containerId).withStdOut(true).withStdErr(true).exec(resultCallback); - - // Try to ensure that container log output is shown before proceeding - try { - resultCallback.getCompletionLatch().await(1, TimeUnit.MINUTES); - } catch (InterruptedException ignored) { - // Cannot do anything at this point + final String containerLogs = getLogs(); + + if (containerLogs.length() > 0) { + logger().error("Log output from the failed container:\n{}", getLogs()); + } else { + logger().error("There are no stdout/stderr logs available for the failed container"); } } diff --git a/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java b/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java index 367581528c2..858f5a4b487 100644 --- a/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java @@ -113,8 +113,13 @@ private void waitUntil(Predicate predicate, long expiry, int times) /** * Wait until Docker closes the stream of output. */ - public void waitUntilEnd() throws TimeoutException { - waitUntilEnd(Long.MAX_VALUE); + public void waitUntilEnd() { + try { + waitUntilEnd(Long.MAX_VALUE); + } catch (TimeoutException e) { + // timeout condition can never occur in a realistic timeframe + throw new IllegalStateException(e); + } } /** diff --git a/core/src/main/java/org/testcontainers/utility/LogUtils.java b/core/src/main/java/org/testcontainers/utility/LogUtils.java index 100a79a8395..b51325cdda7 100644 --- a/core/src/main/java/org/testcontainers/utility/LogUtils.java +++ b/core/src/main/java/org/testcontainers/utility/LogUtils.java @@ -2,15 +2,14 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.LogContainerCmd; -import com.github.dockerjava.api.model.AuthConfig; -import com.google.common.base.MoreObjects; import lombok.experimental.UtilityClass; import org.testcontainers.containers.output.FrameConsumerResultCallback; import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.ToStringConsumer; +import org.testcontainers.containers.output.WaitingConsumer; import java.util.function.Consumer; -import static com.google.common.base.Strings.isNullOrEmpty; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; @@ -19,15 +18,76 @@ */ @UtilityClass public class LogUtils { + + /** + * Attach a log consumer to a container's log outputs in follow mode. The consumer will receive all previous + * and all future log frames of the specified type(s). + * + * @param dockerClient a Docker client + * @param containerId container ID to attach to + * @param consumer a consumer of {@link OutputFrame}s + * @param types types of {@link OutputFrame} to receive + */ + public void followOutput(DockerClient dockerClient, + String containerId, + Consumer consumer, + OutputFrame.OutputType... types) { + + attachConsumer(dockerClient, containerId, consumer, true, types); + } + + /** + * Attach a log consumer to a container's log outputs in follow mode. The consumer will receive all previous + * and all future log frames (both stdout and stderr). + * + * @param dockerClient a Docker client + * @param containerId container ID to attach to + * @param consumer a consumer of {@link OutputFrame}s + */ + public void followOutput(DockerClient dockerClient, + String containerId, + Consumer consumer) { + + followOutput(dockerClient, containerId, consumer, STDOUT, STDERR); + } + /** - * {@inheritDoc} + * Retrieve all previous log outputs for a container of the specified type(s). + * + * @param dockerClient a Docker client + * @param containerId container ID to attach to + * @param types types of {@link OutputFrame} to receive + * @return all previous output frames (stdout/stderr being separated by newline characters) */ - public void followOutput(DockerClient dockerClient, String containerId, - Consumer consumer, OutputFrame.OutputType... types) { + public String getOutput(DockerClient dockerClient, + String containerId, + OutputFrame.OutputType... types) { + + if (containerId == null) { + return ""; + } + + if (types.length == 0) { + types = new OutputFrame.OutputType[] { STDOUT, STDERR }; + } + + final ToStringConsumer consumer = new ToStringConsumer(); + final WaitingConsumer wait = new WaitingConsumer(); + attachConsumer(dockerClient, containerId, consumer.andThen(wait), false, types); + + wait.waitUntilEnd(); + return consumer.toUtf8String(); + } + + private static void attachConsumer(DockerClient dockerClient, + String containerId, + Consumer consumer, + boolean followStream, + OutputFrame.OutputType... types) { final LogContainerCmd cmd = dockerClient.logContainerCmd(containerId) - .withFollowStream(true) - .withSince(0); + .withFollowStream(followStream) + .withSince(0); final FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); for (OutputFrame.OutputType type : types) { @@ -38,9 +98,4 @@ public void followOutput(DockerClient dockerClient, String containerId, cmd.exec(callback); } - - public void followOutput(DockerClient dockerClient, String containerId, Consumer consumer) { - followOutput(dockerClient, containerId, consumer, STDOUT, STDERR); - } - } diff --git a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java new file mode 100644 index 00000000000..f95d5a06850 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java @@ -0,0 +1,72 @@ +package org.testcontainers.containers.output; + +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; +import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; + +public class ContainerLogsTest { + + @Test + public void getLogsReturnsAllLogsToDate() { + try (GenericContainer container = shortLivedContainer()) { + container.start(); + + // docsGetAllLogs { + final String logs = container.getLogs(); + // } + assertEquals("stdout and stderr are reflected in the returned logs", "stdout\nstderr", logs); + } + } + + @Test + public void getLogsReturnsStdOutToDate() { + try (GenericContainer container = shortLivedContainer()) { + container.start(); + + // docsGetStdOut { + final String logs = container.getLogs(STDOUT); + // } + assertEquals("stdout and stderr are reflected in the returned logs", "stdout", logs); + } + } + + @Test + public void getLogsReturnsStdErrToDate() { + try (GenericContainer container = shortLivedContainer()) { + container.start(); + + // docsGetStdErr { + final String logs = container.getLogs(STDERR); + // } + assertEquals("stdout and stderr are reflected in the returned logs", "stderr", logs); + } + } + + @Test + public void getLogsForLongRunningContainer() throws InterruptedException { + try (GenericContainer container = longRunningContainer()) { + container.start(); + + Thread.sleep(1000L); + + final String logs = container.getLogs(STDOUT); + assertTrue("stdout is reflected in the returned logs for a running container", logs.contains("seq=0")); + } + } + + private static GenericContainer shortLivedContainer() { + return new GenericContainer("alpine:3.3") + .withCommand("/bin/sh", "-c", "echo -n 'stdout' && echo -n 'stderr' 1>&2") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + } + + private static GenericContainer longRunningContainer() { + return new GenericContainer("alpine:3.3") + .withCommand("ping -c 100 127.0.0.1"); + } +} diff --git a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java index 1118302f701..30230cc12ff 100644 --- a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java +++ b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java @@ -3,13 +3,8 @@ import org.junit.ClassRule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.ToStringConsumer; -import org.testcontainers.containers.output.WaitingConsumer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; -import java.util.function.Consumer; - import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** @@ -17,20 +12,15 @@ */ public class WorkingDirectoryTest { - private static WaitingConsumer waitingConsumer = new WaitingConsumer(); - private static ToStringConsumer toStringConsumer = new ToStringConsumer(); - private static Consumer compositeConsumer = waitingConsumer.andThen(toStringConsumer); - @ClassRule public static GenericContainer container = new GenericContainer("alpine:3.2") .withWorkingDirectory("/etc") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withCommand("ls", "-al") - .withLogConsumer(compositeConsumer); + .withCommand("ls", "-al"); @Test public void checkOutput() { - String listing = toStringConsumer.toUtf8String(); + String listing = container.getLogs(); assertTrue("Directory listing contains expected /etc content", listing.contains("hostname")); assertTrue("Directory listing contains expected /etc content", listing.contains("init.d")); diff --git a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java index b73bfeed46e..3789a654c20 100644 --- a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java +++ b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java @@ -5,15 +5,11 @@ import org.hamcrest.core.IsCollectionContaining; import org.junit.Test; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.ToStringConsumer; -import org.testcontainers.containers.output.WaitingConsumer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.images.builder.ImageFromDockerfile; import java.io.File; import java.util.Arrays; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.containsString; @@ -23,12 +19,7 @@ public class DirectoryTarResourceTest { @Test - public void simpleRecursiveFileTest() throws TimeoutException { - - WaitingConsumer wait = new WaitingConsumer(); - - final ToStringConsumer toString = new ToStringConsumer(); - + public void simpleRecursiveFileTest() { // 'src' is expected to be the project base directory, so all source code/resources should be copied in File directory = new File("src"); @@ -40,24 +31,17 @@ public void simpleRecursiveFileTest() throws TimeoutException { .cmd("cat /foo/test/resources/test-recursive-file.txt") .build() ).withFileFromFile("/tmp/foo", directory)) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withLogConsumer(wait.andThen(toString)); + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); - wait.waitUntilEnd(60, TimeUnit.SECONDS); - final String results = toString.toUtf8String(); + final String results = container.getLogs(); assertTrue("The container has a file that was copied in via a recursive copy", results.contains("Used for DirectoryTarResourceTest")); } @Test - public void simpleRecursiveFileWithPermissionTest() throws TimeoutException { - - WaitingConsumer wait = new WaitingConsumer(); - - final ToStringConsumer toString = new ToStringConsumer(); - + public void simpleRecursiveFileWithPermissionTest() { GenericContainer container = new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> @@ -67,13 +51,10 @@ public void simpleRecursiveFileWithPermissionTest() throws TimeoutException { .build() ).withFileFromFile("/tmp/foo", new File("/mappable-resource/test-resource.txt"), 0754)) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withLogConsumer(wait.andThen(toString)); + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); - wait.waitUntilEnd(60, TimeUnit.SECONDS); - - String listing = toString.toUtf8String(); + String listing = container.getLogs(); assertThat("Listing shows that file is copied with mode requested.", Arrays.asList(listing.split("\\n")), @@ -81,13 +62,9 @@ public void simpleRecursiveFileWithPermissionTest() throws TimeoutException { } @Test - public void simpleRecursiveClasspathResourceTest() throws TimeoutException { + public void simpleRecursiveClasspathResourceTest() { // This test combines the copying of classpath resources from JAR files with the recursive TAR approach, to allow JARed classpath resources to be copied in to an image - WaitingConsumer wait = new WaitingConsumer(); - - final ToStringConsumer toString = new ToStringConsumer(); - GenericContainer container = new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> @@ -96,13 +73,11 @@ public void simpleRecursiveClasspathResourceTest() throws TimeoutException { .cmd("ls -lRt /foo") .build() ).withFileFromClasspath("/tmp/foo", "/recursive/dir")) // here we use /org/junit as a directory that really should exist on the classpath - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withLogConsumer(wait.andThen(toString)); + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); - wait.waitUntilEnd(60, TimeUnit.SECONDS); - final String results = toString.toUtf8String(); + final String results = container.getLogs(); // ExternalResource.class is known to exist in a subdirectory of /org/junit so should be successfully copied in assertTrue("The container has a file that was copied in via a recursive copy from a JAR resource", results.contains("content.txt")); diff --git a/docs/features/container_logs.md b/docs/features/container_logs.md index 389dc57c631..a9e2832eb70 100644 --- a/docs/features/container_logs.md +++ b/docs/features/container_logs.md @@ -1,13 +1,34 @@ # Accessing container logs -It is possible to capture container output using the `followOutput()` method. This method accepts a Consumer and (optionally) +It is possible to capture container output using: + + * the `getLogs()` method, which simply returns a `String` snapshot of a container's entire log output + * the `followOutput()` method. This method accepts a Consumer and (optionally) a varargs list stating which of STDOUT, STDERR, or both, should be followed. If not specified, both will be followed. At present, container output will always begin from the time of container creation. -Testcontainers includes some out-of-the-box Consumer implementations that can be used; examples follow. +## Reading all logs (from startup time to present) -## Streaming container output to an SLF4J logger +`getLogs()` is the simplest mechanism for accessing container logs, and can be used as follows: + + +[Accessing all output (stdout and stderr)](../../core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java) inside_block:docsGetAllLogs + + + +[Accessing just stdout](../../core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java) inside_block:docsGetStdOut + + + +[Accessing just stderr](../../core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java) inside_block:docsGetStdErr + + +## Streaming logs + +Testcontainers includes some out-of-the-box Consumer implementations that can be used with the streaming `followOutput()` model; examples follow. + +### Streaming container output to an SLF4J logger Given an existing SLF4J logger instance named LOGGER: ```java @@ -15,7 +36,10 @@ Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER); container.followOutput(logConsumer); ``` -## Capturing container output as a String +### Capturing container output as a String + +To stream logs live or customize the decoding, `ToStringConsumer` may be used: + ```java ToStringConsumer toStringConsumer = new ToStringConsumer(); container.followOutput(toStringConsumer, OutputType.STDOUT); @@ -26,7 +50,7 @@ String utf8String = toStringConsumer.toUtf8String(); String otherString = toStringConsumer.toString(CharSet.forName("ISO-8859-1")); ``` -## Waiting for container output to contain expected content +### Waiting for container output to contain expected content `WaitingConsumer` will block until a frame of container output (usually a line) matches a provided predicate. From 1021e0e5c232b0f1a3392cffacf074d9ccfdeb36 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 25 Mar 2019 15:23:46 +0000 Subject: [PATCH 0031/4969] Update latest version number --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 31938bb99f7..fc37c0be80a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,4 +77,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.11.0 + latest_version: 1.11.1 From d6e0e8c7b46a7a88d1b399db3e0109ce85172e0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 28 Mar 2019 17:37:55 +0000 Subject: [PATCH 0032/4969] Bump transport from 6.6.2 to 6.7.0 in /modules/elasticsearch (#1344) Bumps [transport](https://github.com/elastic/elasticsearch) from 6.6.2 to 6.7.0.
Commits - [`8453f77`](https://github.com/elastic/elasticsearch/commit/8453f7701de25c467ce08088ddddac185cb8028c) SQL: Preserve original source for cast/convert function ([#40271](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40271)) - [`8b9fd09`](https://github.com/elastic/elasticsearch/commit/8b9fd0937d1e1a4ef95dc0db6b111ff80955104a) Reduce retention lease sync intervals ([#40302](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40302)) - [`c1999c7`](https://github.com/elastic/elasticsearch/commit/c1999c7b604793bc808b3685f11610def576a154) SQL: fix LIKE function equality by considering its pattern as well ([#40260](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40260)) - [`3522b00`](https://github.com/elastic/elasticsearch/commit/3522b00ae6c46cb3154fb660d998ee4ddd7ceb4c) Moving tests in locale-aware test file ([#40254](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40254)) - [`145e10b`](https://github.com/elastic/elasticsearch/commit/145e10b52e45818a84b7afaa6c627faba9e82769) Fix so non super users can also create API keys ([#40028](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40028)) ([#40288](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40288)) - [`e9ab087`](https://github.com/elastic/elasticsearch/commit/e9ab0879077df9f07c783005a4da0b37cd8a1d90) SQL: Fix issue with getting DATE type in JDBC ([#40207](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40207)) - [`3c00866`](https://github.com/elastic/elasticsearch/commit/3c008663a2749ff38804700bf0163814369b703f) SQL: Fix issue with optimization on queries with ORDER BY/LIMIT ([#40256](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40256)) - [`6998ea7`](https://github.com/elastic/elasticsearch/commit/6998ea7280772816b503d72ce9a5621328848c82) SQL: Fix issue with date columns returned always in UTC ([#40163](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40163)) - [`df1883d`](https://github.com/elastic/elasticsearch/commit/df1883d745f074d4d0c3de41726bddbf80c16243) Fix snapshot restore logging on fresh restore ([#40252](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40252)) - [`d5b26a4`](https://github.com/elastic/elasticsearch/commit/d5b26a46cd2e2b6d75442385b59427ad102c0419) Cascading primary failure lead to MSU too low ([#40249](https://github-redirect.dependabot.com/elastic/elasticsearch/issues/40249)) - Additional commits viewable in [compare view](https://github.com/elastic/elasticsearch/compare/v6.6.2...v6.7.0)

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.elasticsearch.client:transport&package-manager=gradle&previous-version=6.6.2&new-version=6.7.0)](https://dependabot.com/compatibility-score.html?dependency-name=org.elasticsearch.client:transport&package-manager=gradle&previous-version=6.6.2&new-version=6.7.0) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 78d8c96a4be..f7119b02ef6 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.6.2" - testCompile "org.elasticsearch.client:transport:6.6.2" + testCompile "org.elasticsearch.client:transport:6.7.0" } From bf1e5b22dbb090d2e49e6232dbf885b5a941a69e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 28 Mar 2019 17:38:29 +0000 Subject: [PATCH 0033/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#1343) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 6.6.2 to 6.7.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v6.6.2...v6.7.0) Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index f7119b02ef6..af6efc2a436 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.6.2" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.7.0" testCompile "org.elasticsearch.client:transport:6.7.0" } From 94b1a3c9b85311143aa60dd210af6c6ccb05ca91 Mon Sep 17 00:00:00 2001 From: bopi- Date: Fri, 29 Mar 2019 17:47:09 +0100 Subject: [PATCH 0034/4969] hostPort != containerPort (#1334) * hostPort != containerPort * hostPort != containerPort * hostPort != containerPort * hostPort != containerPort * hostPort != containerPort * hostPort != containerPort * hostPort != containerPort * Update ExposedHostTest.java * Do not use the two-keys Map because of the key conflicts --- .../org/testcontainers/Testcontainers.java | 10 ++++++++++ .../containers/PortForwardingContainer.java | 13 ++++++++++--- .../containers/ExposedHostTest.java | 18 ++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/testcontainers/Testcontainers.java b/core/src/main/java/org/testcontainers/Testcontainers.java index 4d7f5af4753..0f83725c55b 100644 --- a/core/src/main/java/org/testcontainers/Testcontainers.java +++ b/core/src/main/java/org/testcontainers/Testcontainers.java @@ -1,6 +1,10 @@ package org.testcontainers; +import java.util.Map; +import java.util.Map.Entry; + import lombok.experimental.UtilityClass; + import org.testcontainers.containers.PortForwardingContainer; @UtilityClass @@ -11,4 +15,10 @@ public void exposeHostPorts(int... ports) { PortForwardingContainer.INSTANCE.exposeHostPort(port); } } + + public void exposeHostPorts(Map ports) { + for(Entry entry : ports.entrySet()) { + PortForwardingContainer.INSTANCE.exposeHostPort(entry.getKey(), entry.getValue()); + } + } } diff --git a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java index 576ac33d148..852a986b58f 100644 --- a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java @@ -8,10 +8,12 @@ import org.testcontainers.utility.TestcontainersConfiguration; import java.time.Duration; +import java.util.AbstractMap; import java.util.Collections; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; public enum PortForwardingContainer { @@ -19,7 +21,7 @@ public enum PortForwardingContainer { private GenericContainer container; - private final Set exposedPorts = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Set> exposedPorts = Collections.newSetFromMap(new ConcurrentHashMap<>()); @Getter(value = AccessLevel.PRIVATE, lazy = true) private final Connection sshConnection = createSSHSession(); @@ -56,8 +58,13 @@ private Connection createSSHSession() { @SneakyThrows public void exposeHostPort(int port) { - if (exposedPorts.add(port)) { - getSshConnection().requestRemotePortForwarding("", port, "localhost", port); + exposeHostPort(port, port); + } + + @SneakyThrows + public void exposeHostPort(int hostPort, int containerPort) { + if (exposedPorts.add(new AbstractMap.SimpleEntry<>(hostPort, containerPort))) { + getSshConnection().requestRemotePortForwarding("", containerPort, "localhost", hostPort); } } diff --git a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java index 30bb6573533..8c98b0730b0 100644 --- a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java +++ b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java @@ -1,5 +1,6 @@ package org.testcontainers.containers; +import com.google.common.collect.ImmutableMap; import com.sun.net.httpserver.HttpServer; import lombok.SneakyThrows; import org.junit.AfterClass; @@ -30,6 +31,9 @@ public static void setUpClass() throws Exception { server.start(); Testcontainers.exposeHostPorts(server.getAddress().getPort()); + + Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 80)); + Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 81)); } @AfterClass @@ -39,22 +43,28 @@ public static void tearDownClass() throws Exception { @Test public void testExposedHost() throws Exception { - assertResponse(new GenericContainer().withCommand("top")); + assertResponse(new GenericContainer().withCommand("top"), server.getAddress().getPort()); } @Test public void testExposedHostWithNetwork() throws Exception { try (Network network = Network.newNetwork()) { - assertResponse(new GenericContainer().withNetwork(network).withCommand("top")); + assertResponse(new GenericContainer().withNetwork(network).withCommand("top"), server.getAddress().getPort()); } } + + @Test + public void testExposedHostPortOnFixedInternalPorts() throws Exception { + assertResponse(new GenericContainer().withCommand("top"), 80); + assertResponse(new GenericContainer().withCommand("top"), 81); + } @SneakyThrows - protected void assertResponse(GenericContainer container) { + protected void assertResponse(GenericContainer container, int port) { try { container.start(); - String response = container.execInContainer("wget", "-O", "-", "http://host.testcontainers.internal:" + server.getAddress().getPort()).getStdout(); + String response = container.execInContainer("wget", "-O", "-", "http://host.testcontainers.internal:" + port).getStdout(); assertEquals("received response", "Hello World!", response); } finally { From bb7c9bd1a665432d1fbb139ee7d6d60f1eb7aba2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 8 Apr 2019 16:50:45 +0100 Subject: [PATCH 0035/4969] Bump neo4j from 3.5.3 to 3.5.4 in /modules/neo4j (#1368) Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.3 to 3.5.4.
Release notes *Sourced from [neo4j's releases](https://github.com/neo4j/neo4j/releases).* > ## Neo4j 1.9.0 stable release > The 1.9 release of Neo4j builds upon the previous 1.8 releases and brings extensive improvements in stability and performance. In addition, _Neo4j 1.9 Enterprise_ introduces auto-clustering support, with dramatically simplified configuration and deployment for high demand production use. > - Support for [auto-clustering in _Neo4j Enterprise_](http://docs.neo4j.org/chunked/1.9/ha.html), which replaces the previous Zookeeper based HA clustering, provides a streamlined deployment process and is much safer and more resilient in failure scenarios. > - New [neo4j-arbiter](http://docs.neo4j.org/chunked/1.9/arbiter-instances.html) tool, which acts as a voting instance in a Neo4j cluster but does not keep a data store or handle transactions. > - Addition of [string manipulation, timestamp and other functions](http://docs.neo4j.org/chunked/1.9/query-function.html) to the Cypher query language. > - Improvements to memory utilization, which reduces working memory requirements and improves overall performance. > - New [REST endpoints for inspecting cluster status information](http://docs.neo4j.org/chunked/1.9/ha-rest-info.html) (master, slave, etc). > - Correction of several concurrency and performance issues. > - Improvements to [Online Backup](http://docs.neo4j.org/chunked/1.9/operations-backup.html) in _Neo4j Enterprise_, including auto-detection of full vs incremental backup based on existing content at the backup location. > - Updates to Neo4j server webadmin, including welcome pages for new users. > > **It is recommended to upgrade all previous Neo4j installations to this release.** Neo4j 1.9 does not require any explicit upgrade to persistent stores created using Neo4j 1.7 and 1.8 installations, however _current users of Neo4j Enterprise must consult the documentation and update the cluster configuration_. Please see the [deployment](http://docs.neo4j.org/chunked/1.9/deployment.html) and [cluster upgrade](http://docs.neo4j.org/chunked/1.9/upgrade-guide.html) sections of the Neo4j manual for more detail. Also note that Neo4j 1.9 is tested and supported with [Oracle JRE 7](http://www.oracle.com/technetwork/java/javase/downloads/index.html). _Users of previous Java versions should upgrade to [Oracle JRE 7](http://www.oracle.com/technetwork/java/javase/downloads/index.html) when deploying Neo4j 1.9._ > > As part of the Neo4j 1.9 release, multiple behaviours and features of Neo4j have been declared as deprecated, in order to help users prepare for the removal of these in the next major Neo4j release. A [list of deprecations](http://docs.neo4j.org/chunked/1.9.3/deprecations.html) can be found in the Neo4j manual. > > For a full summary of changes in this release, please review the CHANGES.TXT file contained within the distribution. > > ## Neo4j 1.8.0 stable release > The 1.8 release of Neo4j provides extensive improvements in stability and performance. As an incremental service release, Neo4j 1.8 builds upon the previous 1.6 and 1.7 releases and provides full backward compatibility. > > This release includes the following corrections and improvements: > - Correction of several concurrency issues affecting performance in multi- > threaded configurations. > - Correction of several concurrency issues that infrequently affect consistency of persisted data. > - Optimization of high-availability (HA) protocols to increase write performance. > - Support for zero-downtime rolling upgrades in HA clusters. > - Improvements to transaction distribution in HA clusters, providing greater resistance to branching. > - Configurable rotation of logical logs. > - Support for streamed responses to REST API requests. > - Support for bi-directional traversals, branch state and path expanders in the traversal framework. > - Performance improvements to several graph algorithms. > - Support in the Cypher language for writing graph data and updating auto-indexes (manual indexes are not supported). > - Extensions to the Cypher language to allow the use of patterns as expressions and predicates. > - Correction of several issues in the Cypher parser when using collections and when aggregating. > - Improved error reporting in Cypher and more reliable statement parsing. > - Support for explicit transactions in neo4j-shell. > > **It is recommended to upgrade all previous Neo4j installations to this release.** Neo4j 1.8 does not require any explicit upgrade to persistent stores created using Neo4j 1.6 and 1.7 installations. Please see the [deployment section of the Neo4j manual](http://docs.neo4j.org/chunked/1.8/deployment.html) for more detail. > > For a full summary of changes in this release, please review the CHANGES.TXT file contained within the distribution.
Commits - [`a41a4c3`](https://github.com/neo4j/neo4j/commit/a41a4c33edcacd51f2ad1305895d47db588d83bb) Ignored revapi for default method and made guard installer thread safe - [`58a2d96`](https://github.com/neo4j/neo4j/commit/58a2d9695d17a1f936dbae65231e9c689b008a23) Address reviewer feedback for 1603 - [`1515a6b`](https://github.com/neo4j/neo4j/commit/1515a6bbed4b21c4a2e5da21990d92dcb5c766a7) Test fixes - [`214c116`](https://github.com/neo4j/neo4j/commit/214c116f659b11c6eb8b11429d602586ad7bf128) Added AvailabilityGuardInstaller to LifecycleManagingDatabase - [`8d133d5`](https://github.com/neo4j/neo4j/commit/8d133d590b7cb54d2b949acd67243ebe2f43d685) Merge branch '3.4' into 3.5 - [`c60c090`](https://github.com/neo4j/neo4j/commit/c60c090b64ee00b6c8c2598e42cd5fa92b4849a4) Merge branch '3.3' into 3.4 - [`dadb6a9`](https://github.com/neo4j/neo4j/commit/dadb6a992e7e02c3f16a71ef0f93152f393bcf0a) Backport a data-race fix that could prevent profiles from being captured. - [`e4db673`](https://github.com/neo4j/neo4j/commit/e4db673dcf926f7c779bf62d5d1feadf1abc611b) Merge remote-tracking branch 'origin/3.4' into 3.5 - [`2041c79`](https://github.com/neo4j/neo4j/commit/2041c79183c8ab1f136ea0eb70b920e0a949d1d5) Merge remote-tracking branch 'origin/3.3' into 3.4 - [`f9c012a`](https://github.com/neo4j/neo4j/commit/f9c012ad1e0501865a0f7940f3e3e8e472f36eb7) Fix possible NPE in dbms.setTXMetaData - Additional commits viewable in [compare view](https://github.com/neo4j/neo4j/compare/3.5.3...3.5.4)

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.neo4j:neo4j&package-manager=gradle&previous-version=3.5.3&new-version=3.5.4)](https://dependabot.com/compatibility-score.html?dependency-name=org.neo4j:neo4j&package-manager=gradle&previous-version=3.5.3&new-version=3.5.4) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 092cb3a6889..9b0f3a48c3b 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -25,7 +25,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.3" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.4" compile project(":testcontainers") From 81ca4f196436c56c423cea0c663312e049635ab6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 8 Apr 2019 16:51:12 +0100 Subject: [PATCH 0036/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#1369) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 6.7.0 to 6.7.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v6.7.0...v6.7.1) Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index af6efc2a436..68e9028c43b 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.7.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.7.1" testCompile "org.elasticsearch.client:transport:6.7.0" } From dc61742b47c1a20edf8b1057c2db0fc079bf7a89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 8 Apr 2019 16:51:27 +0100 Subject: [PATCH 0037/4969] Bump junit-jupiter-engine from 5.4.1 to 5.4.2 in /modules/junit-jupiter (#1364) Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.4.1 to 5.4.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.4.1...r5.4.2) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ba9a2db096e..bd2f38e5737 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.15' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.1' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.2' } test { From 12c1fd4a39ad5f371bca2f896bcd2bcefb8fc205 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 8 Apr 2019 16:56:51 +0100 Subject: [PATCH 0038/4969] Bump httpclient from 4.5.7 to 4.5.8 in /modules/spock (#1353) Bumps httpclient from 4.5.7 to 4.5.8. [![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.apache.httpcomponents:httpclient&package-manager=gradle&previous-version=4.5.7&new-version=4.5.8)](https://dependabot.com/compatibility-score.html?dependency-name=org.apache.httpcomponents:httpclient&package-manager=gradle&previous-version=4.5.7&new-version=4.5.8) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 2e8b175e303..d9c482b0c7b 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' - testCompile 'org.apache.httpcomponents:httpclient:4.5.7' + testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.15' From 9f23e022fca06e1903ebb811b194ca8fd0c75ada Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 8 Apr 2019 16:57:16 +0100 Subject: [PATCH 0039/4969] Bump httpclient from 4.5.7 to 4.5.8 in /modules/junit-jupiter (#1352) Bumps httpclient from 4.5.7 to 4.5.8. Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index bd2f38e5737..36b0f217cb4 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,7 +8,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'redis.clients:jedis:3.0.1' - testCompile 'org.apache.httpcomponents:httpclient:4.5.7' + testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.15' From 738c90a8f08b45ed7f7cb3bb49a9ad18cafacab5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 8 Apr 2019 16:57:31 +0100 Subject: [PATCH 0040/4969] Bump httpclient from 4.5.7 to 4.5.8 in /core (#1351) Bumps httpclient from 4.5.7 to 4.5.8. Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 1e3083c4542..57984f513f6 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -100,7 +100,7 @@ dependencies { exclude(group: 'org.slf4j') } - testCompile 'org.apache.httpcomponents:httpclient:4.5.7' + testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.6.0' testCompile 'org.mongodb:mongo-java-driver:3.10.1' From 935b12f3798265c588f28212877719721b4f39cf Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 9 Apr 2019 15:54:04 +0100 Subject: [PATCH 0041/4969] Update mssqlserver docs to link to EULA description --- docs/modules/databases/mssqlserver.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/modules/databases/mssqlserver.md b/docs/modules/databases/mssqlserver.md index 9d63cee9494..9e0bec25dad 100644 --- a/docs/modules/databases/mssqlserver.md +++ b/docs/modules/databases/mssqlserver.md @@ -20,7 +20,9 @@ public class SomeTest { ``` !!! warning "EULA Acceptance" - Due to licencing restrictions you are required to accept an EULA for this container image. To indicate that you accept the MS SQL Server image EULA, Please place a file at the root of the classpath named `container-license-acceptance.txt`, e.g. at `src/test/resources/container-license-acceptance.txt`. This file should contain the line: `mcr.microsoft.com/mssql/server:latest` + Due to licencing restrictions you are required to accept an EULA for this container image. To indicate that you accept the MS SQL Server image EULA, Please place a file at the root of the classpath named `container-license-acceptance.txt`, e.g. at `src/test/resources/container-license-acceptance.txt`. This file should contain the line: `mcr.microsoft.com/mssql/server:2017-CU12` (or, if you are overriding the docker image name/tag, update accordingly). + + Please see the [`microsoft-mssql-server` image documentation](https://hub.docker.com/_/microsoft-mssql-server#environment-variables) for a link to the EULA document. ## Adding this module to your project dependencies From 1938b32868751af6b28304292bf5b6fa9a4bf18e Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 9 Apr 2019 20:18:55 +0100 Subject: [PATCH 0042/4969] Add build args and Dockerfile path override to ImageFromDockerfile (#1372) --- .../images/builder/ImageFromDockerfile.java | 20 ++++++ .../images/builder/DockerfileBuildTest.java | 67 +++++++++++++++++++ .../dockerfile-build-test/Dockerfile | 2 + .../dockerfile-build-test/Dockerfile-alt | 2 + .../dockerfile-build-test/Dockerfile-buildarg | 3 + .../dockerfile-build-test/localfile.txt | 1 + docs/features/creating_images.md | 33 +++++++-- 7 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java create mode 100644 core/src/test/resources/dockerfile-build-test/Dockerfile create mode 100644 core/src/test/resources/dockerfile-build-test/Dockerfile-alt create mode 100644 core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg create mode 100644 core/src/test/resources/dockerfile-build-test/localfile.txt diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index ed109acc4c3..c7d409c0660 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -23,6 +23,7 @@ import java.io.PipedOutputStream; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.zip.GZIPOutputStream; @@ -60,6 +61,8 @@ public class ImageFromDockerfile extends LazyFuture implements private boolean deleteOnExit = true; private final Map transferables = new HashMap<>(); + private final Map buildArgs = new HashMap<>(); + private Optional dockerFilePath = Optional.empty(); public ImageFromDockerfile() { this("testcontainers/" + Base58.randomString(16).toLowerCase()); @@ -139,5 +142,22 @@ public void onNext(BuildResponseItem item) { protected void configure(BuildImageCmd buildImageCmd) { buildImageCmd.withTag(this.getDockerImageName()); + this.dockerFilePath.ifPresent(buildImageCmd::withDockerfilePath); + this.buildArgs.forEach(buildImageCmd::withBuildArg); + } + + public ImageFromDockerfile withBuildArg(final String key, final String value) { + this.buildArgs.put(key, value); + return this; + } + + public ImageFromDockerfile withBuildArgs(final Map args) { + this.buildArgs.putAll(args); + return this; + } + + public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildRoot) { + this.dockerFilePath = Optional.of(relativePathFromBuildRoot); + return this; } } diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java new file mode 100644 index 00000000000..4c33fe9118b --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java @@ -0,0 +1,67 @@ +package org.testcontainers.images.builder; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; + +@RunWith(Parameterized.class) +public class DockerfileBuildTest { + + private static final Path RESOURCE_PATH = Paths.get("src/test/resources/dockerfile-build-test"); + + public String expectedFileContent; + public ImageFromDockerfile image; + + @Parameterized.Parameters + public static Object[][] parameters() { + return new Object[][]{ + // Dockerfile build without explicit per-file inclusion + new Object[]{"test1234", + // docsShowRecursiveFileInclusion { + new ImageFromDockerfile() + .withFileFromPath(".", RESOURCE_PATH) + // } + }, + + // Dockerfile build using a non-standard Dockerfile + new Object[]{"test4567", + new ImageFromDockerfile() + .withFileFromPath(".", RESOURCE_PATH) + .withDockerfilePath("./Dockerfile-alt") + }, + + // Dockerfile build using build args + new Object[]{"test7890", + new ImageFromDockerfile() + .withFileFromPath(".", RESOURCE_PATH) + .withDockerfilePath("./Dockerfile-buildarg") + .withBuildArg("CUSTOM_ARG", "test7890") + }, + }; + } + + public DockerfileBuildTest(String expectedFileContent, ImageFromDockerfile image) { + this.expectedFileContent = expectedFileContent; + this.image = image; + } + + @Test + public void performTest() { + try (final GenericContainer container = new GenericContainer(image) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withCommand("cat", "/test.txt")) { + + container.start(); + + final String logs = container.getLogs(); + assertTrue("expected file content indicates that dockerfile build steps have been run", logs.contains(expectedFileContent)); + } + } +} diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile b/core/src/test/resources/dockerfile-build-test/Dockerfile new file mode 100644 index 00000000000..eee182f21c1 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile @@ -0,0 +1,2 @@ +FROM alpine:3.2 +COPY localfile.txt /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-alt b/core/src/test/resources/dockerfile-build-test/Dockerfile-alt new file mode 100644 index 00000000000..f6938e5fc8d --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-alt @@ -0,0 +1,2 @@ +FROM alpine:3.2 +RUN echo "test4567" > /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg b/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg new file mode 100644 index 00000000000..4ae26f50f77 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg @@ -0,0 +1,3 @@ +FROM alpine:3.2 +ARG CUSTOM_ARG +RUN echo "${CUSTOM_ARG}" > /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/localfile.txt b/core/src/test/resources/dockerfile-build-test/localfile.txt new file mode 100644 index 00000000000..5586d4f8333 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/localfile.txt @@ -0,0 +1 @@ +test1234 diff --git a/docs/features/creating_images.md b/docs/features/creating_images.md index 0437e6d8a8e..0539642e159 100644 --- a/docs/features/creating_images.md +++ b/docs/features/creating_images.md @@ -9,10 +9,7 @@ image needs to be customized for specific test(s). Simply pass a configured instance of `ImageFromDockerfile` as a constructor parameter to `GenericContainer`. Testcontainers will `docker build` a temporary container image, and will use it when creating the container. - -## Examples - -### Dockerfile from String, file or classpath resource +## Dockerfile from String, file or classpath resource `ImageFromDockerfile` accepts arbitrary files, strings or classpath resources to be used as files in the build context. At least one of these needs to be a `Dockerfile`. @@ -25,14 +22,27 @@ public GenericContainer dslContainer = new GenericContainer( .withFileFromClasspath("Dockerfile", "mappable-dockerfile/Dockerfile")) ``` -The following methods may be used to provide the `Dockerfile` and any other required files: +The following methods may be used to provide the `Dockerfile` and any other required build context files: * `withFileFromString(buildContextPath, content)` * `withFileFromClasspath(buildContextPath, classpathPath)` * `withFileFromPath(buildContextPath, filesystemPath)` * `withFileFromFile(buildContextPath, filesystemFile)` -### Dockerfile DSL +!!! info + In older versions of Testcontainers (before 1.3.0) it was necessary to explicitly declare each file that needed to + be present in the Docker build context. + This can be replaced with the following syntax: + + [Passing an entire directory of files to the Dockerfile build context](../../core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java) inside_block:docsShowRecursiveFileInclusion + + + Where `RESOURCE_PATH` is the path to a directory containing a `Dockerfile` and any files that it needs to refer to. + Doing this is equivalent to `docker build RESOURCE_PATH` on the command line. + + To mimic `docker build .`, `RESOURCE_PATH` would simply be set to `.` as well. + +## Dockerfile DSL If a static Dockerfile is not sufficient (e.g. your test needs to cover many variations that are best generated programmatically), there is a DSL available to allow Dockerfiles to be defined in code. e.g.: @@ -64,3 +74,14 @@ By default the no-args constructor will use an image name of the form `testconta * `public ImageFromDockerfile()` * `public ImageFromDockerfile(String dockerImageName)` * `public ImageFromDockerfile(String dockerImageName, boolean deleteOnExit)` + +## Alternative Dockerfiles + +Normally Docker will automatically build an image from any `/Dockerfile` that it finds in the root of the build context. +To override this behaviour, use `.withDockerfilePath("./Name-Of-Other-Dockerfile")`. + +## Build Args + +[Build Args](https://docs.docker.com/engine/reference/builder/#arg) may be used to allow lightweight parameterization. + +To specify build args, use `.withBuildArg("varname", "value")` or provide a `Map` of args using `.withBuildArgs(map)`. From 30d5f8518f86dc2861213fb6f59432defcffcb82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 9 Apr 2019 20:21:15 +0100 Subject: [PATCH 0043/4969] Bump transport from 6.7.0 to 6.7.1 in /modules/elasticsearch (#1370) Bumps [transport](https://github.com/elastic/elasticsearch) from 6.7.0 to 6.7.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v6.7.0...v6.7.1) Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 68e9028c43b..699bc54bd9e 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.7.1" - testCompile "org.elasticsearch.client:transport:6.7.0" + testCompile "org.elasticsearch.client:transport:6.7.1" } From 2da17b9855f855b3ae6ea5b9f07f8cb6080dc2fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 9 Apr 2019 20:21:33 +0100 Subject: [PATCH 0044/4969] Bump mockito-core from 2.25.1 to 2.26.0 in /core (#1366) Bumps [mockito-core](https://github.com/mockito/mockito) from 2.25.1 to 2.26.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v2.25.1...v2.26.0) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 57984f513f6..cbac38e88ff 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -104,7 +104,7 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.6.0' testCompile 'org.mongodb:mongo-java-driver:3.10.1' - testCompile ('org.mockito:mockito-core:2.25.1') { + testCompile ('org.mockito:mockito-core:2.26.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 3fff9741183013666a0e5672fc1359e03f431681 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Wed, 10 Apr 2019 12:37:21 +0200 Subject: [PATCH 0045/4969] Improve WaitAllStrategy (#1272) --- .../containers/DockerComposeContainer.java | 2 +- .../wait/strategy/WaitAllStrategy.java | 73 +++++- .../containers/wait/WaitAllStrategyTest.java | 69 ------ .../wait/strategy/WaitAllStrategyTest.java | 224 ++++++++++++++++++ 4 files changed, 290 insertions(+), 78 deletions(-) delete mode 100644 core/src/test/java/org/testcontainers/containers/wait/WaitAllStrategyTest.java create mode 100644 core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index ae10c3096fa..0b6db19ca28 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -335,7 +335,7 @@ private String getServiceInstanceName(String serviceName) { */ private void addWaitStrategy(String serviceInstanceName, @NonNull WaitStrategy waitStrategy) { final WaitAllStrategy waitAllStrategy = waitStrategyMap.computeIfAbsent(serviceInstanceName, __ -> - (WaitAllStrategy) new WaitAllStrategy().withStartupTimeout(Duration.ofMinutes(30))); + new WaitAllStrategy(WaitAllStrategy.Mode.WITH_MAXIMUM_OUTER_TIMEOUT).withStartupTimeout(Duration.ofMinutes(30))); waitAllStrategy.withStrategy(waitStrategy); } diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java index 1cc76c0747c..cebacb375b6 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java @@ -1,34 +1,91 @@ package org.testcontainers.containers.wait.strategy; -import org.rnorth.ducttape.timeouts.Timeouts; - import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import org.rnorth.ducttape.timeouts.Timeouts; + public class WaitAllStrategy implements WaitStrategy { + public enum Mode { + + /** + * This is the default mode: The timeout of the {@link WaitAllStrategy strategy} is applied to each individual + * strategy, so that the container waits maximum for + * {@link org.testcontainers.containers.wait.strategy.WaitAllStrategy#timeout}. + */ + WITH_OUTER_TIMEOUT, + + /** + * Using this mode triggers the following behaviour: The outer timeout is disabled and the outer enclosing + * strategy waits for all inner strategies according to their timeout. Once set, it disables + * {@link org.testcontainers.containers.wait.strategy.WaitAllStrategy#withStartupTimeout(java.time.Duration)} method, + * as it would overwrite inner timeouts. + */ + WITH_INDIVIDUAL_TIMEOUTS_ONLY, + + /** + * This is the original mode of this strategy: The inner strategies wait with their preconfigured timeout + * individually and the wait all strategy kills them, if the outer limit is reached. + */ + WITH_MAXIMUM_OUTER_TIMEOUT + } + + private final Mode mode; private final List strategies = new ArrayList<>(); private Duration timeout = Duration.ofSeconds(30); + public WaitAllStrategy() { + this(Mode.WITH_OUTER_TIMEOUT); + } + + public WaitAllStrategy(Mode mode) { + this.mode = mode; + } + @Override public void waitUntilReady(WaitStrategyTarget waitStrategyTarget) { - Timeouts.doWithTimeout((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> { - for (WaitStrategy strategy : strategies) { - strategy.waitUntilReady(waitStrategyTarget); - } - }); + if (mode == Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) { + waitUntilNestedStrategiesAreReady(waitStrategyTarget); + } else { + Timeouts.doWithTimeout((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> { + waitUntilNestedStrategiesAreReady(waitStrategyTarget); + }); + } + } + + private void waitUntilNestedStrategiesAreReady(WaitStrategyTarget waitStrategyTarget) { + for (WaitStrategy strategy : strategies) { + strategy.waitUntilReady(waitStrategyTarget); + } } public WaitAllStrategy withStrategy(WaitStrategy strategy) { + + if (mode == Mode.WITH_OUTER_TIMEOUT) { + applyStartupTimeout(strategy); + } + this.strategies.add(strategy); return this; } @Override - public WaitStrategy withStartupTimeout(Duration startupTimeout) { + public WaitAllStrategy withStartupTimeout(Duration startupTimeout) { + + if (mode == Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) { + throw new IllegalStateException(String.format( + "Changing startup timeout is not supported with mode %s", Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY)); + } + this.timeout = startupTimeout; + strategies.forEach(this::applyStartupTimeout); return this; } + + private void applyStartupTimeout(WaitStrategy childStrategy) { + childStrategy.withStartupTimeout(this.timeout); + } } diff --git a/core/src/test/java/org/testcontainers/containers/wait/WaitAllStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/WaitAllStrategyTest.java deleted file mode 100644 index f47a7212a5c..00000000000 --- a/core/src/test/java/org/testcontainers/containers/wait/WaitAllStrategyTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.testcontainers.containers.wait; - -import com.google.common.util.concurrent.Uninterruptibles; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.rnorth.ducttape.TimeoutException; -import org.testcontainers.containers.GenericContainer; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.inOrder; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; - -public class WaitAllStrategyTest { - - @Mock - private GenericContainer container; - @Mock - private WaitStrategy strategy1; - @Mock - private WaitStrategy strategy2; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - } - - @Test - public void simpleTest() { - - final WaitStrategy underTest = new WaitAllStrategy() - .withStrategy(strategy1) - .withStrategy(strategy2); - - doNothing().when(strategy1).waitUntilReady(eq(container)); - doNothing().when(strategy2).waitUntilReady(eq(container)); - - underTest.waitUntilReady(container); - - InOrder inOrder = inOrder(strategy1, strategy2); - inOrder.verify(strategy1).waitUntilReady(any()); - inOrder.verify(strategy2).waitUntilReady(any()); - } - - @Test - public void appliesOuterTimeout() { - - final WaitStrategy underTest = new WaitAllStrategy() - .withStrategy(strategy1) - .withStartupTimeout(Duration.ofMillis(10)); - - doAnswer(invocation -> { - Uninterruptibles.sleepUninterruptibly(10, TimeUnit.SECONDS); - return null; - }).when(strategy1).waitUntilReady(eq(container)); - - assertThrows("The outer strategy timeout applies", TimeoutException.class, () -> { - underTest.waitUntilReady(container); - }); - } -} diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java new file mode 100644 index 00000000000..3b2172d5bcf --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java @@ -0,0 +1,224 @@ +package org.testcontainers.containers.wait.strategy; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.rnorth.visibleassertions.VisibleAssertions.*; + +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.rnorth.ducttape.TimeoutException; +import org.testcontainers.containers.GenericContainer; + +import com.google.common.util.concurrent.Uninterruptibles; + +public class WaitAllStrategyTest { + + @Mock + private GenericContainer container; + @Mock + private WaitStrategy strategy1; + @Mock + private WaitStrategy strategy2; + @Mock + private WaitStrategy strategy3; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void simpleTest() { + + final WaitStrategy underTest = new WaitAllStrategy() + .withStrategy(strategy1) + .withStrategy(strategy2); + + doNothing().when(strategy1).waitUntilReady(eq(container)); + doNothing().when(strategy2).waitUntilReady(eq(container)); + + underTest.waitUntilReady(container); + + InOrder inOrder = inOrder(strategy1, strategy2); + inOrder.verify(strategy1).waitUntilReady(any()); + inOrder.verify(strategy2).waitUntilReady(any()); + } + + @Test + public void maxTimeOutApplies() { + + WaitStrategy child1 = new SleepingStrategy(Duration.ofMinutes(30)) + .withStartupTimeout(Duration.ofHours(1)); + + final WaitStrategy underTest = new WaitAllStrategy() + .withStrategy(child1) + .withStartupTimeout(Duration.ofMillis(10)); + + assertThrows("The outer strategy timeout applies", TimeoutException.class, () -> { + underTest.waitUntilReady(container); + }); + } + + @Test + public void appliesOuterTimeoutTooLittleTime() { + + Duration defaultInnerWait = Duration.ofMillis(2); + Duration outerWait = Duration.ofMillis(6); + + WaitStrategy child1 = new SleepingStrategy(defaultInnerWait); + WaitStrategy child2 = new SleepingStrategy(defaultInnerWait); + + final WaitStrategy underTest = new WaitAllStrategy() + .withStrategy(child1) + .withStrategy(child2) + .withStartupTimeout(outerWait); + + assertThrows("The outer strategy timeout applies", TimeoutException.class, () -> { + underTest.waitUntilReady(container); + }); + } + + @Test + public void appliesOuterTimeoutEnoughTime() { + + Duration defaultInnerWait = Duration.ofMillis(2); + Duration outerWait = Duration.ofMillis(20); + + WaitStrategy child1 = new SleepingStrategy(defaultInnerWait); + WaitStrategy child2 = new SleepingStrategy(defaultInnerWait); + + final WaitStrategy underTest = new WaitAllStrategy() + .withStrategy(child1) + .withStrategy(child2) + .withStartupTimeout(outerWait); + + try { + underTest.waitUntilReady(container); + } catch (Exception e) { + if (e.getCause() instanceof CaughtTimeoutException) + fail("The timeout wasn't applied to inner strategies."); + else { + fail(e.getMessage()); + } + } + } + + @Test + public void withoutOuterTimeoutShouldRelyOnInnerStrategies() { + + final WaitStrategy underTest = new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) + .withStrategy(strategy1) + .withStrategy(strategy2) + .withStrategy(strategy3); + + doNothing().when(strategy1).waitUntilReady(eq(container)); + doThrow(TimeoutException.class).when(strategy2).waitUntilReady(eq(container)); + + assertThrows("The outer strategy timeout applies", TimeoutException.class, () -> { + underTest.waitUntilReady(container); + }); + + InOrder inOrder = inOrder(strategy1, strategy2, strategy3); + inOrder.verify(strategy1).waitUntilReady(any()); + inOrder.verify(strategy2).waitUntilReady(any()); + inOrder.verify(strategy3, never()).waitUntilReady(any()); + } + + @Test + public void timeoutChangeShouldNotBePossibleWithIndividualTimeoutMode() { + + final WaitStrategy underTest = new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY); + + assertThrows("Cannot change timeout for individual timeouts", IllegalStateException.class, () -> { + underTest.withStartupTimeout(Duration.ofSeconds(42)); + }); + } + + @Test + public void shouldNotMessWithIndividualTimeouts() { + + final WaitStrategy underTest = new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) + .withStrategy(strategy1) + .withStrategy(strategy2); + + verify(strategy1, never()).withStartupTimeout(any()); + verify(strategy1, never()).withStartupTimeout(any()); + } + + @Test + public void shouldOverwriteIndividualTimeouts() { + + Duration someSeconds = Duration.ofSeconds(23); + final WaitStrategy underTest = new WaitAllStrategy() + .withStartupTimeout(someSeconds) + .withStrategy(strategy1) + .withStrategy(strategy2); + + verify(strategy1).withStartupTimeout(someSeconds); + verify(strategy1).withStartupTimeout(someSeconds); + } + + @Test + public void appliesOuterTimeoutOnAdditionalChildren() { + + Duration defaultInnerWait = Duration.ofMillis(2); + Duration outerWait = Duration.ofMillis(20); + + WaitStrategy child1 = new SleepingStrategy(defaultInnerWait); + WaitStrategy child2 = new SleepingStrategy(defaultInnerWait); + + final WaitStrategy underTest = new WaitAllStrategy() + .withStrategy(child1) + .withStartupTimeout(outerWait) + .withStrategy(child2); + + try { + underTest.waitUntilReady(container); + } catch (Exception e) { + if (e.getCause() instanceof CaughtTimeoutException) + fail("The timeout wasn't applied to inner strategies."); + else { + fail(e.getMessage()); + } + } + } + + static class CaughtTimeoutException extends RuntimeException { + + CaughtTimeoutException(String message) { + super(message); + } + } + + static class SleepingStrategy extends AbstractWaitStrategy { + + private final long sleepingDuration; + + SleepingStrategy(Duration defaultInnerWait) { + super.startupTimeout = defaultInnerWait; + // Always oversleep by default + this.sleepingDuration = defaultInnerWait.multipliedBy(2).toMillis(); + } + + @Override + protected void waitUntilReady() { + try { + // Don't use ducttape, make sure we don't catch the wrong TimeoutException later on. + CompletableFuture.runAsync( + () -> Uninterruptibles.sleepUninterruptibly(this.sleepingDuration, TimeUnit.MILLISECONDS) + ).get((int) startupTimeout.toMillis(), TimeUnit.MILLISECONDS); + } catch (InterruptedException | ExecutionException e) { + } catch (java.util.concurrent.TimeoutException e) { + throw new CaughtTimeoutException("Inner wait timed out, outer strategy didn't apply."); + } + } + } +} From 1628b659cf991576902457845319602ea2c8fc23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 10 Apr 2019 17:58:43 +0100 Subject: [PATCH 0046/4969] Bump amqp-client from 5.6.0 to 5.7.0 in /core (#1367) Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.6.0 to 5.7.0.
Release notes *Sourced from [amqp-client's releases](https://github.com/rabbitmq/rabbitmq-java-client/releases).* > ## 5.7.0 > # Changes between 5.6.0 and 5.7.0 > > This is a minor release with usability improvements and dependency upgrades. All users of the 5.x.x series are encouraged to upgrade to this version. > > ## Improve logging for TLS connections > > GitHub issue: [#441](https://github-redirect.dependabot.com/rabbitmq/rabbitmq-java-client/issues/441) > > ## Don't panic when cancelling an unknown consumer > > GitHub issue: [#525](https://github-redirect.dependabot.com/rabbitmq/rabbitmq-java-client/issues/525) > > ## Bump dependencies > > GitHub issue: [#607](https://github-redirect.dependabot.com/rabbitmq/rabbitmq-java-client/issues/607) > > ## 5.7.0.RC1 > # Changes between 5.6.0 and 5.7.0.RC1 > > This is a pre-release for 5.7.0, a maintenance release with usability improvements and dependency upgrades. All users of the 5.x.x series are encouraged to test this version. > > ## Improve logging for TLS connections > > GitHub issue: [#441](https://github-redirect.dependabot.com/rabbitmq/rabbitmq-java-client/issues/441) > > ## Don't panic when cancelling an unknown consumer > > GitHub issue: [#525](https://github-redirect.dependabot.com/rabbitmq/rabbitmq-java-client/issues/525) > > ## Bump dependencies > > GitHub issue: [#607](https://github-redirect.dependabot.com/rabbitmq/rabbitmq-java-client/issues/607)
Changelog *Sourced from [amqp-client's changelog](https://github.com/rabbitmq/rabbitmq-java-client/blob/v5.7.0/release-versions.txt).* > RELEASE_VERSION="5.7.0" > DEVELOPMENT_VERSION="5.8.0-SNAPSHOT"
Commits - [`57aa724`](https://github.com/rabbitmq/rabbitmq-java-client/commit/57aa724ddd15ac376576894bd869d04b49e62451) [maven-release-plugin] prepare release v5.7.0 - [`1928ce8`](https://github.com/rabbitmq/rabbitmq-java-client/commit/1928ce86a7c7da761003af4ee8fed89237b18938) Set release version to 5.7.0 - [`9f2dffe`](https://github.com/rabbitmq/rabbitmq-java-client/commit/9f2dffec12bcebcc41dc0d2a6d996df04661143a) [maven-release-plugin] prepare for next development iteration - [`e79ed4d`](https://github.com/rabbitmq/rabbitmq-java-client/commit/e79ed4d7491bc541e15c3e548ed77181778ff0b8) [maven-release-plugin] prepare release v5.7.0.RC1 - [`bb8f6ed`](https://github.com/rabbitmq/rabbitmq-java-client/commit/bb8f6edf2f4c7fc3d9c805b91c32e59a58782e0a) Bump test dependencies - [`953d255`](https://github.com/rabbitmq/rabbitmq-java-client/commit/953d255e4728b222e3f3fbc88b8db8a541d82933) Bump dependencies - [`e49f66d`](https://github.com/rabbitmq/rabbitmq-java-client/commit/e49f66d6f0fad816feb33012a95d059cfdab2c20) Add comment to explain decision tree - [`365dd22`](https://github.com/rabbitmq/rabbitmq-java-client/commit/365dd22a51a79ed40e7f45742a4eb71ecbfd44e5) Add test for Channel#basicCancel with unknown consumer tag - [`6081628`](https://github.com/rabbitmq/rabbitmq-java-client/commit/6081628163669bac39456c9fcf1dbc3c6692786d) Log warning when receiving basic.cancel for unknown consumer - [`be57b26`](https://github.com/rabbitmq/rabbitmq-java-client/commit/be57b2620a5d148af3a0857fe798bd1f1bbb26a6) Merge pull request [#548](https://github-redirect.dependabot.com/rabbitmq/rabbitmq-java-client/issues/548) from spring-operator/polish-urls-apache-license-5.x.x... - Additional commits viewable in [compare view](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.6.0...v5.7.0)

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=com.rabbitmq:amqp-client&package-manager=gradle&previous-version=5.6.0&new-version=5.7.0)](https://dependabot.com/compatibility-score.html?dependency-name=com.rabbitmq:amqp-client&package-manager=gradle&previous-version=5.6.0&new-version=5.7.0) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index cbac38e88ff..112bd096193 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -102,7 +102,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testCompile 'redis.clients:jedis:3.0.1' - testCompile 'com.rabbitmq:amqp-client:5.6.0' + testCompile 'com.rabbitmq:amqp-client:5.7.0' testCompile 'org.mongodb:mongo-java-driver:3.10.1' testCompile ('org.mockito:mockito-core:2.26.0') { exclude(module: 'hamcrest-core') From a6c676bc43541100f036ac368d242b25c5a16069 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 10 Apr 2019 17:58:56 +0100 Subject: [PATCH 0047/4969] Bump kafka-clients from 2.1.1 to 2.2.0 in /modules/kafka (#1338) Bumps kafka-clients from 2.1.1 to 2.2.0. Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 6985f7a89a6..cefb6368445 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.1.1' + testCompile 'org.apache.kafka:kafka-clients:2.2.0' testCompile 'org.assertj:assertj-core:3.12.2' testCompile 'com.google.guava:guava:23.0' } From 8a8548affca2dab87478677215283817ce3bbd46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 10 Apr 2019 18:00:14 +0100 Subject: [PATCH 0048/4969] Bump mongo-java-driver from 3.10.1 to 3.10.2 in /core (#1374) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.10.1 to 3.10.2. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.10.1...r3.10.2) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 112bd096193..1f08c0159b2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -103,7 +103,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.7.0' - testCompile 'org.mongodb:mongo-java-driver:3.10.1' + testCompile 'org.mongodb:mongo-java-driver:3.10.2' testCompile ('org.mockito:mockito-core:2.26.0') { exclude(module: 'hamcrest-core') } From 3b9e61e2b69db264db4e3f18dce8194d4debd2cf Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 11 Apr 2019 17:51:28 +0200 Subject: [PATCH 0049/4969] Fix shading of modules (#1342, #1390) --- build.gradle | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 75977bd540f..27f1d8859f1 100644 --- a/build.gradle +++ b/build.gradle @@ -56,16 +56,34 @@ subprojects { configurations = [] classifier = null - // Keep docker-java's package inside the final jar - relocate("com.github.dockerjava", "com.github.dockerjava") - } + doFirst { + // See https://github.com/johnrengelman/shadow/blob/5.0.0/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ConfigureShadowRelocation.groovy + Set packages = [] + // Always read from core's configurations + for (configuration in tasks.getByPath(":testcontainers:shadowJar").configurations) { + for (jar in configuration.files) { + def jf = new java.util.jar.JarFile(jar) + for (entry in jf.entries()) { + def name = entry.name + if (name.endsWith(".class")) { + packages.add(name.substring(0, name.lastIndexOf('/'))) + } + } + jf.close() + } + } + for (pkg in packages) { + pkg = pkg.replaceAll('/', '.') - task relocateShadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation) { - target = tasks.shadowJar - prefix = "org.testcontainers.shaded" - } + if (pkg.startsWith("com.github.dockerjava.")) { + // Keep docker-java's package inside the final jar + continue; + } - tasks.shadowJar.dependsOn tasks.relocateShadowJar + tasks.shadowJar.relocate(pkg, "org.testcontainers.shaded.${pkg}") + } + } + } publishing { publications { From 7501244d0ee19038b5e9c3c10d8c6844b0ce0d89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 13 Apr 2019 21:47:45 +0100 Subject: [PATCH 0050/4969] Bump cucumber-java from 2.3.1 to 4.3.0 in /examples (#1394) * Bump cucumber-java from 2.3.1 to 4.3.0 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 2.3.1 to 4.3.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v2.3.1...v4.3.0) Signed-off-by: dependabot[bot] * Bump cucumber libs together for compatibility --- examples/cucumber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index f8744b9d0e8..e9b052050d5 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:2.3.1' - testImplementation 'io.cucumber:cucumber-junit:2.3.1' + implementation 'io.cucumber:cucumber-java:4.3.0' + testImplementation 'io.cucumber:cucumber-junit:4.3.0' testImplementation 'org.testcontainers:selenium' } From e5b629eb668c103701b3fc4751b929c9b211f250 Mon Sep 17 00:00:00 2001 From: Gerasimov Gennady Date: Sat, 13 Apr 2019 23:50:05 +0300 Subject: [PATCH 0051/4969] Remove repeated call to toLowerCase() in ScriptUtils (#1397) Fixes #1396 --- .../java/org/testcontainers/ext/ScriptUtils.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java index 0f917a1561f..f27b3610f15 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java @@ -124,6 +124,7 @@ public static void splitSqlScript(String resource, String script, String separat Character currentLiteralDelimiter = null; int compoundStatementDepth = 0; + final String lowerCaseScriptContent = script.toLowerCase(); char[] content = script.toCharArray(); for (int i = 0; i < script.length(); i++) { char c = content[i]; @@ -148,24 +149,24 @@ public static void splitSqlScript(String resource, String script, String separat } final boolean inLiteral = currentLiteralDelimiter != null; - if (!inLiteral && containsSubstringAtOffset(script, commentPrefix, i)) { + if (!inLiteral && containsSubstringAtOffset(lowerCaseScriptContent, commentPrefix, i)) { inLineComment = true; } if (inLineComment && c == '\n') { inLineComment = false; } - if (!inLiteral && containsSubstringAtOffset(script, blockCommentStartDelimiter, i)) { + if (!inLiteral && containsSubstringAtOffset(lowerCaseScriptContent, blockCommentStartDelimiter, i)) { inBlockComment = true; } - if (!inLiteral && inBlockComment && containsSubstringAtOffset(script, blockCommentEndDelimiter, i)) { + if (!inLiteral && inBlockComment && containsSubstringAtOffset(lowerCaseScriptContent, blockCommentEndDelimiter, i)) { inBlockComment = false; } final boolean inComment = inLineComment || inBlockComment; - if (!inLiteral && !inComment && containsSubstringAtOffset(script, "BEGIN", i)) { + if (!inLiteral && !inComment && containsSubstringAtOffset(lowerCaseScriptContent, "BEGIN", i)) { compoundStatementDepth++; } - if (!inLiteral && !inComment && containsSubstringAtOffset(script, "END", i)) { + if (!inLiteral && !inComment && containsSubstringAtOffset(lowerCaseScriptContent, "END", i)) { compoundStatementDepth--; } final boolean inCompoundStatement = compoundStatementDepth != 0; @@ -222,8 +223,7 @@ else if (c == ' ' || c == '\n' || c == '\t') { } } - private static boolean containsSubstringAtOffset(String string, String substring, int offset) { - String lowercaseString = string.toLowerCase(); + private static boolean containsSubstringAtOffset(String lowercaseString, String substring, int offset) { String lowercaseSubstring = substring.toLowerCase(); return lowercaseString.startsWith(lowercaseSubstring, offset); From 92fc7fa78fc8eee94badd2d0df3e8a45809b9dfa Mon Sep 17 00:00:00 2001 From: sullis Date: Sun, 14 Apr 2019 06:46:00 -0400 Subject: [PATCH 0052/4969] Postgresql 9.6.8 -> 9.6.12 (#1350) --- .../java/org/testcontainers/containers/PostgreSQLContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 13c5b49efc7..eb7b78b1864 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -15,7 +15,7 @@ public class PostgreSQLContainer> extends JdbcDatabaseContainer { public static final String NAME = "postgresql"; public static final String IMAGE = "postgres"; - public static final String DEFAULT_TAG = "9.6.8"; + public static final String DEFAULT_TAG = "9.6.12"; public static final Integer POSTGRESQL_PORT = 5432; private String databaseName = "test"; From 6f6fb8299aaa6e01b93a2d4ba89e50e1a16927d5 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 15 Apr 2019 10:55:07 +0100 Subject: [PATCH 0053/4969] Attempt to make WaitAllStrategyTests more stable (#1400) @kiview WDYT? I was finding that these tests were failing randomly ~30% of the time, which is likely to be caused by the specific timing-sensitive aspects of the code. To be honest I also found the existing tests (the ones which exercised the timeouts behaviour) to be hard to follow, and therefore very hard to be sure that it would be both correct and stable. So, instead, I've updated the test: * to keep the existing mock-based tests to check _what the strategy does_ (agnostic of timeout durations). * to replace the timing-sensitive tests with some simpler tests that just check that the `startupTimeout`s get propagated properly. These tests _don't_ fire the `WaitAllStrategy`, i.e. don't actually wait at all. My thinking is that the combination of these two types of tests really should be enough. 'Integration testing' this would be nice, but is complicated and error prone, so testing the execution flow and the data flow, essentially, is a compromise that I'm happier with. --- .../wait/strategy/WaitAllStrategyTest.java | 161 ++++++------------ 1 file changed, 55 insertions(+), 106 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java index 3b2172d5bcf..897293282bd 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java @@ -1,14 +1,5 @@ package org.testcontainers.containers.wait.strategy; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.rnorth.visibleassertions.VisibleAssertions.*; - -import java.time.Duration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; @@ -17,7 +8,12 @@ import org.rnorth.ducttape.TimeoutException; import org.testcontainers.containers.GenericContainer; -import com.google.common.util.concurrent.Uninterruptibles; +import java.time.Duration; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; +import static org.rnorth.visibleassertions.VisibleAssertions.*; public class WaitAllStrategyTest { @@ -35,80 +31,78 @@ public void setUp() { MockitoAnnotations.initMocks(this); } + /* + * Dummy-based tests, to check that timeout values are propagated correctly, without involving actual timing-sensitive code + */ @Test - public void simpleTest() { - - final WaitStrategy underTest = new WaitAllStrategy() - .withStrategy(strategy1) - .withStrategy(strategy2); - - doNothing().when(strategy1).waitUntilReady(eq(container)); - doNothing().when(strategy2).waitUntilReady(eq(container)); - - underTest.waitUntilReady(container); - - InOrder inOrder = inOrder(strategy1, strategy2); - inOrder.verify(strategy1).waitUntilReady(any()); - inOrder.verify(strategy2).waitUntilReady(any()); - } + public void parentTimeoutApplies() { - @Test - public void maxTimeOutApplies() { + DummyStrategy child1 = new DummyStrategy(Duration.ofMillis(10)); + child1.withStartupTimeout(Duration.ofMillis(20)); - WaitStrategy child1 = new SleepingStrategy(Duration.ofMinutes(30)) - .withStartupTimeout(Duration.ofHours(1)); + assertEquals("withStartupTimeout directly sets the timeout", 20L, child1.startupTimeout.toMillis()); - final WaitStrategy underTest = new WaitAllStrategy() + new WaitAllStrategy() .withStrategy(child1) - .withStartupTimeout(Duration.ofMillis(10)); + .withStartupTimeout(Duration.ofMillis(30)); - assertThrows("The outer strategy timeout applies", TimeoutException.class, () -> { - underTest.waitUntilReady(container); - }); + assertEquals("WaitAllStrategy overrides a child's timeout", 30L, child1.startupTimeout.toMillis()); } @Test - public void appliesOuterTimeoutTooLittleTime() { + public void parentTimeoutAppliesToMultipleChildren() { Duration defaultInnerWait = Duration.ofMillis(2); Duration outerWait = Duration.ofMillis(6); - WaitStrategy child1 = new SleepingStrategy(defaultInnerWait); - WaitStrategy child2 = new SleepingStrategy(defaultInnerWait); + DummyStrategy child1 = new DummyStrategy(defaultInnerWait); + DummyStrategy child2 = new DummyStrategy(defaultInnerWait); - final WaitStrategy underTest = new WaitAllStrategy() + new WaitAllStrategy() .withStrategy(child1) .withStrategy(child2) .withStartupTimeout(outerWait); - assertThrows("The outer strategy timeout applies", TimeoutException.class, () -> { - underTest.waitUntilReady(container); - }); + assertEquals("WaitAllStrategy overrides a child's timeout (1st)", 6L, child1.startupTimeout.toMillis()); + assertEquals("WaitAllStrategy overrides a child's timeout (2nd)", 6L, child2.startupTimeout.toMillis()); } @Test - public void appliesOuterTimeoutEnoughTime() { + public void parentTimeoutAppliesToAdditionalChildren() { Duration defaultInnerWait = Duration.ofMillis(2); Duration outerWait = Duration.ofMillis(20); - WaitStrategy child1 = new SleepingStrategy(defaultInnerWait); - WaitStrategy child2 = new SleepingStrategy(defaultInnerWait); + DummyStrategy child1 = new DummyStrategy(defaultInnerWait); + DummyStrategy child2 = new DummyStrategy(defaultInnerWait); - final WaitStrategy underTest = new WaitAllStrategy() + new WaitAllStrategy() .withStrategy(child1) - .withStrategy(child2) - .withStartupTimeout(outerWait); + .withStartupTimeout(outerWait) + .withStrategy(child2); - try { - underTest.waitUntilReady(container); - } catch (Exception e) { - if (e.getCause() instanceof CaughtTimeoutException) - fail("The timeout wasn't applied to inner strategies."); - else { - fail(e.getMessage()); - } - } + assertEquals("WaitAllStrategy overrides a child's timeout (1st)", 20L, child1.startupTimeout.toMillis()); + assertEquals("WaitAllStrategy overrides a child's timeout (2nd, additional)", 20L, child2.startupTimeout.toMillis()); + } + + /* + * Mock-based tests to check overall behaviour, without involving timing-sensitive code + */ + @Test + public void childExecutionTest() { + + final WaitStrategy underTest = new WaitAllStrategy() + .withStrategy(strategy1) + .withStrategy(strategy2); + + doNothing().when(strategy1).waitUntilReady(eq(container)); + doNothing().when(strategy2).waitUntilReady(eq(container)); + + underTest.waitUntilReady(container); + + InOrder inOrder = inOrder(strategy1, strategy2); + inOrder.verify(strategy1).waitUntilReady(any()); + inOrder.verify(strategy2).waitUntilReady(any()); } @Test @@ -145,7 +139,7 @@ public void timeoutChangeShouldNotBePossibleWithIndividualTimeoutMode() { @Test public void shouldNotMessWithIndividualTimeouts() { - final WaitStrategy underTest = new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) + new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) .withStrategy(strategy1) .withStrategy(strategy2); @@ -157,7 +151,7 @@ public void shouldNotMessWithIndividualTimeouts() { public void shouldOverwriteIndividualTimeouts() { Duration someSeconds = Duration.ofSeconds(23); - final WaitStrategy underTest = new WaitAllStrategy() + new WaitAllStrategy() .withStartupTimeout(someSeconds) .withStrategy(strategy1) .withStrategy(strategy2); @@ -166,59 +160,14 @@ public void shouldOverwriteIndividualTimeouts() { verify(strategy1).withStartupTimeout(someSeconds); } - @Test - public void appliesOuterTimeoutOnAdditionalChildren() { - - Duration defaultInnerWait = Duration.ofMillis(2); - Duration outerWait = Duration.ofMillis(20); - - WaitStrategy child1 = new SleepingStrategy(defaultInnerWait); - WaitStrategy child2 = new SleepingStrategy(defaultInnerWait); - - final WaitStrategy underTest = new WaitAllStrategy() - .withStrategy(child1) - .withStartupTimeout(outerWait) - .withStrategy(child2); - - try { - underTest.waitUntilReady(container); - } catch (Exception e) { - if (e.getCause() instanceof CaughtTimeoutException) - fail("The timeout wasn't applied to inner strategies."); - else { - fail(e.getMessage()); - } - } - } - - static class CaughtTimeoutException extends RuntimeException { - - CaughtTimeoutException(String message) { - super(message); - } - } - - static class SleepingStrategy extends AbstractWaitStrategy { - - private final long sleepingDuration; - - SleepingStrategy(Duration defaultInnerWait) { + static class DummyStrategy extends AbstractWaitStrategy { + DummyStrategy(Duration defaultInnerWait) { super.startupTimeout = defaultInnerWait; - // Always oversleep by default - this.sleepingDuration = defaultInnerWait.multipliedBy(2).toMillis(); } @Override protected void waitUntilReady() { - try { - // Don't use ducttape, make sure we don't catch the wrong TimeoutException later on. - CompletableFuture.runAsync( - () -> Uninterruptibles.sleepUninterruptibly(this.sleepingDuration, TimeUnit.MILLISECONDS) - ).get((int) startupTimeout.toMillis(), TimeUnit.MILLISECONDS); - } catch (InterruptedException | ExecutionException e) { - } catch (java.util.concurrent.TimeoutException e) { - throw new CaughtTimeoutException("Inner wait timed out, outer strategy didn't apply."); - } + // no-op } } } From 978d374ceb38e6fa1ea677db27b4ac0e976463ce Mon Sep 17 00:00:00 2001 From: Gerasimov Gennady Date: Mon, 15 Apr 2019 13:17:06 +0300 Subject: [PATCH 0054/4969] #1389 Override close method without throws statement (#1392) --- core/src/main/java/org/testcontainers/containers/Network.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/Network.java b/core/src/main/java/org/testcontainers/containers/Network.java index b71a74a455c..411459b62eb 100644 --- a/core/src/main/java/org/testcontainers/containers/Network.java +++ b/core/src/main/java/org/testcontainers/containers/Network.java @@ -28,6 +28,9 @@ public void close() { String getId(); + @Override + void close(); + static Network newNetwork() { return builder().build(); } From ed0db162c445169431373989ff3bd0cf62f9f02f Mon Sep 17 00:00:00 2001 From: Jeremy Comte Date: Mon, 15 Apr 2019 13:29:29 +0200 Subject: [PATCH 0055/4969] Make StartupCheckStrategy timeout value configurable (#1308) in case of big docker images (Elasticsearch 6.6.0 is 808MB for example) the hardcoded 30s timeout makes a lot of our builds fail the first time they run. We fixed this locally, but it would be nice to have it as a parameter on the parent class. --- .../containers/startupcheck/StartupCheckStrategy.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java b/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java index f592411b4fb..1425123473b 100644 --- a/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java @@ -6,6 +6,7 @@ import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.rnorth.ducttape.unreliables.Unreliables; +import java.time.Duration; import java.util.concurrent.TimeUnit; import static org.testcontainers.containers.GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC; @@ -21,9 +22,17 @@ public abstract class StartupCheckStrategy { .withConstantThroughput() .build(); + private Duration timeout = Duration.ofSeconds(CONTAINER_RUNNING_TIMEOUT_SEC); + + @SuppressWarnings("unchecked") + public SELF withTimeout(Duration timeout) { + this.timeout = timeout; + return (SELF) this; + } + public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { final Boolean[] startedOK = {null}; - Unreliables.retryUntilTrue(CONTAINER_RUNNING_TIMEOUT_SEC, TimeUnit.SECONDS, () -> { + Unreliables.retryUntilTrue((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> { //noinspection CodeBlock2Expr return DOCKER_CLIENT_RATE_LIMITER.getWhenReady(() -> { StartupStatus state = checkStartupState(dockerClient, containerId); From 999d4f7d5ea56f05d132178ba9a989dcd9965a8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 15 Apr 2019 12:49:34 +0100 Subject: [PATCH 0056/4969] Bump tomcat-jdbc from 9.0.17 to 9.0.19 in /modules/mysql (#1401) Bumps tomcat-jdbc from 9.0.17 to 9.0.19. [![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=org.apache.tomcat:tomcat-jdbc&package-manager=gradle&previous-version=9.0.17&new-version=9.0.19)](https://dependabot.com/compatibility-score.html?dependency-name=org.apache.tomcat:tomcat-jdbc&package-manager=gradle&previous-version=9.0.17&new-version=9.0.19) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) If all status checks pass Dependabot will automatically merge this pull request. [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in the `.dependabot/config.yml` file in this repo: - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot.
--- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 0703b29ad3a..00217f4ff41 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.14' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.17' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.19' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From cc09697878dd11e21148972a54c8c287a99d2045 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 15 Apr 2019 12:49:58 +0100 Subject: [PATCH 0057/4969] Bump tomcat-jdbc from 9.0.17 to 9.0.19 in /modules/mariadb (#1403) Bumps tomcat-jdbc from 9.0.17 to 9.0.19. Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 1f679b7a592..84c5ce667d4 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.1' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.17' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.19' testCompile 'org.vibur:vibur-dbcp:22.2' } From 40724a0abbaa04b60e0231c7fa2616564f058430 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 15 Apr 2019 21:00:07 +0100 Subject: [PATCH 0058/4969] Fix #1391 by using a tagged version of `sshd` (#1407) Workaround for #1406 --- .../org/testcontainers/utility/TestcontainersConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 2d478b4cc0a..f87b02a17d3 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -55,7 +55,7 @@ public String getRyukImage() { } public String getSSHdImage() { - return (String) properties.getOrDefault("sshd.container.image", "quay.io/testcontainers/sshd@sha256:18aa929c653284189fc9cefa45b731021857b6047a0a1757e909f958f258f088"); + return (String) properties.getOrDefault("sshd.container.image", "quay.io/testcontainers/sshd:1.0.0"); } public Integer getRyukTimeout() { From 57a154b46ac3a2804341272ed06e89aebfce8f2e Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 16 Apr 2019 07:01:45 +0100 Subject: [PATCH 0059/4969] Update latest version in docs --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index fc37c0be80a..3bdf1466e47 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,4 +77,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.11.1 + latest_version: 1.11.2 From 2c3b36ad43f20a1e43015ac270b5318f2d45ca41 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 16 Apr 2019 07:34:17 +0100 Subject: [PATCH 0060/4969] Configure boomper probot (#1409) Configure [boomper](https://github.com/toolmantim/boomper) probot to keep latest version number in docs in sync with releases --- .github/boomper.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/boomper.yml diff --git a/.github/boomper.yml b/.github/boomper.yml new file mode 100644 index 00000000000..bb9bca7d29a --- /dev/null +++ b/.github/boomper.yml @@ -0,0 +1,3 @@ +updates: +- path: mkdocs.yml + pattern: 'latest_version: (.*)' From d9362fcbfdbf302fb41454132b65d54fc288c36a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 26 Apr 2019 09:28:40 +0200 Subject: [PATCH 0061/4969] Bump mysql-connector-java from 8.0.15 to 8.0.16 in /modules/spock (#1429) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.15 to 8.0.16. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.15...8.0.16) Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index d9c482b0c7b..6076788dbc4 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -14,5 +14,5 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testRuntime 'org.postgresql:postgresql:42.2.5' - testRuntime 'mysql:mysql-connector-java:8.0.15' + testRuntime 'mysql:mysql-connector-java:8.0.16' } From f604a2f9c97b3fb28dda109c7a9493150faceba2 Mon Sep 17 00:00:00 2001 From: Gerasimov Gennady Date: Sat, 27 Apr 2019 23:09:58 +0300 Subject: [PATCH 0062/4969] Support SELF typing for OracleContainer (#1425) * PR #1292 Added waitUntilContainerStarted and adjusted OracleContainer class declaration * PR #1292 Do not override waitUntilContainerStarted method. Changed class declaration according. --- .../java/org/testcontainers/containers/OracleContainer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index d7410373fd9..ea0eee1a2ff 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -7,7 +7,7 @@ /** * @author gusohal */ -public class OracleContainer extends JdbcDatabaseContainer { +public class OracleContainer extends JdbcDatabaseContainer { public static final String NAME = "oracle"; @@ -81,13 +81,13 @@ public String getPassword() { @Override public OracleContainer withUsername(String username) { this.username = username; - return this; + return self(); } @Override public OracleContainer withPassword(String password) { this.password = password; - return this; + return self(); } @SuppressWarnings("SameReturnValue") From c02ec79e9ad077bd03ec85f108e625531ac2ef40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 27 Apr 2019 21:37:34 +0100 Subject: [PATCH 0063/4969] Bump mysql-connector-java from 8.0.15 to 8.0.16 in /modules/junit-jupiter (#1428) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.15 to 8.0.16. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.15...8.0.16) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 36b0f217cb4..5d3ff61d46d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testRuntime 'org.postgresql:postgresql:42.2.5' - testRuntime 'mysql:mysql-connector-java:8.0.15' + testRuntime 'mysql:mysql-connector-java:8.0.16' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.2' } From 3d2a7ed936cf467fc07189753746fd0ea7bcf31e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 27 Apr 2019 21:37:56 +0100 Subject: [PATCH 0064/4969] Bump mysql-connector-java from 8.0.14 to 8.0.16 in /modules/mysql (#1427) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.14 to 8.0.16. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.14...8.0.16) Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 00217f4ff41..4bc4640b0fc 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { compile project(':jdbc') - testCompile 'mysql:mysql-connector-java:8.0.14' + testCompile 'mysql:mysql-connector-java:8.0.16' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.19' testCompile 'commons-dbutils:commons-dbutils:1.7' From a727b0bfb98472418bc251d76ddc532095427c1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 27 Apr 2019 21:38:37 +0100 Subject: [PATCH 0065/4969] Bump neo4j from 3.5.4 to 3.5.5 in /modules/neo4j (#1426) Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.4 to 3.5.5. - [Release notes](https://github.com/neo4j/neo4j/releases) - [Commits](https://github.com/neo4j/neo4j/commits) Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 9b0f3a48c3b..2a6f5ea1e1e 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -25,7 +25,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.4" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.5" compile project(":testcontainers") From e83136f53ea0835e462ed60b21a10e9aec0c5b89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 27 Apr 2019 21:38:51 +0100 Subject: [PATCH 0066/4969] Bump mockito-core from 2.26.0 to 2.27.0 in /core (#1382) Bumps [mockito-core](https://github.com/mockito/mockito) from 2.26.0 to 2.27.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v2.26.0...v2.27.0) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 1f08c0159b2..d9dee98ee6b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -104,7 +104,7 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.7.0' testCompile 'org.mongodb:mongo-java-driver:3.10.2' - testCompile ('org.mockito:mockito-core:2.26.0') { + testCompile ('org.mockito:mockito-core:2.27.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 7d299acd0087ba8f756d56c44e53aad1e3db3722 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 27 Apr 2019 21:39:15 +0100 Subject: [PATCH 0067/4969] Bump pulsar-client from 2.3.0 to 2.3.1 in /modules/pulsar (#1402) Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.3.0 to 2.3.1. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.3.0...v2.3.1) Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index a67c83cc923..c3505dedf65 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.1' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.2' } From ff9f0c443e8cb5c6bd37319cc5e5142549eb2355 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 27 Apr 2019 21:39:59 +0100 Subject: [PATCH 0068/4969] Bump junit-jupiter-api from 5.4.1 to 5.4.2 in /modules/junit-jupiter (#1365) Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.4.1 to 5.4.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.4.1...r5.4.2) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5d3ff61d46d..591347ca699 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.4.1' + compile 'org.junit.jupiter:junit-jupiter-api:5.4.2' testCompile project(':mysql') testCompile project(':postgresql') From ea2c25c4c407582f4a0553a3f46bbcfb36cbc929 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 1 May 2019 10:50:51 +0200 Subject: [PATCH 0069/4969] Bump org.springframework.boot in /examples (#1443) Bumps org.springframework.boot from 2.1.2.RELEASE to 2.1.4.RELEASE. Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 884657194cb..c978a96082d 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.2.RELEASE' + id 'org.springframework.boot' version '2.1.4.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 5a5ad6d893a..926d1cd8eb6 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.2.RELEASE' + id 'org.springframework.boot' version '2.1.4.RELEASE' } apply plugin: 'io.spring.dependency-management' From 51333a64b596260845c230e15ef038a367833cd2 Mon Sep 17 00:00:00 2001 From: mschnitzler Date: Tue, 7 May 2019 14:24:09 +0200 Subject: [PATCH 0070/4969] Add documentation for Bitbucket Pipelines (#1439) --- .../bitbucket_pipelines.md | 26 +++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 27 insertions(+) create mode 100644 docs/supported_docker_environment/continuous_integration/bitbucket_pipelines.md diff --git a/docs/supported_docker_environment/continuous_integration/bitbucket_pipelines.md b/docs/supported_docker_environment/continuous_integration/bitbucket_pipelines.md new file mode 100644 index 00000000000..0fd76448ffc --- /dev/null +++ b/docs/supported_docker_environment/continuous_integration/bitbucket_pipelines.md @@ -0,0 +1,26 @@ +# Bitbucket Pipelines + +To enable access to Docker in Bitbucket Pipelines, you need to add `docker` as a service on the step. + +Furthermore, Ryuk needs to be turned off since Bitbucket Pipelines does not allow starting privileged containers (see [Disabling Ryuk](../../features/configuration.md#disabling-ryuk)). This can either be done by setting a repository variable in Bitbucket's project settings or by explicitly exporting the variable on a step. + +In some cases the memory available to Docker needs to be increased. + +Here is a sample Bitbucket Pipeline configuration that does a checkout of a project and runs maven: + +```yml +image: maven:3.6.1 + +pipelines: + default: + - step: + script: + - export TESTCONTAINERS_RYUK_DISABLED=true + - mvn clean install + services: + - docker +definitions: + services: + docker: + memory: 2048 +``` diff --git a/mkdocs.yml b/mkdocs.yml index 3bdf1466e47..2238c7573a8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -70,6 +70,7 @@ nav: - supported_docker_environment/continuous_integration/dind_patterns.md - supported_docker_environment/continuous_integration/circle_ci.md - supported_docker_environment/continuous_integration/gitlab_ci.md + - supported_docker_environment/continuous_integration/bitbucket_pipelines.md - supported_docker_environment/windows.md - supported_docker_environment/logging_config.md - Getting help: getting_help.md From 55f10a704802b1fe8288d911d85ef272d44580e9 Mon Sep 17 00:00:00 2001 From: Enno <458526+ennru@users.noreply.github.com> Date: Tue, 14 May 2019 12:04:09 +0200 Subject: [PATCH 0071/4969] Add Lightbend to the Who is using list (#1464) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index dc038d374be..cbee344e637 100644 --- a/docs/index.md +++ b/docs/index.md @@ -70,6 +70,7 @@ You can also [check the latest version available on Maven Central](https://searc * [eBay Marketing](https://www.ebay.com) - Testing for MySQL, Cassandra, Redis, Couchbase, Kafka, etc. * [Skyscanner](https://www.skyscanner.net/) - Integration testing against HTTP service mocks and various data stores * [Neo4j-OGM](https://neo4j.com/developer/neo4j-ogm/) - Testing new, reactive client implementations +* [Lightbend](https://www.lightbend.com/) - Testing [Alpakka Kafka](https://doc.akka.io/docs/alpakka-kafka/current/) and support in [Alpakka Kafka Testkit](https://doc.akka.io/docs/alpakka-kafka/current/testing.html#testing-with-kafka-in-docker) ## License From 4947ec4a9b12daf3709cb9dc4d1447fe3be3caa9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 09:34:10 +0100 Subject: [PATCH 0072/4969] Bump cucumber-java from 4.3.0 to 4.3.1 in /examples (#1463) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v4.3.0...v4.3.1) Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index e9b052050d5..97d56deeb05 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.3.0' + implementation 'io.cucumber:cucumber-java:4.3.1' testImplementation 'io.cucumber:cucumber-junit:4.3.0' testImplementation 'org.testcontainers:selenium' } From e930b59a2ac28caa6a82890781a2487eea6e9beb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 09:34:26 +0100 Subject: [PATCH 0073/4969] Bump lombok from 1.18.6 to 1.18.8 in /examples (#1462) Bumps [lombok](https://github.com/rzwitserloot/lombok) from 1.18.6 to 1.18.8. - [Release notes](https://github.com/rzwitserloot/lombok/releases) - [Changelog](https://github.com/rzwitserloot/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/rzwitserloot/lombok/compare/v1.18.6...v1.18.8) Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 77b6022a968..78a38d2ba08 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.projectlombok:lombok:1.18.6' + compileOnly 'org.projectlombok:lombok:1.18.8' implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 926d1cd8eb6..ee2b0d032d6 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -9,7 +9,7 @@ repositories { } dependencies { - compileOnly 'org.projectlombok:lombok:1.18.6' + compileOnly 'org.projectlombok:lombok:1.18.8' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' From b7bbbfdf504f74e0c43b296ec4beb9e45e79ac97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 09:34:56 +0100 Subject: [PATCH 0074/4969] Bump rest-assured from 3.3.0 to 4.0.0 in /modules/vault (#1460) Bumps [rest-assured](https://github.com/jayway/rest-assured) from 3.3.0 to 4.0.0. - [Release notes](https://github.com/jayway/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/jayway/rest-assured/compare/rest-assured-3.3.0...rest-assured-4.0.0) Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index d5c791acd32..3dd346ab559 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Vault" dependencies { compile project(':testcontainers') - testCompile 'io.rest-assured:rest-assured:3.3.0' + testCompile 'io.rest-assured:rest-assured:4.0.0' } From 5acb599797d809d72836499140fe79214958cf99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 10:35:27 +0100 Subject: [PATCH 0075/4969] Bump neo4j-java-driver from 1.7.3 to 1.7.4 in /modules/neo4j (#1451) Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 1.7.3 to 1.7.4. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/1.7.3...1.7.4) Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 2a6f5ea1e1e..c467cc7381f 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -29,6 +29,6 @@ dependencies { compile project(":testcontainers") - testCompile "org.neo4j.driver:neo4j-java-driver:1.7.3" + testCompile "org.neo4j.driver:neo4j-java-driver:1.7.4" testCompile 'org.assertj:assertj-core:3.12.2' } From 2f1bce93926cc7827a3bb811167cfc4a7eade699 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 10:35:49 +0100 Subject: [PATCH 0076/4969] Bump tomcat-jdbc from 9.0.19 to 9.0.20 in /modules/mysql (#1468) Bumps tomcat-jdbc from 9.0.19 to 9.0.20. Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 4bc4640b0fc..e48c71734ae 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.16' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.19' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.20' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From 88014b3d46fd65c13ca366635f62fb6fb679cb0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 21:21:36 +0100 Subject: [PATCH 0077/4969] Bump cucumber-junit from 4.3.0 to 4.3.1 in /examples (#1461) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v4.3.0...v4.3.1) Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 97d56deeb05..bab77700eff 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.3.1' - testImplementation 'io.cucumber:cucumber-junit:4.3.0' + testImplementation 'io.cucumber:cucumber-junit:4.3.1' testImplementation 'org.testcontainers:selenium' } From 0a66f3cde6aaea232f9ece858caca2e89f5581fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 16 May 2019 09:05:39 +0200 Subject: [PATCH 0078/4969] Bump org.springframework.boot in /examples (#1471) Bumps org.springframework.boot from 2.1.4.RELEASE to 2.1.5.RELEASE. Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index c978a96082d..0aa55093dca 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.4.RELEASE' + id 'org.springframework.boot' version '2.1.5.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index ee2b0d032d6..f45b0e51c11 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.4.RELEASE' + id 'org.springframework.boot' version '2.1.5.RELEASE' } apply plugin: 'io.spring.dependency-management' From 03f8caa3a9dabc6dedd7caa4541a235b1f73a0a3 Mon Sep 17 00:00:00 2001 From: Stefan Ludwig Date: Thu, 16 May 2019 10:01:59 +0200 Subject: [PATCH 0079/4969] Add example for MongoDB containers (#1288) --- examples/mongodb-container/build.gradle | 12 +++++ .../containers/MongoDbContainer.java | 53 +++++++++++++++++++ .../containers/MongoDbContainerTest.java | 27 ++++++++++ examples/settings.gradle | 1 + 4 files changed, 93 insertions(+) create mode 100644 examples/mongodb-container/build.gradle create mode 100644 examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java create mode 100644 examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle new file mode 100644 index 00000000000..11c5f2bbe24 --- /dev/null +++ b/examples/mongodb-container/build.gradle @@ -0,0 +1,12 @@ +plugins { + id 'java' +} + +repositories { + jcenter() +} + +dependencies { + testImplementation 'org.testcontainers:testcontainers' + testImplementation 'junit:junit:4.12' +} diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java new file mode 100644 index 00000000000..00fd9c05b52 --- /dev/null +++ b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java @@ -0,0 +1,53 @@ +package org.testcontainers.containers; + +import org.jetbrains.annotations.NotNull; + + +/** + * This {@link Container} is based on the official MongoDb ({@code mongo}) image from + * DockerHub. If you need to use a custom MongoDB + * image, you can provide the full image name as well. + * + * @author Stefan Ludwig + */ +public class MongoDbContainer extends GenericContainer { + + /** + * This is the internal port on which MongoDB is running inside the container. + *

+ * You can use this constant in case you want to map an explicit public port to it + * instead of the default random port. This can be done using methods like + * {@link #setPortBindings(java.util.List)}. + */ + public static final int MONGODB_PORT = 27017; + public static final String DEFAULT_IMAGE_AND_TAG = "mongo:4.0"; + + /** + * Creates a new {@link MongoDbContainer} with the {@value DEFAULT_IMAGE_AND_TAG} image. + */ + public MongoDbContainer() { + this(DEFAULT_IMAGE_AND_TAG); + } + + /** + * Creates a new {@link MongoDbContainer} with the given {@code 'image'}. + * + * @param image the image (e.g. {@value DEFAULT_IMAGE_AND_TAG}) to use + */ + public MongoDbContainer(@NotNull String image) { + super(image); + addExposedPort(MONGODB_PORT); + } + + /** + * Returns the actual public port of the internal MongoDB port ({@value MONGODB_PORT}). + * + * @return the public port of this container + * @see #getMappedPort(int) + */ + @NotNull + public Integer getPort() { + return getMappedPort(MONGODB_PORT); + } + +} diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java new file mode 100644 index 00000000000..96096d51c1a --- /dev/null +++ b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java @@ -0,0 +1,27 @@ +package org.testcontainers.containers; + +import java.io.IOException; +import java.net.Socket; + +import org.junit.Test; + + +public class MongoDbContainerTest { + + @Test + public void containerStartsAndPublicPortIsAvailable() { + try (MongoDbContainer container = new MongoDbContainer()) { + container.start(); + assertThatPortIsAvailable(container); + } + } + + private void assertThatPortIsAvailable(MongoDbContainer container) { + try { + new Socket(container.getContainerIpAddress(), container.getPort()); + } catch (IOException e) { + throw new AssertionError("The expected port " + container.getPort() + " is not available!"); + } + } + +} diff --git a/examples/settings.gradle b/examples/settings.gradle index 671646b76d6..06252afa580 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -5,6 +5,7 @@ includeBuild '..' // explicit include to allow Dependabot to autodiscover subprojects include 'disque-job-queue' include 'linked-container' +include 'mongodb-container' include 'redis-backed-cache' include 'redis-backed-cache-testng' include 'selenium-container' From e4ce8f578d09a29c3dbddc9be47a92ee6f06d9cd Mon Sep 17 00:00:00 2001 From: Patrick Pfeiler Date: Sat, 18 May 2019 23:07:47 +0200 Subject: [PATCH 0080/4969] Fix ScriptUtils splitting with Windows EOF (#1467, #1465) --- .../org/testcontainers/ext/ScriptUtils.java | 2 +- .../org/testcontainers/ext/ScriptUtilsTest.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java index f27b3610f15..eb041708fb6 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java @@ -206,7 +206,7 @@ else if (script.startsWith(blockCommentStartDelimiter, i)) { blockCommentEndDelimiter), resource); } } - else if (c == ' ' || c == '\n' || c == '\t') { + else if (c == ' ' || c == '\n' || c == '\t' || c == '\r') { // avoid multiple adjacent whitespace characters if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') { c = ' '; diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java index 7a50026cd93..c9b1218321b 100644 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java @@ -28,4 +28,21 @@ public void testSplit() throws IOException { assertEquals("SELECT * from `bar`", statements.get(4)); assertEquals("INSERT INTO bar (foo) VALUES ('hello world')", statements.get(6)); } + + /* + * Test ScriptUtils script splitting with some ugly/hard-to-split cases and linux line endings + */ + @Test + public void testSplitWithWidnwosLineEnding() throws IOException { + final String script = Resources.toString(Resources.getResource("splittable.sql"), Charsets.UTF_8); + final String scriptWithWindowsLineEndings = script.replaceAll("\n", "\r\n"); + final List statements = new ArrayList<>(); + ScriptUtils.splitSqlScript("resourcename", scriptWithWindowsLineEndings, ";", "--", "/*", "*/", statements); + + assertEquals(7, statements.size()); + assertEquals("SELECT \"a /* string literal containing comment characters like -- here\"", statements.get(2)); + assertEquals("SELECT \"a 'quoting' \\\"scenario ` involving BEGIN keyword\\\" here\"", statements.get(3)); + assertEquals("SELECT * from `bar`", statements.get(4)); + assertEquals("INSERT INTO bar (foo) VALUES ('hello world')", statements.get(6)); + } } From 2dffb2648e2d9fbfcb7892e60cf6dbe8f1151d46 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 21 May 2019 17:00:23 +0900 Subject: [PATCH 0081/4969] Fix NB in the "Database containers" docs (#1484) --- docs/modules/databases/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index aaef47a44ef..c7253cdddd7 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -43,6 +43,7 @@ Examples/Tests: As long as you have Testcontainers and the appropriate JDBC driver on your classpath, you can simply modify regular JDBC connection URLs to get a fresh containerized instance of the database each time your application starts up. _N.B:_ + * _TC needs to be on your application's classpath at runtime for this to work_ * _For Spring Boot you need to specify the driver manually `spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver`_ From 24e6f1154f371ebe1623e9621726ce2d019b23d5 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 21 May 2019 17:53:44 +0200 Subject: [PATCH 0082/4969] Redirect Docker-Compose stderr to INFO logger (#1485) Docker-Compose logs pull information to stderr, but we don't want those logs in our ERROR logger. --- .../org/testcontainers/containers/DockerComposeContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 0b6db19ca28..67674796cdd 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -638,7 +638,7 @@ public void invoke() { try { new ProcessExecutor().command(command) .redirectOutput(Slf4jStream.of(logger()).asInfo()) - .redirectError(Slf4jStream.of(logger()).asError()) + .redirectError(Slf4jStream.of(logger()).asInfo()) // docker-compose will log pull information to stderr .environment(environment) .directory(pwd) .exitValueNormal() From b75f52c2412b39cc166358622d1fe4c330c26812 Mon Sep 17 00:00:00 2001 From: Anand Date: Tue, 21 May 2019 21:10:09 +0100 Subject: [PATCH 0083/4969] Adding field name to ExtensionConfigurationException message (#1488) --- CONTRIBUTING.md | 8 ++++++-- .../junit/jupiter/TestcontainersExtension.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cd3822df3a2..2914c874e1a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,5 +8,9 @@ * discuss with the authors on an issue ticket prior to doing anything big * follow the style, naming and structure conventions of the rest of the project * make commits atomic and easy to merge - * verify all tests are passing. Build the project with `./gradlew check` to do this. - **N.B.** Gradle's Build Cache is enabled by default, but you can add `--no-build-cache` flag to disable it. \ No newline at end of file + * verify all tests are passing. Build the project with `./gradlew check` to do this + + **PS:** Make sure Docker is running locally and you have the lombok plugin installed in your IDE + + **N.B.** Gradle's Build Cache is enabled by default, but you can add `--no-build-cache` flag to disable it. + diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java index 7c5f8b205ef..7f6183cc74d 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java @@ -95,7 +95,7 @@ private static Predicate isContainer() { boolean isStartable = Startable.class.isAssignableFrom(field.getType()); if (!isStartable) { - throw new ExtensionConfigurationException("Annotation is only supported for Startable types"); + throw new ExtensionConfigurationException(String.format("FieldName: %s does not implement Startable", field.getName())); } return true; } From 581b80b184e2d0a0f65e4f12f8493565adb2f60a Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 27 May 2019 20:55:43 +0100 Subject: [PATCH 0084/4969] Support MySQL 8 (#1470) Amend default MySQL connection parameters for MySQL 5 - 8 compatibility Fixes #736 --- modules/jdbc-test/build.gradle | 2 +- .../testcontainers/jdbc/JDBCDriverTest.java | 4 +- .../junit/AbstractContainerDatabaseTest.java | 32 +++++++++++ .../junit/MultiVersionMySQLTest.java | 37 ++++++++++++ .../junit/SimpleClickhouseTest.java | 15 +---- .../junit/SimpleMSSQLServerTest.java | 23 ++------ .../junit/SimpleMariaDBTest.java | 25 +------- .../testcontainers/junit/SimpleMySQLTest.java | 57 +++---------------- .../junit/SimpleOracleTest.java | 16 +----- .../junit/SimplePostgreSQLTest.java | 20 +------ .../containers/MySQLContainer.java | 10 +++- 11 files changed, 99 insertions(+), 142 deletions(-) create mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java create mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/MultiVersionMySQLTest.java diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index e631d2fa1a3..4c7ab8b0974 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { testCompile 'com.google.guava:guava:18.0' testCompile 'org.postgresql:postgresql:42.0.0' - testCompile 'mysql:mysql-connector-java:5.1.45' + testCompile 'mysql:mysql-connector-java:8.0.14' testCompile 'org.mariadb.jdbc:mariadb-java-client:1.4.6' testCompile 'com.oracle:ojdbc6:12.1.0.1-atlassian-hosted' testCompile 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8' diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index 4eb55b38e24..40cb707a2d0 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -198,8 +198,8 @@ private HikariDataSource verifyCharacterSet(String jdbcUrl) throws SQLException HikariDataSource dataSource = getDataSource(jdbcUrl, 1); boolean result = new QueryRunner(dataSource).query("SHOW VARIABLES LIKE 'character\\_set\\_connection'", rs -> { rs.next(); - String resultSetInt = rs.getString(2); - assertEquals("Passing query parameters to set DB connection encoding is successful", "utf8", resultSetInt); + String resultSetString = rs.getString(2); + assertTrue("Passing query parameters to set DB connection encoding is successful", resultSetString.startsWith("utf8")); return true; }); diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java new file mode 100644 index 00000000000..a01146fe7a3 --- /dev/null +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java @@ -0,0 +1,32 @@ +package org.testcontainers.junit; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.testcontainers.containers.JdbcDatabaseContainer; + +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +abstract class AbstractContainerDatabaseTest { + + ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLException { + DataSource ds = getDataSource(container); + Statement statement = ds.getConnection().createStatement(); + statement.execute(sql); + ResultSet resultSet = statement.getResultSet(); + + resultSet.next(); + return resultSet; + } + + DataSource getDataSource(JdbcDatabaseContainer container) { + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setJdbcUrl(container.getJdbcUrl()); + hikariConfig.setUsername(container.getUsername()); + hikariConfig.setPassword(container.getPassword()); + + return new HikariDataSource(hikariConfig); + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/MultiVersionMySQLTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/MultiVersionMySQLTest.java new file mode 100644 index 00000000000..b685d6dad80 --- /dev/null +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/MultiVersionMySQLTest.java @@ -0,0 +1,37 @@ +package org.testcontainers.junit; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.containers.MySQLContainer; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +@RunWith(Parameterized.class) +public class MultiVersionMySQLTest extends AbstractContainerDatabaseTest { + + @Parameterized.Parameters(name = "{0}") + public static String[] params() { + return new String[]{"5.5.62", "5.6.42", "5.7.26", "8.0.16"}; + } + + private final String version; + + public MultiVersionMySQLTest(String version) { + this.version = version; + } + + @Test + public void versionCheckTest() throws SQLException { + try (final MySQLContainer container = new MySQLContainer<>("mysql:" + version)) { + container.start(); + final ResultSet resultSet = performQuery(container, "SELECT VERSION()"); + final String resultSetString = resultSet.getString(1); + + assertEquals("The database version can be set using a container rule parameter", version, resultSetString); + } + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java index 4e123617b8d..b765208e212 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java @@ -1,33 +1,22 @@ package org.testcontainers.junit; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.ClickHouseContainer; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -public class SimpleClickhouseTest { +public class SimpleClickhouseTest extends AbstractContainerDatabaseTest { @Rule public ClickHouseContainer clickhouse = new ClickHouseContainer(); @Test public void testSimple() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(clickhouse.getJdbcUrl()); - hikariConfig.setUsername(clickhouse.getUsername()); - hikariConfig.setPassword(clickhouse.getPassword()); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT 1"); - ResultSet resultSet = statement.getResultSet(); + ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); resultSet.next(); int resultSetInt = resultSet.getInt(1); diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java index 93904cfb94a..2791efa0780 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java @@ -1,11 +1,10 @@ package org.testcontainers.junit; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.MSSQLServerContainer; +import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -15,36 +14,22 @@ /** * @author Stefan Hufschmidt */ -public class SimpleMSSQLServerTest { +public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { @Rule public MSSQLServerContainer mssqlServer = new MSSQLServerContainer(); @Test public void testSimple() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(mssqlServer.getJdbcUrl()); - hikariConfig.setUsername(mssqlServer.getUsername()); - hikariConfig.setPassword(mssqlServer.getPassword()); + ResultSet resultSet = performQuery(mssqlServer, "SELECT 1"); - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT 1"); - ResultSet resultSet = statement.getResultSet(); - - resultSet.next(); int resultSetInt = resultSet.getInt(1); assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } @Test public void testSetupDatabase() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(mssqlServer.getJdbcUrl()); - hikariConfig.setUsername(mssqlServer.getUsername()); - hikariConfig.setPassword(mssqlServer.getPassword()); - - HikariDataSource ds = new HikariDataSource(hikariConfig); + DataSource ds = getDataSource(mssqlServer); Statement statement = ds.getConnection().createStatement(); statement.executeUpdate("CREATE DATABASE [test];"); statement = ds.getConnection().createStatement(); diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMariaDBTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMariaDBTest.java index 042582ed890..21badefb9fb 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMariaDBTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMariaDBTest.java @@ -1,26 +1,21 @@ package org.testcontainers.junit; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import lombok.NonNull; - import org.apache.commons.lang.SystemUtils; import org.junit.Test; import org.testcontainers.containers.MariaDBContainer; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; +import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.junit.Assume.assumeFalse; /** * @author Miguel Gonzalez Sanchez */ -public class SimpleMariaDBTest { +public class SimpleMariaDBTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { @@ -85,20 +80,4 @@ public void testMariaDBWithCommandOverride() throws SQLException { mariadbCustomConfig.stop(); } } - - @NonNull - protected ResultSet performQuery(MariaDBContainer containerRule, String sql) throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(containerRule.getJdbcUrl()); - hikariConfig.setUsername(containerRule.getUsername()); - hikariConfig.setPassword(containerRule.getPassword()); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute(sql); - ResultSet resultSet = statement.getResultSet(); - - resultSet.next(); - return resultSet; - } } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java index 5c8e4133a22..9570659c4dc 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java @@ -1,17 +1,5 @@ package org.testcontainers.junit; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; - import org.apache.commons.lang.SystemUtils; import org.junit.Test; import org.slf4j.Logger; @@ -20,13 +8,19 @@ import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.output.Slf4jLogConsumer; -import lombok.NonNull; +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** * @author richardnorth */ -public class SimpleMySQLTest { +public class SimpleMySQLTest extends AbstractContainerDatabaseTest { private static final Logger logger = LoggerFactory.getLogger(SimpleMySQLTest.class); @@ -114,24 +108,6 @@ public void testCommandOverride() throws SQLException { } - @Test - public void testMySQL8() throws SQLException { - assumeFalse(SystemUtils.IS_OS_WINDOWS); - MySQLContainer container = new MySQLContainer<>("mysql:8.0.11") - .withCommand("mysqld --default-authentication-plugin=mysql_native_password"); - container.start(); - - try { - ResultSet resultSet = performQuery(container, "SELECT VERSION()"); - String resultSetString = resultSet.getString(1); - - assertTrue("The database version can be set using a container rule parameter", "8.0.11".equals(resultSetString)); - } - finally { - container.stop(); - } - } - @Test public void testExplicitInitScript() throws SQLException { try (MySQLContainer container = (MySQLContainer) new MySQLContainer() @@ -160,21 +136,4 @@ public void testEmptyPasswordWithNonRootUser() { container.stop(); } } - - @NonNull - protected ResultSet performQuery(MySQLContainer containerRule, String sql) throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setDriverClassName(containerRule.getDriverClassName()); - hikariConfig.setJdbcUrl(containerRule.getJdbcUrl()); - hikariConfig.setUsername(containerRule.getUsername()); - hikariConfig.setPassword(containerRule.getPassword()); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute(sql); - ResultSet resultSet = statement.getResultSet(); - - resultSet.next(); - return resultSet; - } } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleOracleTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleOracleTest.java index 2fedcaf08e1..0855fd4860e 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleOracleTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleOracleTest.java @@ -1,7 +1,5 @@ package org.testcontainers.junit; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -9,7 +7,6 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; @@ -17,25 +14,18 @@ * @author gusohal */ @Ignore -public class SimpleOracleTest { +public class SimpleOracleTest extends AbstractContainerDatabaseTest { @Rule public OracleContainer oracle = new OracleContainer(); @Test public void testSimple() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(oracle.getJdbcUrl()); - hikariConfig.setUsername(oracle.getUsername()); - hikariConfig.setPassword(oracle.getPassword()); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT 1 FROM dual"); - ResultSet resultSet = statement.getResultSet(); + ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual"); resultSet.next(); int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java index 2581240cd84..c6685343c29 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java @@ -1,21 +1,17 @@ package org.testcontainers.junit; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; import org.junit.Test; -import org.testcontainers.containers.JdbcDatabaseContainer; import org.testcontainers.containers.PostgreSQLContainer; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; /** * @author richardnorth */ -public class SimplePostgreSQLTest { +public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { @@ -41,18 +37,4 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } } - - private ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(container.getJdbcUrl()); - hikariConfig.setUsername(container.getUsername()); - hikariConfig.setPassword(container.getPassword()); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute(sql); - ResultSet resultSet = statement.getResultSet(); - resultSet.next(); - return resultSet; - } } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 6d9139fa971..172ead4856a 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -70,10 +70,14 @@ protected String constructUrlForConnection(String queryString) { if (! url.contains("useSSL=")) { String separator = url.contains("?") ? "&" : "?"; - return url + separator + "useSSL=false"; - } else { - return url; + url = url + separator + "useSSL=false"; + } + + if (! url.contains("allowPublicKeyRetrieval=")) { + url = url + "&allowPublicKeyRetrieval=true"; } + + return url; } @Override From 9fd199d39183798c046ae0f8de2d8340cc5f8584 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 28 May 2019 06:20:12 +0900 Subject: [PATCH 0085/4969] Fix initscript typo in documentation (#1491) --- docs/modules/databases/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index c7253cdddd7..71d65af7e20 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -67,7 +67,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database ## Using a classpath init script -Testcontainers can run an initscript after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: +Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: `jdbc:tc:mysql:5.7.22://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql` From b0b3f9a1205037906838f6643594f27a79c8a734 Mon Sep 17 00:00:00 2001 From: Frederik Hahne Date: Mon, 27 May 2019 23:30:08 +0200 Subject: [PATCH 0086/4969] Fix docker registry auth parsing of GCR json key format credentials (#1492) closes #1466 --- .../utility/RegistryAuthLocator.java | 2 +- .../utility/RegistryAuthLocatorTest.java | 14 ++++++++++++-- .../auth-config/config-with-json-key.json | 7 +++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 core/src/test/resources/auth-config/config-with-json-key.json diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index 402a15d58b4..a1be23eb82e 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -154,7 +154,7 @@ private AuthConfig findExistingAuthConfig(final JsonNode config, final String re !isBlank(deserializedAuth.getAuth())) { final String rawAuth = new String(Base64.getDecoder().decode(deserializedAuth.getAuth())); - final String[] splitRawAuth = rawAuth.split(":"); + final String[] splitRawAuth = rawAuth.split(":", 2); if (splitRawAuth.length == 2) { deserializedAuth.withUsername(splitRawAuth[0]); diff --git a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java index 938505c0212..fe930cf78b7 100644 --- a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java +++ b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java @@ -11,8 +11,7 @@ import java.util.HashMap; import java.util.Map; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNull; +import static org.rnorth.visibleassertions.VisibleAssertions.*; public class RegistryAuthLocatorTest { @Test @@ -37,6 +36,17 @@ public void lookupAuthConfigWithBasicAuthCredentials() throws URISyntaxException assertEquals("Password is set", "pass", authConfig.getPassword()); } + @Test + public void lookupAuthConfigWithJsonKeyCredentials() throws URISyntaxException { + final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-json-key.json"); + + final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registry.example.com/org/repo"), new AuthConfig()); + + assertEquals("Default docker registry URL is set on auth config", "https://registry.example.com", authConfig.getRegistryAddress()); + assertEquals("Username is set", "_json_key", authConfig.getUsername()); + assertNotNull("Password is set", authConfig.getPassword()); + } + @Test public void lookupAuthConfigUsingStore() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-store.json"); diff --git a/core/src/test/resources/auth-config/config-with-json-key.json b/core/src/test/resources/auth-config/config-with-json-key.json new file mode 100644 index 00000000000..3584963d645 --- /dev/null +++ b/core/src/test/resources/auth-config/config-with-json-key.json @@ -0,0 +1,7 @@ +{ + "auths": { + "https://registry.example.com": { + "auth": "X2pzb25fa2V5OnsKInR5cGUiOiAic2VydmljZV9hY2NvdW50IiwKInByb2plY3RfaWQiOiAiZXhhbXBsZS1wcm9qZWN0IiwKInByaXZhdGVfa2V5X2lkIjogImV4YW1wbGUta2V5LWlkIiwKInByaXZhdGVfa2V5IjogImV4YW1wbGUtcHJpdmF0ZS1rZXkiLAoiY2xpZW50X2VtYWlsIjogInVzZXJAZXhhbXBsZS5jb20iLAoiY2xpZW50X2lkIjogInVzZXJAZXhhbXBsZS5jb20iLAoiYXV0aF91cmkiOiAiaHR0cHM6Ly9yZWdpc3RyeS5leGFtcGxlLmNvbS9vL29hdXRoMi9hdXRoIiwKInRva2VuX3VyaSI6ICJodHRwczovL3JlZ2lzdHJ5LmV4YW1wbGUuY29tL3Rva2VuIiwKImF1dGhfcHJvdmlkZXJfeDUwOV9jZXJ0X3VybCI6ICJodHRwczovL3JlZ2lzdHJ5LmV4YW1wbGUuY29tIiwKImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHBzOi8vcmVnaXN0cnkuZXhhbXBsZS5jb20iCn0=" + } + } +} From d54e119eaf31ec13a3d2bcfbf6d44f7e46c604e8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Mon, 27 May 2019 22:31:18 +0100 Subject: [PATCH 0087/4969] Bump neo4j-java-driver from 1.7.4 to 1.7.5 in /modules/neo4j (#1477) Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 1.7.4 to 1.7.5. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/1.7.4...1.7.5) Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index c467cc7381f..cc0e246396f 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -29,6 +29,6 @@ dependencies { compile project(":testcontainers") - testCompile "org.neo4j.driver:neo4j-java-driver:1.7.4" + testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" testCompile 'org.assertj:assertj-core:3.12.2' } From 6feb6c9e0fc5c4e5ef2ff94e538ee173b5eca2e0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Mon, 27 May 2019 22:32:02 +0100 Subject: [PATCH 0088/4969] Bump java-client from 2.7.4 to 2.7.6 in /modules/couchbase (#1493) Bumps [java-client](https://github.com/couchbase/couchbase-java-client) from 2.7.4 to 2.7.6. - [Release notes](https://github.com/couchbase/couchbase-java-client/releases) - [Commits](https://github.com/couchbase/couchbase-java-client/compare/2.7.4...2.7.6) Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 2bf1055038b..8cf0f879215 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,5 +2,5 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.4' + compile 'com.couchbase.client:java-client:2.7.6' } From e5de96aa39bee8e774f46912cd47eb115204c38c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 28 May 2019 09:03:23 +0100 Subject: [PATCH 0089/4969] Bump neo4j from 3.5.5 to 3.5.6 in /modules/neo4j (#1498) Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.5 to 3.5.6. - [Release notes](https://github.com/neo4j/neo4j/releases) - [Commits](https://github.com/neo4j/neo4j/compare/3.5.5...3.5.6) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index cc0e246396f..68a52d115cd 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -25,7 +25,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.5" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.6" compile project(":testcontainers") From 31f33aa96a7345e1e5eb22fc54f4422a4cfa2475 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 28 May 2019 09:03:34 +0100 Subject: [PATCH 0090/4969] Bump jna-platform from 5.2.0 to 5.3.1 in /core (#1437) Bumps [jna-platform](https://github.com/java-native-access/jna) from 5.2.0 to 5.3.1. - [Release notes](https://github.com/java-native-access/jna/releases) - [Changelog](https://github.com/java-native-access/jna/blob/master/CHANGES.md) - [Commits](https://github.com/java-native-access/jna/compare/5.2.0...5.3.1) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d9dee98ee6b..9786e51a774 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -73,7 +73,7 @@ dependencies { exclude(group: "log4j", module: "log4j") } - compile "net.java.dev.jna:jna-platform:5.2.0" + compile "net.java.dev.jna:jna-platform:5.3.1" shaded ('org.scala-sbt.ipcsocket:ipcsocket:1.0.0') { exclude(group: "net.java.dev.jna") From 1b3a3bd45211ad2b4a5c1b24d89cd1e092d64647 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 28 May 2019 09:03:59 +0100 Subject: [PATCH 0091/4969] Bump amqp-client from 5.7.0 to 5.7.1 in /core (#1501) Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.7.0 to 5.7.1. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.7.0...v5.7.1) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9786e51a774..853d3a199b9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -102,7 +102,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.8' testCompile 'redis.clients:jedis:3.0.1' - testCompile 'com.rabbitmq:amqp-client:5.7.0' + testCompile 'com.rabbitmq:amqp-client:5.7.1' testCompile 'org.mongodb:mongo-java-driver:3.10.2' testCompile ('org.mockito:mockito-core:2.27.0') { exclude(module: 'hamcrest-core') From 6f6942ef68236eb57a792a6b387c9efdb2fa7396 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 28 May 2019 09:04:21 +0100 Subject: [PATCH 0092/4969] Bump tomcat-jdbc from 9.0.19 to 9.0.20 in /modules/mariadb (#1469) Bumps tomcat-jdbc from 9.0.19 to 9.0.20. Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 84c5ce667d4..371ec52641d 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.1' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.19' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.20' testCompile 'org.vibur:vibur-dbcp:22.2' } From 4325c2ad7da78a3057710a2af0950bc80140af57 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 28 May 2019 17:07:54 +0900 Subject: [PATCH 0093/4969] Fix typo in docs (describe use of stop() method rather than close()) (#1479) --- docs/test_framework_integration/junit_4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test_framework_integration/junit_4.md b/docs/test_framework_integration/junit_4.md index f2f46636442..8ab753e611f 100644 --- a/docs/test_framework_integration/junit_4.md +++ b/docs/test_framework_integration/junit_4.md @@ -18,7 +18,7 @@ public class SimpleMySQLTest { ## Manually controlling container lifecycle -As an alternative, you can manually start the container in a `@BeforeClass`/`@Before` annotated method in your tests. Tear down will be done automatically on JVM exit, but you can of course also use an `@AfterClass`/`@After` annotated method to manually call the `close()` method on your container. +As an alternative, you can manually start the container in a `@BeforeClass`/`@Before` annotated method in your tests. Tear down will be done automatically on JVM exit, but you can of course also use an `@AfterClass`/`@After` annotated method to manually call the `stop()` method on your container. *Example of starting a container in a `@Before` annotated method:* From 83a7accfebae7671294bd0193caba7c5fff4563a Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 28 May 2019 13:02:12 +0100 Subject: [PATCH 0094/4969] Remove internet connectivity dependency from test (#1502) * Remove internet connectivity dependency from test * Add test timeout * Remove redundant throw --- .../org/testcontainers/junit/OutputStreamTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java index a14e1e32237..83ba05be86e 100644 --- a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java +++ b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java @@ -24,11 +24,11 @@ public class OutputStreamTest { @Rule public GenericContainer container = new GenericContainer("alpine:3.2") - .withCommand("ping -c 5 www.google.com"); + .withCommand("ping -c 5 127.0.0.1"); private static final Logger LOGGER = LoggerFactory.getLogger(OutputStreamTest.class); - @Test + @Test(timeout = 60_000L) public void testFetchStdout() throws TimeoutException { WaitingConsumer consumer = new WaitingConsumer(); @@ -39,8 +39,8 @@ public void testFetchStdout() throws TimeoutException { 30, TimeUnit.SECONDS); } - @Test - public void testFetchStdoutWithTimeout() throws TimeoutException { + @Test(timeout = 60_000L) + public void testFetchStdoutWithTimeout() { WaitingConsumer consumer = new WaitingConsumer(); @@ -53,7 +53,7 @@ public void testFetchStdoutWithTimeout() throws TimeoutException { }); } - @Test + @Test(timeout = 60_000L) public void testFetchStdoutWithNoLimit() throws TimeoutException { WaitingConsumer consumer = new WaitingConsumer(); @@ -63,7 +63,7 @@ public void testFetchStdoutWithNoLimit() throws TimeoutException { consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("seq=2")); } - @Test + @Test(timeout = 60_000L) public void testLogConsumer() throws TimeoutException { WaitingConsumer waitingConsumer = new WaitingConsumer(); @@ -75,7 +75,7 @@ public void testLogConsumer() throws TimeoutException { waitingConsumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("seq=2")); } - @Test + @Test(timeout = 60_000L) public void testToStringConsumer() throws TimeoutException { WaitingConsumer waitingConsumer = new WaitingConsumer(); From 3b0a7e652b5913cae2e560c748ba75e2535e9ca3 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Wed, 29 May 2019 04:38:54 +0900 Subject: [PATCH 0095/4969] Replace deprecated RestClient.performRequest() (#1494) --- docs/modules/elasticsearch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index 3f683e570f9..02eeb61dfbe 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -22,7 +22,7 @@ credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredential RestClient restClient = RestClient.builder(HttpHost.create(container.getHttpHostAddress())) .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)) .build(); -Response response = restClient.performRequest("GET", "/"); +Response response = restClient.performRequest(new Request("GET", "/")); // ... or the transport client TransportAddress transportAddress = new TransportAddress(container.getTcpHost()); From 833f4170fb862ab5b0976926986ec9508bd55798 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 29 May 2019 16:25:45 +0100 Subject: [PATCH 0096/4969] Rename boomper bot configuration file to match correct name --- .github/{boomper.yml => bumper.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{boomper.yml => bumper.yml} (100%) diff --git a/.github/boomper.yml b/.github/bumper.yml similarity index 100% rename from .github/boomper.yml rename to .github/bumper.yml From 94a14f0bbb8f4b57a19f6ff69aa0298d81a8132c Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 29 May 2019 16:27:16 +0100 Subject: [PATCH 0097/4969] Fix latest version (manual, due to misconfigured boomper bot) --- mkdocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 2238c7573a8..9539df4fad8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: Testcontainers +'site_name: Testcontainers plugins: - search - codeinclude @@ -78,4 +78,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.11.2 + latest_version: 1.11.3 From 261982768ceecd9aec26dff9457c8ec7953d791b Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 29 May 2019 17:16:45 +0100 Subject: [PATCH 0098/4969] Fix broken mkdocs.yml --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 9539df4fad8..762116a062c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -'site_name: Testcontainers +site_name: Testcontainers plugins: - search - codeinclude From 16ed2379ff6e8622adddfd271032a28477cdcd0c Mon Sep 17 00:00:00 2001 From: Stuart Davidson Date: Thu, 30 May 2019 13:54:19 +0100 Subject: [PATCH 0099/4969] Remove broken link to roadmap (#1511) The docs/ROADMAP.md link doesn't work and I don't see a replacement, so either remove the link or update it. --- CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2914c874e1a..9a9f1e43b55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,6 @@ * Star the project on [Github](https://github.com/testcontainers/testcontainers-java) and help spread the word :) * Join our Slack: http://slack.testcontainers.org -* See [ROADMAP](docs/ROADMAP.md) to understand the approach behind the project and what may/may not be in store for the future. * [Post an issue](https://github.com/testcontainers/testcontainers-java/issues) if you find any bugs * Contribute improvements or fixes using a [Pull Request](https://github.com/testcontainers/testcontainers-java/pulls). If you're going to contribute, thank you! Please just be sure to: * discuss with the authors on an issue ticket prior to doing anything big From 5c5bfe83308791c578351e99bff13c9b3eaeede4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Thu, 30 May 2019 13:55:02 +0100 Subject: [PATCH 0100/4969] Bump mockito-core from 2.27.0 to 2.28.2 in /core (#1512) Bumps [mockito-core](https://github.com/mockito/mockito) from 2.27.0 to 2.28.2. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v2.27.0...v2.28.2) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 853d3a199b9..a0c35863328 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -104,7 +104,7 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.7.1' testCompile 'org.mongodb:mongo-java-driver:3.10.2' - testCompile ('org.mockito:mockito-core:2.27.0') { + testCompile ('org.mockito:mockito-core:2.28.2') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 1e49e7dcaaaa54ce6e5c27b18aed63a5ed3545b0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Fri, 31 May 2019 01:31:23 +0000 Subject: [PATCH 0101/4969] Bump okhttp from 3.12.1 to 3.14.2 in /core (#1475) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index a0c35863328..a77720d66df 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -92,7 +92,7 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded 'com.squareup.okhttp3:okhttp:3.12.1' + shaded 'com.squareup.okhttp3:okhttp:3.14.2' shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From 3a9a7a2ac36b0a0fe808c032300906fe45c2381e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Fri, 31 May 2019 02:08:45 +0000 Subject: [PATCH 0102/4969] Bump okhttp from 3.13.1 to 3.14.2 in /examples (#1478) --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 565ed7c5353..8522878f5ec 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.26' - implementation 'com.squareup.okhttp3:okhttp:3.13.1' + implementation 'com.squareup.okhttp3:okhttp:3.14.2' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.5' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From bded5611667a0a9c6b779927643db9fea8405d79 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Fri, 31 May 2019 07:58:29 +0000 Subject: [PATCH 0103/4969] Bump pulsar-client from 2.3.1 to 2.3.2 in /modules/pulsar (#1517) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index c3505dedf65..301d6f81da2 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.2' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.2' } From 481ff4873f6a80138c9ce84bf5eb1a87749f1e8d Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 31 May 2019 12:03:42 +0100 Subject: [PATCH 0104/4969] Disable dependabot automerge for core module (#1518) Disabling for core only, due to higher risk of accidental changes if automerge is used for this library --- .dependabot/config.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.dependabot/config.yml b/.dependabot/config.yml index 7acddda566c..7fe8921a36b 100644 --- a/.dependabot/config.yml +++ b/.dependabot/config.yml @@ -4,9 +4,6 @@ update_configs: - package_manager: "java:gradle" directory: "/core" update_schedule: "daily" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } # Explicit entry for each module - package_manager: "java:gradle" From 3d57220a0a557def6bf717ca26604f59293bcfab Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Mon, 3 Jun 2019 08:36:54 +0000 Subject: [PATCH 0105/4969] Bump kafka-clients from 2.2.0 to 2.2.1 in /modules/kafka (#1522) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index cefb6368445..29cef0b4713 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.2.0' + testCompile 'org.apache.kafka:kafka-clients:2.2.1' testCompile 'org.assertj:assertj-core:3.12.2' testCompile 'com.google.guava:guava:23.0' } From 369cfe1cac3d4ab3bf1c8590199cd4786c11f4d6 Mon Sep 17 00:00:00 2001 From: RSchlenker Date: Mon, 3 Jun 2019 11:08:15 +0200 Subject: [PATCH 0106/4969] Add spock quickstart documentation (#1499) --- docs/quickstart/spock_quickstart.md | 87 +++++++++++++++++++ examples/settings.gradle | 2 +- examples/spock/build.gradle | 15 ++++ .../java/quickstart/RedisBackedCache.java | 22 +++++ .../quickstart/RedisBackedCacheIntTest.groovy | 36 ++++++++ .../RedisBackedCacheIntTestStep0.groovy | 25 ++++++ .../spock/src/test/resources/logback-test.xml | 27 ++++++ mkdocs.yml | 1 + 8 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 docs/quickstart/spock_quickstart.md create mode 100644 examples/spock/build.gradle create mode 100644 examples/spock/src/main/java/quickstart/RedisBackedCache.java create mode 100644 examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy create mode 100644 examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy create mode 100644 examples/spock/src/test/resources/logback-test.xml diff --git a/docs/quickstart/spock_quickstart.md b/docs/quickstart/spock_quickstart.md new file mode 100644 index 00000000000..921956c875a --- /dev/null +++ b/docs/quickstart/spock_quickstart.md @@ -0,0 +1,87 @@ +# Spock Quickstart + +It's easy to add Testcontainers to your project - let's walk through a quick example to see how. + +Let's imagine we have a simple program that has a dependency on Redis, and we want to add some tests for it. +In our imaginary program, there is a `RedisBackedCache` class which stores data in Redis. + +You can see an example test that could have been written for it (without using Testcontainers): + + +[Pre-Testcontainers test code](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy) block:RedisBackedCacheIntTestStep0 + + +Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability. +This may work if we were sure that every developer and CI machine had Redis installed, but would fail otherwise. +We might also have problems if we attempted to run tests in parallel, such as state bleeding between tests, or port clashes. + +Let's start from here, and see how to improve the test with Testcontainers: + +## 1. Add Testcontainers as a test-scoped dependency + +First, add Testcontainers as a dependency as follows: + +```groovy tab='Gradle' +testCompile "org.testcontainers:spock:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + spock + {{latest_version}} + test + +``` + +## 2. Get Testcontainers to run a Redis container during our tests + +Annotate the Spock specification class with the Testcontainers extension: + +```groovy tab='Spock Testcontainers annotation' +@org.testcontainers.spock.Testcontainers +class RedisBackedCacheIntTest extends Specification { +``` + +And add the following field to the body of our test class: + + +[Spock Testcontainers init](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) inside_block:init + + +This tells Spock to start a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port. + +If we run our test as-is, then regardless of the actual test outcome, we'll see logs showing us that Testcontainers: + +* was activated before our test method ran +* discovered and quickly tested our local Docker setup +* pulled the image if necessary +* started a new container and waited for it to be ready +* shut down and deleted the container after the test + +## 3. Make sure our code can talk to the container + +Before Testcontainers, we might have hardcoded an address like `localhost:6379` into our tests. + +Testcontainers uses *randomized ports* for each container it starts, but makes it easy to obtain the actual port at runtime. +We can do this in our test `setup` method, to set up our component under test: + + +[Obtaining a mapped port](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) inside_block:setup + + +!!! tip + Notice that we also ask Testcontainers for the container's actual address with `redis.containerIpAddress`, + rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may + not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use + `containerIpAddress` instead. + +## 4. Run the tests! + +That's it! + +Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers: + + +[RedisBackedCacheIntTest](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) block:complete + diff --git a/examples/settings.gradle b/examples/settings.gradle index 06252afa580..3d57c2a18df 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -12,4 +12,4 @@ include 'selenium-container' include 'singleton-container' include 'spring-boot' include 'cucumber' - +include 'spock' diff --git a/examples/spock/build.gradle b/examples/spock/build.gradle new file mode 100644 index 00000000000..0b727fbd18a --- /dev/null +++ b/examples/spock/build.gradle @@ -0,0 +1,15 @@ +plugins { + id 'java' + id 'groovy' +} + +repositories { + jcenter() +} + +dependencies { + compile "io.lettuce:lettuce-core:5.1.1.RELEASE" + testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' + testImplementation 'org.testcontainers:spock' + testImplementation 'ch.qos.logback:logback-classic:1.2.3' +} diff --git a/examples/spock/src/main/java/quickstart/RedisBackedCache.java b/examples/spock/src/main/java/quickstart/RedisBackedCache.java new file mode 100644 index 00000000000..1123858ca17 --- /dev/null +++ b/examples/spock/src/main/java/quickstart/RedisBackedCache.java @@ -0,0 +1,22 @@ +package quickstart; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; + +public class RedisBackedCache { + + private final StatefulRedisConnection connection; + + public RedisBackedCache(String hostname, Integer port) { + RedisClient client = RedisClient.create(String.format("redis://%s:%d/0", hostname, port)); + connection = client.connect(); + } + + public String get(String key) { + return connection.sync().get(key); + } + + public void put(String key, String value) { + connection.sync().set(key, value); + } +} diff --git a/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy b/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy new file mode 100644 index 00000000000..d8c056b5070 --- /dev/null +++ b/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy @@ -0,0 +1,36 @@ +package quickstart + +import org.testcontainers.containers.GenericContainer +import spock.lang.Specification + +// complete { +@org.testcontainers.spock.Testcontainers +class RedisBackedCacheIntTest extends Specification { + + private RedisBackedCache underTest + + // init { + public GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") + .withExposedPorts(6379) + // } + + void setup() { + String address = redis.containerIpAddress + Integer port = redis.firstMappedPort + + // Now we have an address and port for Redis, no matter where it is running + underTest = new RedisBackedCache(address, port) + } + + void testSimplePutAndGet() { + setup: + underTest.put("test", "example") + + when: + String retrieved = underTest.get("test") + + then: + retrieved == "example" + } +} +// } diff --git a/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy b/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy new file mode 100644 index 00000000000..52897c30097 --- /dev/null +++ b/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy @@ -0,0 +1,25 @@ +package quickstart + +import spock.lang.Ignore +import spock.lang.Specification + +@Ignore("This test class is deliberately invalid, as it relies on a non-existent local Redis") +class RedisBackedCacheIntTestStep0 extends Specification { + private RedisBackedCache underTest + + void setup() { + // Assume that we have Redis running locally? + underTest = new RedisBackedCache("localhost", 6379) + } + + void testSimplePutAndGet() { + setup: + underTest.put("test", "example") + + when: + String retrieved = underTest.get("test") + + then: + retrieved == "example" + } +} diff --git a/examples/spock/src/test/resources/logback-test.xml b/examples/spock/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..6e7cfd092de --- /dev/null +++ b/examples/spock/src/test/resources/logback-test.xml @@ -0,0 +1,27 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + + + + + + + + + PROFILER + DENY + + diff --git a/mkdocs.yml b/mkdocs.yml index 762116a062c..869d0d4b551 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,6 +25,7 @@ nav: - Home: index.md - Quickstart: - quickstart/junit_4_quickstart.md + - quickstart/spock_quickstart.md - Features: - features/creating_container.md - features/networking.md From 4bb2dea90c61759c75745c99052c33175f8a2a53 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 4 Jun 2019 08:28:09 +0000 Subject: [PATCH 0107/4969] Bump lettuce-core from 5.1.1.RELEASE to 5.1.6.RELEASE in /examples (#1526) --- examples/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spock/build.gradle b/examples/spock/build.gradle index 0b727fbd18a..9ac238b54f4 100644 --- a/examples/spock/build.gradle +++ b/examples/spock/build.gradle @@ -8,7 +8,7 @@ repositories { } dependencies { - compile "io.lettuce:lettuce-core:5.1.1.RELEASE" + compile "io.lettuce:lettuce-core:5.1.6.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' testImplementation 'org.testcontainers:spock' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From a44f357956e116bcbc0062d22096671150fdf376 Mon Sep 17 00:00:00 2001 From: Sandra Parsick Date: Tue, 4 Jun 2019 13:00:16 +0200 Subject: [PATCH 0108/4969] Add support for tmpfs to ContainerDatabaseDriver (#1500) --- docs/modules/databases/index.md | 15 ++++- .../jdbc/DatabaseDriverTmpfsTest.java | 35 +++++++++++ .../testcontainers/jdbc/ConnectionUrl.java | 59 ++++++++++++++----- .../jdbc/ContainerDatabaseDriver.java | 1 + .../jdbc/ConnectionUrlTest.java | 15 +++++ 5 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index 71d65af7e20..22292875307 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -7,7 +7,7 @@ You might want to use Testcontainers' database support: * **Instead of H2 database for DAO unit tests that depend on database features that H2 doesn't emulate.** Testcontainers is not as performant as H2, but does give you the benefit of 100% database compatibility (since it runs a real DB inside of a container). * **Instead of a database running on the local machine or in a VM** for DAO unit tests or end-to-end integration tests that need a database to be present. In this context, the benefit of Testcontainers is that the database always starts in a known state, without any contamination between test runs or on developers' local machines. -!!! note +!!! note Of course, it's still important to have as few tests that hit the database as possible, and make good use of mocks for components higher up the stack. You can obtain a temporary database in one of two ways: @@ -101,3 +101,16 @@ By default database container is being stopped as soon as last connection is clo `jdbc:tc:mysql:5.7.22://hostname/databasename?TC_DAEMON=true` With this parameter database container will keep running even when there're no open connections. + + +#### Running container with tmpfs options + +Container can have `tmpfs` mounts for storing data in host memory. This is useful if you want to speed up your database tests. Be aware that the data will be lost when the container stops. + +To pass this option to the container, add `TC_TMPFS` paramater to the URL as follows: + + `jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw` + +If you need more than one option, seperate them by comma (e.g. `TC_TMPFS=key:value,key1:value1&other_parameters=foo`). + +For more information about `tmpfs` mount, see [the official Docker documentation](https://docs.docker.com/storage/tmpfs/). diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java new file mode 100644 index 00000000000..07b70020733 --- /dev/null +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -0,0 +1,35 @@ +package org.testcontainers.jdbc; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import org.junit.Test; +import org.testcontainers.containers.Container; +import org.testcontainers.containers.JdbcDatabaseContainer; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class DatabaseDriverTmpfsTest { + + @Test + public void tmpfs() throws IOException, InterruptedException, SQLException { + final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw"; + try (Connection ignored = DriverManager.getConnection(jdbcUrl)) { + + JdbcDatabaseContainer container = ContainerDatabaseDriver.getContainer(jdbcUrl); + // check file doesn't exist + String path = "/testtmpfs/test.file"; + Container.ExecResult execResult = container.execInContainer("ls", path); + assertEquals("tmpfs inside container works fine", execResult.getStderr(), + "ls: cannot access '/testtmpfs/test.file': No such file or directory\n"); + // touch && check file does exist + container.execInContainer("touch", path); + execResult = container.execInContainer("ls", path); + assertEquals("tmpfs inside container works fine", execResult.getStdout(), path + "\n"); + } + + } + + +} diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java index 7c5a53ede65..36206b89d82 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java @@ -1,13 +1,20 @@ package org.testcontainers.jdbc; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.toMap; /** * This is an Immutable class holding JDBC Connection Url and its parsed components, used by {@link ContainerDatabaseDriver}. @@ -16,7 +23,8 @@ * * @author manikmagar */ -@EqualsAndHashCode(of = "url") @Getter +@EqualsAndHashCode(of = "url") +@Getter public class ConnectionUrl { private String url; @@ -48,8 +56,9 @@ public class ConnectionUrl { private Map containerParameters; private Map queryParameters; + private Map tmpfsOptions = new HashMap<>(); - public static ConnectionUrl newInstance(final String url){ + public static ConnectionUrl newInstance(final String url) { ConnectionUrl connectionUrl = new ConnectionUrl(url); connectionUrl.parseUrl(); return connectionUrl; @@ -65,7 +74,8 @@ public static boolean accepts(final String url) { /** * This method applies various REGEX Patterns to parse the URL associated with this instance. - * This is called from a @{@link ConnectionUrl#newInstance(String)} static factory method to create immutable instance of {@link ConnectionUrl}. + * This is called from a @{@link ConnectionUrl#newInstance(String)} static factory method to create immutable instance of + * {@link ConnectionUrl}. * To avoid mutation after class is instantiated, this method should not be publicly accessible. */ private void parseUrl() { @@ -100,14 +110,14 @@ private void parseUrl() { } queryParameters = Collections.unmodifiableMap( - parseQueryParameters( - Optional.ofNullable(urlMatcher.group(5)).orElse(""))); + parseQueryParameters( + Optional.ofNullable(urlMatcher.group(5)).orElse(""))); String query = queryParameters - .entrySet() - .stream() - .map(e -> e.getKey() + "=" + e.getValue()) - .collect(Collectors.joining("&")); + .entrySet() + .stream() + .map(e -> e.getKey() + "=" + e.getValue()) + .collect(Collectors.joining("&")); if (query == null || query.trim().length() == 0) { queryString = Optional.empty(); @@ -117,6 +127,9 @@ private void parseUrl() { containerParameters = Collections.unmodifiableMap(parseContainerParameters()); + tmpfsOptions = parseTmpfsOptions(containerParameters); + + initScriptPath = Optional.ofNullable(containerParameters.get("TC_INITSCRIPT")); Matcher funcMatcher = Patterns.INITFUNCTION_MATCHING_PATTERN.matcher(this.getUrl()); @@ -129,6 +142,19 @@ private void parseUrl() { } + private Map parseTmpfsOptions(Map containerParameters) { + if(!containerParameters.containsKey("TC_TMPFS")){ + return Collections.emptyMap(); + } + + String tmpfsOptions = containerParameters.get("TC_TMPFS"); + + return Stream.of(tmpfsOptions.split(",")) + .collect(toMap( + string -> string.split(":")[0], + string -> string.split(":")[1])); + } + /** * Get the TestContainers Parameters such as Init Function, Init Script path etc. * @@ -160,12 +186,17 @@ private Map parseQueryParameters(final String queryString) { while (matcher.find()) { String key = matcher.group(1); String value = matcher.group(2); - if(!key.matches(Patterns.TC_PARAM_NAME_PATTERN)) results.put(key, value); + if (!key.matches(Patterns.TC_PARAM_NAME_PATTERN)) + results.put(key, value); } return results; } + public Map getTmpfsOptions() { + return Collections.unmodifiableMap(tmpfsOptions); + } + /** * This interface defines the Regex Patterns used by {@link ConnectionUrl}. * diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java index 0f470e36979..6d3df6c7cc5 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java @@ -93,6 +93,7 @@ public synchronized Connection connect(String url, final Properties info) throws for (JdbcDatabaseContainerProvider candidateContainerType : databaseContainers) { if (candidateContainerType.supports(connectionUrl.getDatabaseType())) { container = candidateContainerType.newInstance(connectionUrl); + container.withTmpFs(connectionUrl.getTmpfsOptions()); delegate = container.getJdbcDriverInstance(); } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java index a5c36d8f065..53524eb32b2 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java @@ -49,6 +49,21 @@ public void testConnectionUrl2() { } + @Test + public void testTmpfsOption() { + String urlString = "jdbc:tc:mysql://somehostname/databasename?TC_TMPFS=key:value,key1:value1"; + ConnectionUrl url = ConnectionUrl.newInstance(urlString); + + assertTrue("Connection Parameters set is empty", url.getQueryParameters().isEmpty()); + assertFalse("Container Parameters set is not empty", url.getContainerParameters().isEmpty()); + assertEquals("Container Parameter TC_TMPFS is true", "key:value,key1:value1", url.getContainerParameters().get("TC_TMPFS")); + assertTrue("tmpfs option key exists", url.getTmpfsOptions().containsKey("key")); + assertEquals("tmpfs option key has correct value", "value" , url.getTmpfsOptions().get("key")); + assertTrue("tmpfs option key1 exists", url.getTmpfsOptions().containsKey("key1")); + assertEquals("tmpfs option key1 has correct value", "value1" , url.getTmpfsOptions().get("key1")); + } + + @Test public void testInitScriptPathCapture() { String urlString = "jdbc:tc:mysql:5.6.23://somehostname:3306/databasename?a=b&c=d&TC_INITSCRIPT=somepath/init_mysql.sql"; From e6693bc9f0f88f1ad5ae5b0368b42daf8a22972a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Fri, 7 Jun 2019 07:58:41 +0000 Subject: [PATCH 0109/4969] Bump java-client from 2.7.6 to 2.7.7 in /modules/couchbase (#1536) --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 8cf0f879215..6635462818f 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,5 +2,5 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.6' + compile 'com.couchbase.client:java-client:2.7.7' } From cdf3501c2be5c5c6b891e30c6642719bb22ba4ba Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Mon, 10 Jun 2019 08:20:49 +0000 Subject: [PATCH 0110/4969] Bump tomcat-jdbc from 9.0.20 to 9.0.21 in /modules/mariadb (#1538) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 371ec52641d..e1b21c58d04 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.1' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.20' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.21' testCompile 'org.vibur:vibur-dbcp:22.2' } From 287f7512113dfe1531cc54fd674ef9a3ec331ef9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Mon, 10 Jun 2019 08:58:20 +0000 Subject: [PATCH 0111/4969] Bump tomcat-jdbc from 9.0.20 to 9.0.21 in /modules/mysql (#1539) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index e48c71734ae..e2b1b416400 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.16' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.20' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.21' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From 7de41161a3e3b0dfb737ff8964f44dc70db04b16 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Wed, 12 Jun 2019 08:02:12 +0000 Subject: [PATCH 0112/4969] Bump httpclient from 4.5.8 to 4.5.9 in /modules/junit-jupiter (#1543) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 591347ca699..59d72d82a21 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,7 +8,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'redis.clients:jedis:3.0.1' - testCompile 'org.apache.httpcomponents:httpclient:4.5.8' + testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.16' From 57ed84a58a0b0a9b93b3175321e89eec0d922a0d Mon Sep 17 00:00:00 2001 From: Dmitry Yakubovsky Date: Wed, 12 Jun 2019 15:14:07 +0200 Subject: [PATCH 0113/4969] Add Zalando SE as one of the users (#1542) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index cbee344e637..d202ef67cbb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -71,6 +71,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Skyscanner](https://www.skyscanner.net/) - Integration testing against HTTP service mocks and various data stores * [Neo4j-OGM](https://neo4j.com/developer/neo4j-ogm/) - Testing new, reactive client implementations * [Lightbend](https://www.lightbend.com/) - Testing [Alpakka Kafka](https://doc.akka.io/docs/alpakka-kafka/current/) and support in [Alpakka Kafka Testkit](https://doc.akka.io/docs/alpakka-kafka/current/testing.html#testing-with-kafka-in-docker) +* [Zalando SE](https://corporate.zalando.com/en) - Testing core business services ## License From 8d242a385ea472655b77b4ada498cc67f6666aec Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 12 Jun 2019 20:17:05 +0100 Subject: [PATCH 0114/4969] Add minimal docs describing Drone CI usage (#1505) --- .../continuous_integration/dind_patterns.md | 7 +++++++ .../continuous_integration/drone.md | 5 ++++- mkdocs.yml | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/continuous_integration/dind_patterns.md b/docs/supported_docker_environment/continuous_integration/dind_patterns.md index 38bcd82c752..1534949e1bd 100644 --- a/docs/supported_docker_environment/continuous_integration/dind_patterns.md +++ b/docs/supported_docker_environment/continuous_integration/dind_patterns.md @@ -47,3 +47,10 @@ tests: - ~/.m2:/root/.m2 command: mvn test ``` + +## Docker-in-Docker + +While Docker-in-Docker (DinD) is generally considered an instrument of last resort, it is necessary for some CI environments. + +[Drone CI](./drone.md) is one such example. Testcontainers has a Docker-in-Docker plugin (build image) for use with Drone, +which could be used as inspiration for setting up other similar testing using DinD. diff --git a/docs/supported_docker_environment/continuous_integration/drone.md b/docs/supported_docker_environment/continuous_integration/drone.md index 2549bdf4f48..f4a1dd2bc6a 100644 --- a/docs/supported_docker_environment/continuous_integration/drone.md +++ b/docs/supported_docker_environment/continuous_integration/drone.md @@ -1,3 +1,6 @@ # Drone CI -> TODO +Drone CI 0.8 is supported via the use of a general purpose Docker-in-Docker plugin. + +Please see [testcontainers/dind-drone-plugin](https://github.com/testcontainers/dind-drone-plugin) for further details and usage instructions. + diff --git a/mkdocs.yml b/mkdocs.yml index 869d0d4b551..6b38d82eff4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -70,6 +70,7 @@ nav: - Continuous Integration: - supported_docker_environment/continuous_integration/dind_patterns.md - supported_docker_environment/continuous_integration/circle_ci.md + - supported_docker_environment/continuous_integration/drone.md - supported_docker_environment/continuous_integration/gitlab_ci.md - supported_docker_environment/continuous_integration/bitbucket_pipelines.md - supported_docker_environment/windows.md From 271835edd0f0afa875ad79146faa9f207d4c0a3c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 18 Jun 2019 08:07:52 +0000 Subject: [PATCH 0115/4969] Bump mariadb-java-client from 2.4.1 to 2.4.2 in /modules/mariadb (#1551) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index e1b21c58d04..0068368b8a3 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.1' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.2' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.21' From 4f56c79a9175b24934eb759f51742baa3925ed7f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 18 Jun 2019 08:58:56 +0000 Subject: [PATCH 0116/4969] Bump httpclient from 4.5.8 to 4.5.9 in /modules/spock (#1545) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 6076788dbc4..c11850eacc6 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' - testCompile 'org.apache.httpcomponents:httpclient:4.5.8' + testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testRuntime 'org.postgresql:postgresql:42.2.5' testRuntime 'mysql:mysql-connector-java:8.0.16' From b6f42a343960ba0542e7b48c0148ef8557db6e9a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Wed, 19 Jun 2019 06:01:29 +0000 Subject: [PATCH 0117/4969] Bump lettuce-core from 5.1.6.RELEASE to 5.1.7.RELEASE in /examples (#1554) --- examples/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spock/build.gradle b/examples/spock/build.gradle index 9ac238b54f4..cc04f74c90d 100644 --- a/examples/spock/build.gradle +++ b/examples/spock/build.gradle @@ -8,7 +8,7 @@ repositories { } dependencies { - compile "io.lettuce:lettuce-core:5.1.6.RELEASE" + compile "io.lettuce:lettuce-core:5.1.7.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' testImplementation 'org.testcontainers:spock' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From b8126ac70345c1d6eda32a7375e1ebf11081911c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Wed, 19 Jun 2019 06:35:58 +0000 Subject: [PATCH 0118/4969] Bump org.springframework.boot in /examples (#1556) --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 0aa55093dca..d4f3c132896 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.5.RELEASE' + id 'org.springframework.boot' version '2.1.6.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index f45b0e51c11..52767c7a9ca 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.5.RELEASE' + id 'org.springframework.boot' version '2.1.6.RELEASE' } apply plugin: 'io.spring.dependency-management' From 1862873051d0ea12d6acc80e3ac98f40c7253ee1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Wed, 19 Jun 2019 07:22:38 +0000 Subject: [PATCH 0119/4969] Bump cucumber-junit from 4.3.1 to 4.4.0 in /examples (#1555) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index bab77700eff..3381ecab567 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.3.1' - testImplementation 'io.cucumber:cucumber-junit:4.3.1' + testImplementation 'io.cucumber:cucumber-junit:4.4.0' testImplementation 'org.testcontainers:selenium' } From d44c83289ede050b1f0a87bb0d765047e5fd7d6f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Wed, 19 Jun 2019 08:19:01 +0000 Subject: [PATCH 0120/4969] Bump cucumber-java from 4.3.1 to 4.4.0 in /examples (#1553) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 3381ecab567..6d6e6385a60 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.3.1' + implementation 'io.cucumber:cucumber-java:4.4.0' testImplementation 'io.cucumber:cucumber-junit:4.4.0' testImplementation 'org.testcontainers:selenium' } From ef91a5c126bfa989ee5a962fc87904b548d3a7f8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Thu, 20 Jun 2019 06:11:00 +0000 Subject: [PATCH 0121/4969] Bump postgresql from 42.2.5 to 42.2.6 in /modules/spock (#1558) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index c11850eacc6..74c6b6fd5db 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -13,6 +13,6 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testRuntime 'org.postgresql:postgresql:42.2.5' + testRuntime 'org.postgresql:postgresql:42.2.6' testRuntime 'mysql:mysql-connector-java:8.0.16' } From b880ef0c4ce7d94136edd1dacd82bebc88367aa9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Thu, 20 Jun 2019 07:10:46 +0000 Subject: [PATCH 0122/4969] Bump postgresql from 42.2.5 to 42.2.6 in /modules/postgresql (#1560) --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 0ef6df998e3..1a5980dee55 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { compile project(':jdbc') - testCompile 'org.postgresql:postgresql:42.2.5' + testCompile 'org.postgresql:postgresql:42.2.6' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' } From 10c71d8188d1fc95416745d6f0469ee2b3452d75 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Thu, 20 Jun 2019 07:45:47 +0000 Subject: [PATCH 0123/4969] Bump postgresql from 42.2.5 to 42.2.6 in /examples (#1561) --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 8522878f5ec..ce0eff58a28 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.26' implementation 'com.squareup.okhttp3:okhttp:3.14.2' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.5' + testImplementation 'org.postgresql:postgresql:42.2.6' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From e690b938f4180782a5003f83840e90d642b91569 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2019 09:47:57 +0200 Subject: [PATCH 0124/4969] Bump mockserver-client-java from 5.5.1 to 5.5.4 in /modules/mockserver (#1438) Also increase the used image tag accordingly. --- modules/mockserver/build.gradle | 2 +- .../org/testcontainers/containers/MockServerContainer.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/mockserver/build.gradle b/modules/mockserver/build.gradle index 8855121360c..b463997fed5 100644 --- a/modules/mockserver/build.gradle +++ b/modules/mockserver/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: MockServer" dependencies { compile project(':testcontainers') - testCompile 'org.mock-server:mockserver-client-java:5.5.1' + testCompile 'org.mock-server:mockserver-client-java:5.5.4' } diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index f191adea06d..f1f9dc42d19 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -5,7 +5,7 @@ @Slf4j public class MockServerContainer extends GenericContainer { - public static final String VERSION = "5.5.1"; + public static final String VERSION = "5.5.4"; public static final int PORT = 1080; @@ -15,7 +15,7 @@ public MockServerContainer() { public MockServerContainer(String version) { super("jamesdbloom/mockserver:mockserver-" + version); - withCommand("/opt/mockserver/run_mockserver.sh -logLevel INFO -serverPort " + PORT); + withCommand("-logLevel INFO -serverPort " + PORT); addExposedPorts(PORT); } From c5e4e643382022543244d988cff89a9d5656bdb6 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2019 08:27:41 +0000 Subject: [PATCH 0125/4969] Bump postgresql from 42.2.5 to 42.2.6 in /modules/junit-jupiter (#1559) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 59d72d82a21..9860686eed7 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testRuntime 'org.postgresql:postgresql:42.2.5' + testRuntime 'org.postgresql:postgresql:42.2.6' testRuntime 'mysql:mysql-connector-java:8.0.16' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.2' } From 61595018f232278cf8aa95ad2363e3a2bdf974ab Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2019 05:54:46 +0000 Subject: [PATCH 0126/4969] Bump kafka-clients from 2.2.1 to 2.3.0 in /modules/kafka (#1565) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 29cef0b4713..10013a6e11e 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.2.1' + testCompile 'org.apache.kafka:kafka-clients:2.3.0' testCompile 'org.assertj:assertj-core:3.12.2' testCompile 'com.google.guava:guava:23.0' } From 67ca611a4a3509130663b0ccd54195b8d1014117 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2019 06:26:01 +0000 Subject: [PATCH 0127/4969] Bump junit-jupiter-engine from 5.4.2 to 5.5.0 in /modules/junit-jupiter (#1577) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 9860686eed7..56a11f60ffe 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.6' testRuntime 'mysql:mysql-connector-java:8.0.16' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.2' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.0' } test { From 909f0092bb01781579b04a37d5fadcebabb9c9ec Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2019 07:38:46 +0000 Subject: [PATCH 0128/4969] Bump junit-jupiter-api from 5.4.2 to 5.5.0 in /modules/junit-jupiter (#1578) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 56a11f60ffe..baab3b68bb8 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.4.2' + compile 'org.junit.jupiter:junit-jupiter-api:5.5.0' testCompile project(':mysql') testCompile project(':postgresql') From d5c0dcae4083038bb02c7248d09c672c3b5814b3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2019 08:29:27 +0000 Subject: [PATCH 0129/4969] Bump cucumber-junit from 4.4.0 to 4.5.0 in /examples (#1579) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 6d6e6385a60..8e6c52f451e 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.4.0' - testImplementation 'io.cucumber:cucumber-junit:4.4.0' + testImplementation 'io.cucumber:cucumber-junit:4.5.0' testImplementation 'org.testcontainers:selenium' } From a1f1d242b196a086f8660b260c4e3c969228de4c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2019 09:50:47 +0000 Subject: [PATCH 0130/4969] Bump cucumber-java from 4.4.0 to 4.5.0 in /examples (#1580) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 8e6c52f451e..c590d68875b 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.4.0' + implementation 'io.cucumber:cucumber-java:4.5.0' testImplementation 'io.cucumber:cucumber-junit:4.5.0' testImplementation 'org.testcontainers:selenium' } From 67ca5e717cc2ea88d1fda79286bfef619aca4e25 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2019 05:50:48 +0000 Subject: [PATCH 0131/4969] Bump cucumber-java from 4.5.0 to 4.5.1 in /examples (#1583) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index c590d68875b..48a016a30c8 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.5.0' + implementation 'io.cucumber:cucumber-java:4.5.1' testImplementation 'io.cucumber:cucumber-junit:4.5.0' testImplementation 'org.testcontainers:selenium' } From d5efe5be77e8f868faaf2cc8e044d740b9c65b9a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2019 07:08:13 +0000 Subject: [PATCH 0132/4969] Bump cucumber-junit from 4.5.0 to 4.5.1 in /examples (#1584) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 48a016a30c8..505aad82ae4 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.5.1' - testImplementation 'io.cucumber:cucumber-junit:4.5.0' + testImplementation 'io.cucumber:cucumber-junit:4.5.1' testImplementation 'org.testcontainers:selenium' } From ace97aaa4ede14bc559c786552651acd4c553a48 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2019 05:44:27 +0000 Subject: [PATCH 0133/4969] Bump neo4j from 3.5.6 to 3.5.7 in /modules/neo4j (#1586) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 68a52d115cd..9c5410aa179 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -25,7 +25,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.6" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.7" compile project(":testcontainers") From efabf3d1300da7b735453e916df40da6d5fc9337 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2019 06:16:51 +0000 Subject: [PATCH 0134/4969] Bump pulsar-client from 2.3.2 to 2.4.0 in /modules/pulsar (#1587) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 301d6f81da2..e8e589cda72 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.2' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.4.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.2' } From 52f090acd9d6c97fb534071456164f76868b749d Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 6 Jul 2019 17:23:19 +0100 Subject: [PATCH 0135/4969] =?UTF-8?q?Revert=20"Bump=20pulsar-client=20from?= =?UTF-8?q?=202.3.2=20to=202.4.0=20in=20/modules/puls=E2=80=A6=20(#1589)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit efabf3d1300da7b735453e916df40da6d5fc9337. --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index e8e589cda72..301d6f81da2 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.4.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.2' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.2' } From 06ea95be1e288622aedb3a35ea585575654e5a9a Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 6 Jul 2019 23:18:18 +0200 Subject: [PATCH 0136/4969] Deprecate fields that are derived from `containerInfo` (#1585) --- .../containers/DockerComposeContainer.java | 2 +- .../containers/GenericContainer.java | 16 +++++++++++++++- .../containers/VncRecordingContainer.java | 6 +++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 67674796cdd..ff92289431e 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -559,7 +559,7 @@ public void invoke() { AuditLogger.doComposeLog(this.getCommandParts(), this.getEnv()); - final Integer exitCode = this.dockerClient.inspectContainerCmd(containerId) + final Integer exitCode = this.dockerClient.inspectContainerCmd(getContainerId()) .exec() .getState() .getExitCode(); diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 936d880d1a8..8045d47c720 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -143,13 +143,23 @@ public class GenericContainer> @Setter(AccessLevel.NONE) protected Info dockerDaemonInfo = null; - /* + /** * Set during container startup + * // TODO make it private + * + * @deprecated use {@link ContainerState#getContainerId()} */ @Setter(AccessLevel.NONE) + @Deprecated protected String containerId; + /** + * Set during container startup + * + * @deprecated use {@link GenericContainer#getContainerInfo()} + */ @Setter(AccessLevel.NONE) + @Deprecated protected String containerName; @Setter(AccessLevel.NONE) @@ -188,6 +198,10 @@ public GenericContainer(@NonNull final Future image) { this.image = image; } + public String getContainerId() { + return containerId; + } + /** * Starts the container using docker, pulling an image if necessary. */ diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index b8a26bfe65b..1b06215b706 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -78,7 +78,7 @@ public void onNext(Frame frame) { }; try ( - Closeable __ = dockerClient.logContainerCmd(containerId) + Closeable __ = dockerClient.logContainerCmd(getContainerId()) .withFollowStream(true) .withSince(0) .withStdErr(true) @@ -122,7 +122,7 @@ protected void configure() { @SneakyThrows public InputStream streamRecording() { TarArchiveInputStream archiveInputStream = new TarArchiveInputStream( - dockerClient.copyArchiveFromContainerCmd(containerId, RECORDING_FILE_NAME).exec() + dockerClient.copyArchiveFromContainerCmd(getContainerId(), RECORDING_FILE_NAME).exec() ); archiveInputStream.getNextEntry(); return archiveInputStream; @@ -134,4 +134,4 @@ public void saveRecordingToFile(File file) { Files.copy(inputStream, file.toPath(), StandardCopyOption.REPLACE_EXISTING); } } -} \ No newline at end of file +} From 7fae384751da6101a451aa7d0a753ebd6dbf13ce Mon Sep 17 00:00:00 2001 From: HaMatthias <38075918+HaMatthias@users.noreply.github.com> Date: Sat, 6 Jul 2019 23:19:45 +0200 Subject: [PATCH 0137/4969] Docker Compose: allow specific services to be started (#1528) --- .../containers/DockerComposeContainer.java | 12 ++++++- .../junit/DockerComposeServiceTest.java | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index ff92289431e..46f4c561e5d 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -75,6 +75,8 @@ public class DockerComposeContainer> e private static final Object MUTEX = new Object(); + private List services = new ArrayList<>(); + /** * Properties that should be passed through to all Compose and ambassador containers (not * necessarily to containers that are spawned by Compose itself) @@ -159,10 +161,18 @@ private void pullImages() { runWithCompose("pull"); } + public SELF withServices(@NonNull String... services) { + this.services = Arrays.asList(services); + return self(); + } private void createServices() { // Run the docker-compose container, which starts up the services - runWithCompose("up -d"); + if(services.isEmpty()) { + runWithCompose("up -d"); + } else { + runWithCompose("up -d " + String.join(" ", services)); + } } private void waitUntilServiceStarted() { diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java new file mode 100644 index 00000000000..c0360050d27 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java @@ -0,0 +1,33 @@ +package org.testcontainers.junit; + +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.containers.DockerComposeContainer; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; + +import java.io.File; + +public class DockerComposeServiceTest extends BaseDockerComposeTest { + + @Rule + public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) + .withServices("redis") + .withExposedService("redis_1", REDIS_PORT); + + + @Override + protected DockerComposeContainer getEnvironment() { + return environment; + } + + @Test(expected = NullPointerException.class) + public void testDbIsNotStarting() { + environment.getServicePort("db_1", 10001); + } + + @Test + public void testRedisIsStarting() { + assertNotNull("Redis server started", environment.getServicePort("redis_1", REDIS_PORT)); + } +} From c7945503d99bb573dc05e769a924aebcf8d0a5ee Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jul 2019 22:32:24 +0100 Subject: [PATCH 0138/4969] Bump httpclient from 4.5.8 to 4.5.9 in /core (#1544) Bumps httpclient from 4.5.8 to 4.5.9. Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index a77720d66df..30fd4d6167e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -100,7 +100,7 @@ dependencies { exclude(group: 'org.slf4j') } - testCompile 'org.apache.httpcomponents:httpclient:4.5.8' + testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.7.1' testCompile 'org.mongodb:mongo-java-driver:3.10.2' From 64f3906080961fb11e2023a4fe31adb2a5090a22 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Mon, 8 Jul 2019 14:00:59 +0200 Subject: [PATCH 0139/4969] Add Europace AG as user (#1591) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index d202ef67cbb..89e70611f37 100644 --- a/docs/index.md +++ b/docs/index.md @@ -72,6 +72,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Neo4j-OGM](https://neo4j.com/developer/neo4j-ogm/) - Testing new, reactive client implementations * [Lightbend](https://www.lightbend.com/) - Testing [Alpakka Kafka](https://doc.akka.io/docs/alpakka-kafka/current/) and support in [Alpakka Kafka Testkit](https://doc.akka.io/docs/alpakka-kafka/current/testing.html#testing-with-kafka-in-docker) * [Zalando SE](https://corporate.zalando.com/en) - Testing core business services +* [Europace AG](https://tech.europace.de/) - Integration testing for databases and micro services ## License From ed0143333b386d551ae0fbdf00e11e707e2cf0a1 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 8 Jul 2019 16:51:53 +0200 Subject: [PATCH 0140/4969] Azure pipelines (#1363) --- azure-pipelines.yml | 21 +++ build.gradle | 1 + .../junit/DockerNetworkModeTest.java | 85 ++++------ .../testcontainers/jdbc/JDBCDriverTest.java | 156 ++++++++---------- .../jdbc/JDBCDriverWithPoolTest.java | 3 +- 5 files changed, 127 insertions(+), 139 deletions(-) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000000..abcd155010d --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,21 @@ +steps: +- task: Gradle@2 + displayName: Build core + inputs: + gradleWrapperFile: 'gradlew' + jdkVersionOption: '1.11' + options: '--no-daemon --continue' + tasks: 'testcontainers:check' + publishJUnitResults: true + testResultsFiles: '**/TEST-*.xml' +- task: Gradle@2 + displayName: Build modules + inputs: + gradleWrapperFile: 'gradlew' + jdkVersionOption: '1.11' + options: '--no-daemon --continue -x testcontainers:check' + tasks: 'check' + publishJUnitResults: true + testResultsFiles: '**/TEST-*.xml' + + diff --git a/build.gradle b/build.gradle index 27f1d8859f1..235c1ae22f1 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,7 @@ subprojects { sourceCompatibility = 1.8 targetCompatibility = 1.8 compileJava.options.encoding = 'UTF-8' + compileTestJava.options.encoding = 'UTF-8' lombok { version = '1.18.6' diff --git a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java index 24215094e08..873160bdbc9 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java @@ -1,73 +1,50 @@ package org.testcontainers.junit; +import com.github.dockerjava.api.model.NetworkSettings; +import lombok.extern.slf4j.Slf4j; import org.junit.*; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.ToStringConsumer; -import org.testcontainers.containers.output.WaitingConsumer; -import org.testcontainers.utility.TestEnvironment; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Consumer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** * Simple tests of named network modes - more may be possible, but may not be reproducible * without other setup steps. */ +@Slf4j public class DockerNetworkModeTest { - @BeforeClass - public static void checkVersion() { - Assume.assumeTrue(TestEnvironment.dockerApiAtLeast("1.22")); - } - - @ClassRule - public static GenericContainer noNetwork = new GenericContainer("alpine:3.2") - .withNetworkMode("none") - .withCommand("ping -c 5 www.google.com"); - - @ClassRule - public static GenericContainer hostNetwork = new GenericContainer("alpine:3.2") - .withNetworkMode("host") - .withCommand("ping -c 5 www.google.com"); - - @ClassRule - public static GenericContainer bridgedNetwork = new GenericContainer("alpine:3.2") - .withNetworkMode("bridge") - .withCommand("ping -c 5 www.google.com"); - - @Test - public void testNoNetworkContainer() throws TimeoutException { - String output = getContainerOutput(noNetwork); - - assertTrue("'none' network causes a network access error", output.contains("bad address")); - } - @Test - public void testHostNetworkContainer() throws TimeoutException { - String output = getContainerOutput(hostNetwork); - - assertTrue("'host' network can access the internet", output.contains("seq=1")); + public void testNoNetworkContainer() { + try ( + GenericContainer container = new GenericContainer() + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withCommand("true") + .withNetworkMode("none") + ) { + container.start(); + NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); + + assertEquals("only one network is set", 1, networkSettings.getNetworks().size()); + assertTrue("network is 'none'", networkSettings.getNetworks().containsKey("none")); + } } @Test - public void testBridgedNetworkContainer() throws TimeoutException { - String output = getContainerOutput(bridgedNetwork); - - assertTrue("'bridge' network can access the internet", output.contains("seq=1")); - } - - private String getContainerOutput(GenericContainer container) throws TimeoutException { - WaitingConsumer waitingConsumer = new WaitingConsumer(); - ToStringConsumer toStringConsumer = new ToStringConsumer(); - Consumer composedConsumer = waitingConsumer.andThen(toStringConsumer); - - container.followOutput(composedConsumer); - waitingConsumer.waitUntilEnd(10, TimeUnit.SECONDS); - - return toStringConsumer.toUtf8String(); + public void testHostNetworkContainer() { + try ( + GenericContainer container = new GenericContainer() + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withCommand("true") + .withNetworkMode("host") + ) { + container.start(); + NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); + + assertEquals("only one network is set", 1, networkSettings.getNetworks().size()); + assertTrue("network is 'host'", networkSettings.getNetworks().containsKey("host")); + } } } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index 40cb707a2d0..30b224ab6a6 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -1,6 +1,5 @@ package org.testcontainers.jdbc; -import com.googlecode.junittoolbox.ParallelParameterized; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.apache.commons.dbutils.QueryRunner; @@ -22,7 +21,7 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -@RunWith(ParallelParameterized.class) +@RunWith(Parameterized.class) public class JDBCDriverTest { private enum Options { @@ -86,98 +85,91 @@ public static void testCleanup() { @Test public void test() throws SQLException { - performSimpleTest(jdbcUrl); + try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) { + performSimpleTest(dataSource); - if (options.contains(Options.ScriptedSchema)) { - performTestForScriptedSchema(jdbcUrl); - } + if (options.contains(Options.ScriptedSchema)) { + performTestForScriptedSchema(dataSource); + } - if (options.contains(Options.JDBCParams)) { - performTestForJDBCParamUsage(jdbcUrl); - } + if (options.contains(Options.JDBCParams)) { + performTestForJDBCParamUsage(dataSource); + } - if (options.contains(Options.CharacterSet)) { - //Called twice to ensure that the query string parameters are used when - //connections are created from cached containers. - performSimpleTestWithCharacterSet(jdbcUrl); - performSimpleTestWithCharacterSet(jdbcUrl); + if (options.contains(Options.CharacterSet)) { + performSimpleTestWithCharacterSet(jdbcUrl); - performTestForCharacterEncodingForInitialScriptConnection(jdbcUrl); - } + performTestForCharacterEncodingForInitialScriptConnection(dataSource); + } - if (options.contains(Options.CustomIniFile)) { - performTestForCustomIniFile(jdbcUrl); + if (options.contains(Options.CustomIniFile)) { + performTestForCustomIniFile(dataSource); + } } } - private void performSimpleTest(String jdbcUrl) throws SQLException { - try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) { - boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)).query("SELECT 1", rs -> { - rs.next(); - int resultSetInt = rs.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - return true; - }); - - assertTrue("The database returned a record as expected", result); - } - } + private void performSimpleTest(HikariDataSource dataSource) throws SQLException { + boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)).query("SELECT 1", rs -> { + rs.next(); + int resultSetInt = rs.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + return true; + }); - private void performTestForScriptedSchema(String jdbcUrl) throws SQLException { - try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) { - boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%world'", rs -> { - rs.next(); - String resultSetString = rs.getString(1); - assertEquals("A basic SELECT query succeeds where the schema has been applied from a script", "hello world", resultSetString); - return true; - }); - } + assertTrue("The database returned a record as expected", result); } - private void performTestForJDBCParamUsage(String jdbcUrl) throws SQLException { - try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) { - boolean result = new QueryRunner(dataSource).query("select CURRENT_USER", rs -> { - rs.next(); - String resultUser = rs.getString(1); - // Not all databases (eg. Postgres) return @% at the end of user name. We just need to make sure the user name matches. - if (resultUser.endsWith("@%")) { - resultUser = resultUser.substring(0, resultUser.length() - 2); - } - assertEquals("User from query param is created.", "someuser", resultUser); - return true; - }); + private void performTestForScriptedSchema(HikariDataSource dataSource) throws SQLException { + boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%world'", rs -> { + rs.next(); + String resultSetString = rs.getString(1); + assertEquals("A basic SELECT query succeeds where the schema has been applied from a script", "hello world", resultSetString); + return true; + }); - assertTrue("The database returned a record as expected", result); + assertTrue("The database returned a record as expected", result); + } - String databaseQuery = "SELECT DATABASE()"; - // Postgres does not have Database() as a function - String databaseType = ConnectionUrl.newInstance(jdbcUrl).getDatabaseType(); - if (databaseType.equalsIgnoreCase("postgresql") || databaseType.equalsIgnoreCase("postgis")) { - databaseQuery = "SELECT CURRENT_DATABASE()"; + private void performTestForJDBCParamUsage(HikariDataSource dataSource) throws SQLException { + boolean result = new QueryRunner(dataSource).query("select CURRENT_USER", rs -> { + rs.next(); + String resultUser = rs.getString(1); + // Not all databases (eg. Postgres) return @% at the end of user name. We just need to make sure the user name matches. + if (resultUser.endsWith("@%")) { + resultUser = resultUser.substring(0, resultUser.length() - 2); } + assertEquals("User from query param is created.", "someuser", resultUser); + return true; + }); - result = new QueryRunner(dataSource).query(databaseQuery, rs -> { - rs.next(); - String resultDB = rs.getString(1); - assertEquals("Database name from URL String is used.", "databasename", resultDB); - return true; - }); + assertTrue("The database returned a record as expected", result); - assertTrue("The database returned a record as expected", result); + String databaseQuery = "SELECT DATABASE()"; + // Postgres does not have Database() as a function + String databaseType = ConnectionUrl.newInstance(jdbcUrl).getDatabaseType(); + if (databaseType.equalsIgnoreCase("postgresql") || databaseType.equalsIgnoreCase("postgis")) { + databaseQuery = "SELECT CURRENT_DATABASE()"; } + + result = new QueryRunner(dataSource).query(databaseQuery, rs -> { + rs.next(); + String resultDB = rs.getString(1); + assertEquals("Database name from URL String is used.", "databasename", resultDB); + return true; + }); + + assertTrue("The database returned a record as expected", result); } - private void performTestForCharacterEncodingForInitialScriptConnection(String jdbcUrl) throws SQLException { - try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) { - boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%мир'", rs -> { - rs.next(); - String resultSetString = rs.getString(1); - assertEquals("A SELECT query succeed and the correct charset has been applied for the init script", "привет мир", resultSetString); - return true; - }); + private void performTestForCharacterEncodingForInitialScriptConnection(HikariDataSource dataSource) throws SQLException { + boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%мир'", rs -> { + rs.next(); + String resultSetString = rs.getString(1); + assertEquals("A SELECT query succeed and the correct charset has been applied for the init script", "привет мир", resultSetString); + return true; + }); - assertTrue("The database returned a record as expected", result); - } + assertTrue("The database returned a record as expected", result); } /** @@ -207,18 +199,16 @@ private HikariDataSource verifyCharacterSet(String jdbcUrl) throws SQLException return dataSource; } - private void performTestForCustomIniFile(final String jdbcUrl) throws SQLException { + private void performTestForCustomIniFile(HikariDataSource dataSource) throws SQLException { assumeFalse(SystemUtils.IS_OS_WINDOWS); - try (HikariDataSource ds = getDataSource(jdbcUrl, 1)) { - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT @@GLOBAL.innodb_file_format"); - ResultSet resultSet = statement.getResultSet(); + Statement statement = dataSource.getConnection().createStatement(); + statement.execute("SELECT @@GLOBAL.innodb_file_format"); + ResultSet resultSet = statement.getResultSet(); - assertTrue("The query returns a result", resultSet.next()); - String result = resultSet.getString(1); + assertTrue("The query returns a result", resultSet.next()); + String result = resultSet.getString(1); - assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result); - } + assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result); } private HikariDataSource getDataSource(String jdbcUrl, int poolSize) { diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverWithPoolTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverWithPoolTest.java index c40721223b0..53daa1316f5 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverWithPoolTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverWithPoolTest.java @@ -1,6 +1,5 @@ package org.testcontainers.jdbc; -import com.googlecode.junittoolbox.ParallelParameterized; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.apache.commons.dbutils.QueryRunner; @@ -25,7 +24,7 @@ /** * */ -@RunWith(ParallelParameterized.class) +@RunWith(Parameterized.class) public class JDBCDriverWithPoolTest { public static final String URL = "jdbc:tc:mysql:5://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverWithPoolTest::sampleInitFunction"; From 68d538937ff9d329cb55ca8f7ea2d6390ae80abf Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 9 Jul 2019 10:39:13 +0200 Subject: [PATCH 0141/4969] Allocate lower shared memory in tests (#1597) --- .../testcontainers/junit/GenericContainerRuleTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index a991ebcf60a..6bbd71961a6 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -403,15 +403,13 @@ public void addExposedPortAfterWithExposedPortsTest() { @Test public void sharedMemorySetTest() { - try (GenericContainer containerWithSharedMemory = new GenericContainer("busybox:1.29") - .withSharedMemorySize(1024L * FileUtils.ONE_MB)) { + try (GenericContainer containerWithSharedMemory = new GenericContainer() + .withSharedMemorySize(42L * FileUtils.ONE_MB)) { containerWithSharedMemory.start(); - HostConfig hostConfig = - containerWithSharedMemory.getDockerClient().inspectContainerCmd(containerWithSharedMemory.getContainerId()) - .exec().getHostConfig(); - assertEquals("Shared memory not set on container", hostConfig.getShmSize(), 1024 * FileUtils.ONE_MB); + HostConfig hostConfig = containerWithSharedMemory.getContainerInfo().getHostConfig(); + assertEquals("Shared memory not set on container", hostConfig.getShmSize(), 42L * FileUtils.ONE_MB); } } } From 30574ef7a0aec19223c63d52702c4d5b0a478dfc Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 9 Jul 2019 10:44:33 +0100 Subject: [PATCH 0142/4969] Module contribution policy (#1576) --- CONTRIBUTING.md | 16 ++------- docs/contributing.md | 80 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9a9f1e43b55..ffa95a477db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,5 @@ # Contributing -* Star the project on [Github](https://github.com/testcontainers/testcontainers-java) and help spread the word :) -* Join our Slack: http://slack.testcontainers.org -* [Post an issue](https://github.com/testcontainers/testcontainers-java/issues) if you find any bugs -* Contribute improvements or fixes using a [Pull Request](https://github.com/testcontainers/testcontainers-java/pulls). If you're going to contribute, thank you! Please just be sure to: - * discuss with the authors on an issue ticket prior to doing anything big - * follow the style, naming and structure conventions of the rest of the project - * make commits atomic and easy to merge - * verify all tests are passing. Build the project with `./gradlew check` to do this - - **PS:** Make sure Docker is running locally and you have the lombok plugin installed in your IDE - - **N.B.** Gradle's Build Cache is enabled by default, but you can add `--no-build-cache` flag to disable it. - +Please see the [main contributing guidelines](./docs/contributing.md). + +There are additional docs describing [contributing documentation changes](./docs/contributing_docs.md). diff --git a/docs/contributing.md b/docs/contributing.md index 96ba5975aeb..9d2c63b030c 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -10,3 +10,83 @@ * when updating documentation, please see [our guidance for documentation contributions](contributing_docs.md). * verify all tests are passing. Build the project with `./gradlew check` to do this. **N.B.** Gradle's Build Cache is enabled by default, but you can add `--no-build-cache` flag to disable it. + +## Contributing new modules + +We often receive proposals (or fully formed PRs) for new modules. +We're very happy to have contributions, but new modules require specific extra care. We want to balance: + +* Usefulness of the module. +* Our ability to support the module in the future, potentially after contributors have moved on. +* Contributors time, so that nobody puts in wasted effort. + +### Does it need to be a module? + +*N.B. this is not a perfect list - please always reach out to us before starting on a module contribution!* + +* Does the module enable use of Testcontainers with a popular or rapidly growing technology? +* Does the module 'add value' beyond a `GenericContainer` code snippet/example? e.g. + * does it neatly encapsulate a difficult problem of running the program in a container? + * does it add technology-specific [wait strategies](features/startup_and_waits.md)? + * does it enable straightforward usage of client libraries? + +If the answers to the above are all yes, then a new module may be a good approach. + +Otherwise, it is entirely possible for you to: + +* publish a code snippet +* contribute an [example](../examples/README.md) to the Testcontainers repo +* publish your own third party library + +In any case, please contact us to help validate your proposal! + +### Checklist + +*Suggestion: copy and paste this list into PRs for new modules.* + +Every item on this list will require judgement by the Testcontainers core maintainers. Exceptions will sometimes be possible; items with `should` are more likely to be negotiable than those items with `must`. + +#### Default docker image + +- [ ] Should be a Docker Hub official image, or published by a reputable source (ideally the company or organisation that officially supports the technology) +- [ ] Should have a verifiable open source Dockerfile and a way to view the history of changes +- [ ] MUST show general good practices regarding container image tagging - e.g. we do not use `latest` tags, and we do not use tags that may be mutated in the future +- [ ] MUST be legal for Testcontainers developers and Testcontainers users to pull and use. Mechanisms exist to allow EULA acceptance to be signalled, but images that can be used without a licence are greatly preferred. + +#### Module dependencies + +- [ ] The module should use as few dependencies as possible, +- [ ] Regarding libraries, either: + - they should be `compileOnly` if they are likely to already be on the classpath for users' tests (e.g. client libraries or drivers) + - they can be `implementation` (and thus transitive dependencies) if they are very unlikely to conflict with users' dependencies. +- [ ] If client libraries are used to test or use the module, these MUST be legal for Testcontainers developers and Testcontainers users to download and use. + +#### API (e.g. `MyModuleContainer` class) + +- [ ] Favour doing the right thing, and least surprising thing, by default +- [ ] Ensure that method and parameter names are easy to understand. Many users will ignore documentation, so IDE-based substitutes (autocompletion and Javadocs) should be intuitive. +- [ ] The module's public API should only handle standard JDK data types and MUST not expose data types that come from `compileOnly` dependencies. This is to reduce the risk of compatibility problems with future versions of third party libraries. + +#### Documentation + +- [ ] Every module MUST have a dedicated documentation page containing: + - [ ] A high level overview + - [ ] A usage example + - [ ] If appropriate, basic API documentation or further usage guidelines + - [ ] Dependency information + - [ ] Acknowledgements, if appropriate +- [ ] Consider that many users will not read the documentation pages - even if the first person to add it to a project does, people reading/updating the code in the future may not. Try and avoid the need for critical knowledge that is only present in documentation. + + + +### Incubating modules + +We have a policy of marking new modules as 'incubating' so that we can evaluate its maintainability and usability traits over a longer period of time. +We currently believe 3 months is a fair period of time, but may change this. + +New modules should have the following warning at the top of their documentation pages: + +!!! warning + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. + +We will evaluate incubating modules periodically, and remove the label when appropriate. From 3a0618511293a9e781a2eeb2bb42255a27f8295c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2019 06:28:12 +0000 Subject: [PATCH 0143/4969] Bump tomcat-jdbc from 9.0.21 to 9.0.22 in /modules/mariadb (#1600) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 0068368b8a3..a501b44f04d 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.2' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.21' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.22' testCompile 'org.vibur:vibur-dbcp:22.2' } From d681aeef6f0d2987b6126dbc7382d6eb83fb7f3b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2019 07:29:15 +0000 Subject: [PATCH 0144/4969] Bump tomcat-jdbc from 9.0.21 to 9.0.22 in /modules/mysql (#1599) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index e2b1b416400..2540df73c3f 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.16' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.21' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.22' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From 8f1421ad5310f75f371804c3a3a1402b0eaab6d4 Mon Sep 17 00:00:00 2001 From: "Roman S.A" Date: Mon, 15 Jul 2019 11:38:23 +0300 Subject: [PATCH 0145/4969] Kotlin example (#1521) * add example using spring-boot + kotlin + kafka * add project to settings.gradle * using Gradle DSL instead Kotlin DSL * using redis container instead kafka * cleanups --- examples/settings.gradle | 3 +- .../spring-boot-kotlin-redis/build.gradle | 28 ++++++++++++++ .../com/example/redis/ExampleController.kt | 27 ++++++++++++++ .../com/example/redis/RedisApplication.kt | 11 ++++++ .../example/redis/AbstractIntegrationTest.kt | 37 +++++++++++++++++++ .../example/redis/RedisApplicationTests.kt | 11 ++++++ .../kotlin/com/example/redis/RedisTest.kt | 29 +++++++++++++++ 7 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 examples/spring-boot-kotlin-redis/build.gradle create mode 100644 examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/ExampleController.kt create mode 100644 examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/RedisApplication.kt create mode 100644 examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt create mode 100644 examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisApplicationTests.kt create mode 100644 examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisTest.kt diff --git a/examples/settings.gradle b/examples/settings.gradle index 3d57c2a18df..9efbf097344 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -12,4 +12,5 @@ include 'selenium-container' include 'singleton-container' include 'spring-boot' include 'cucumber' -include 'spock' +include 'spring-boot-kotlin-redis' +include 'spock' \ No newline at end of file diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle new file mode 100644 index 00000000000..f2d9d8d97ec --- /dev/null +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -0,0 +1,28 @@ +plugins { + id("org.springframework.boot") version "2.1.5.RELEASE" + id("org.jetbrains.kotlin.jvm") version "1.3.31" + id("org.jetbrains.kotlin.plugin.spring") version "1.3.31" +} + +apply plugin: 'io.spring.dependency-management' + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation("org.springframework.boot:spring-boot-starter-data-redis") + implementation("org.springframework.boot:spring-boot-starter-web") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.testcontainers:testcontainers") +} + +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs = ["-Xjsr305=strict"] + } +} \ No newline at end of file diff --git a/examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/ExampleController.kt b/examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/ExampleController.kt new file mode 100644 index 00000000000..bbe3083935e --- /dev/null +++ b/examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/ExampleController.kt @@ -0,0 +1,27 @@ +package com.example.redis + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.redis.core.RedisTemplate +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RestController + +@RestController +class ExampleController { + + private val key = "testcontainers" + + @Autowired + private lateinit var redisTemplate: RedisTemplate + + @PostMapping("/set-foo") + fun setFoo(@RequestBody value: String) { + redisTemplate.opsForValue().set(key, value) + } + + @GetMapping("/get-foo") + fun getFoo(): String? { + return redisTemplate.opsForValue().get(key) + } +} diff --git a/examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/RedisApplication.kt b/examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/RedisApplication.kt new file mode 100644 index 00000000000..dc06c8004bf --- /dev/null +++ b/examples/spring-boot-kotlin-redis/src/main/kotlin/com/example/redis/RedisApplication.kt @@ -0,0 +1,11 @@ +package com.example.redis + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication +class RedisApplication + +fun main(args: Array) { + runApplication(*args) +} diff --git a/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt new file mode 100644 index 00000000000..dc8b0bf9e68 --- /dev/null +++ b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt @@ -0,0 +1,37 @@ +package com.example.redis + +import org.junit.runner.RunWith +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.util.TestPropertyValues +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit4.SpringRunner +import org.testcontainers.containers.GenericContainer + +@RunWith(SpringRunner::class) +@SpringBootTest +@ContextConfiguration(initializers = [AbstractIntegrationTest.Initializer::class]) +@AutoConfigureMockMvc +abstract class AbstractIntegrationTest { + + companion object { + val redisContainer = object : GenericContainer("redis:3-alpine") { + init { + withExposedPorts(6379) + } + } + } + + internal class Initializer : ApplicationContextInitializer { + override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) { + redisContainer.start() + + TestPropertyValues.of( + "spring.redis.host=${redisContainer.containerIpAddress}", + "spring.redis.port=${redisContainer.firstMappedPort}" + ).applyTo(configurableApplicationContext.environment) + } + } +} diff --git a/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisApplicationTests.kt b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisApplicationTests.kt new file mode 100644 index 00000000000..aec5a486120 --- /dev/null +++ b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisApplicationTests.kt @@ -0,0 +1,11 @@ +package com.example.redis + +import org.junit.Test + +class RedisApplicationTests : AbstractIntegrationTest() { + + @Test + fun contextLoads() { + } + +} diff --git a/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisTest.kt b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisTest.kt new file mode 100644 index 00000000000..317916bd3e6 --- /dev/null +++ b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/RedisTest.kt @@ -0,0 +1,29 @@ +package com.example.redis + +import org.hamcrest.CoreMatchers.containsString +import org.junit.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.test.web.servlet.setup.MockMvcBuilders + + +class RedisTest : AbstractIntegrationTest() { + + @Autowired + private lateinit var mockMvc: MockMvc + + @Test + fun testRedisFunctionality() { + val greeting = "Hello Testcontainers with Kotlin" + mockMvc.perform(post("/set-foo").content(greeting)) + .andExpect(status().isOk) + + mockMvc.perform(get("/get-foo")) + .andExpect(status().isOk) + .andExpect(content().string(containsString(greeting))) + } +} From 0ccadb75402b6f4e994c90293ced152331bcd46c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2019 06:30:38 +0000 Subject: [PATCH 0146/4969] Bump cucumber-junit from 4.5.1 to 4.5.4 in /examples (#1614) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 505aad82ae4..733a2e6a8b7 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.5.1' - testImplementation 'io.cucumber:cucumber-junit:4.5.1' + testImplementation 'io.cucumber:cucumber-junit:4.5.4' testImplementation 'org.testcontainers:selenium' } From fb1e91c71d44d6ffbd0f395b3eac0547e39eb581 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2019 07:58:06 +0000 Subject: [PATCH 0147/4969] Bump cucumber-java from 4.5.1 to 4.5.4 in /examples (#1615) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 733a2e6a8b7..fb3a1ae875c 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.5.1' + implementation 'io.cucumber:cucumber-java:4.5.4' testImplementation 'io.cucumber:cucumber-junit:4.5.4' testImplementation 'org.testcontainers:selenium' } From 3dc9d9dc3a1d03b87707d6bff6a95e0fbf0a4510 Mon Sep 17 00:00:00 2001 From: Andrew Guibert Date: Tue, 16 Jul 2019 04:48:56 -0500 Subject: [PATCH 0148/4969] Add DB2 module (#1611) * Add db2 jdbc module * Update Db2Container to use ibmcom/db2 image * Add doc page on DB2 module * Resolve review comments --- docs/modules/databases/db2.md | 47 +++++++ modules/db2/build.gradle | 5 + .../containers/Db2Container.java | 129 ++++++++++++++++++ .../containers/Db2ContainerProvider.java | 18 +++ ...s.containers.JdbcDatabaseContainerProvider | 1 + modules/jdbc-test/build.gradle | 2 + .../testcontainers/jdbc/JDBCDriverTest.java | 8 +- .../testcontainers/junit/SimpleDb2Test.java | 39 ++++++ .../container-license-acceptance.txt | 1 + .../testcontainers/jdbc/ConnectionUrl.java | 2 +- 10 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 docs/modules/databases/db2.md create mode 100644 modules/db2/build.gradle create mode 100644 modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java create mode 100644 modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java create mode 100644 modules/db2/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java diff --git a/docs/modules/databases/db2.md b/docs/modules/databases/db2.md new file mode 100644 index 00000000000..b7871e636d0 --- /dev/null +++ b/docs/modules/databases/db2.md @@ -0,0 +1,47 @@ +# DB2 Module + +See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. + +## Usage example + +Running DB2 as a stand-in for in a test: + +```java +public class SomeTest { + + @ClassRule + public Db2Container db2 = new Db2Container() + .acceptLicense(); + + @Test + public void someTestMethod() { + String url = db2.getJdbcUrl(); + + ... create a connection and run test as normal + } +``` + +!!! warning "EULA Acceptance" + Due to licencing restrictions you are required to accept an EULA for this container image. To indicate that you accept the DB2 image EULA, call the `acceptLicense()` method, or place a file at the root of the classpath named `container-license-acceptance.txt`, e.g. at `src/test/resources/container-license-acceptance.txt`. This file should contain the line: `ibmcom/db2:11.5.0.0a` (or, if you are overriding the docker image name/tag, update accordingly). + + Please see the [`ibmcom/db2` image documentation](https://hub.docker.com/r/ibmcom/db2) for a link to the EULA document. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:db2:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + db2 + {{latest_version}} + test + +``` + +!!! hint + Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/modules/db2/build.gradle b/modules/db2/build.gradle new file mode 100644 index 00000000000..a92631df264 --- /dev/null +++ b/modules/db2/build.gradle @@ -0,0 +1,5 @@ +description = "Testcontainers :: JDBC :: DB2" + +dependencies { + compile project(':jdbc') +} diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java new file mode 100644 index 00000000000..6e45b0f7f12 --- /dev/null +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -0,0 +1,129 @@ +package org.testcontainers.containers; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.WaitingConsumer; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.LicenseAcceptance; +import org.testcontainers.utility.LogUtils; + +import java.io.IOException; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; + +public class Db2Container extends JdbcDatabaseContainer { + + public static final String NAME = "db2"; + public static final String DEFAULT_DB2_IMAGE_NAME = "ibmcom/db2"; + public static final String DEFAULT_TAG = "11.5.0.0a"; + public static final int DB2_PORT = 50000; + + private String databaseName = "test"; + private String username = "db2inst1"; + private String password = "foobar1234"; + + public Db2Container() { + this(DEFAULT_DB2_IMAGE_NAME + ":" + DEFAULT_TAG); + } + + public Db2Container(String imageName) { + super(imageName); + withPrivilegedMode(true); + this.waitStrategy = new LogMessageWaitStrategy() + .withRegEx(".*Setup has completed\\..*") + .withStartupTimeout(Duration.of(3, ChronoUnit.MINUTES)); + } + + @Override + protected Set getLivenessCheckPorts() { + return new HashSet<>(getMappedPort(DB2_PORT)); + } + + @Override + protected void configure() { + // If license was not accepted programatically, check if it was accepted via resource file + if (!getEnvMap().containsKey("LICENSE")) { + LicenseAcceptance.assertLicenseAccepted(this.getDockerImageName()); + acceptLicense(); + } + + addExposedPort(DB2_PORT); + + addEnv("DBNAME", databaseName); + addEnv("DB2INSTANCE", username); + addEnv("DB2INST1_PASSWORD", password); + + // These settings help the DB2 container start faster + if (!getEnvMap().containsKey("AUTOCONFIG")) + addEnv("AUTOCONFIG", "false"); + if (!getEnvMap().containsKey("ARCHIVE_LOGS")) + addEnv("ARCHIVE_LOGS", "false"); + } + + /** + * Accepts the license for the DB2 container by setting the LICENSE=accept + * variable as described at https://hub.docker.com/r/ibmcom/db2 + */ + public Db2Container acceptLicense() { + addEnv("LICENSE", "accept"); + return this; + } + + @Override + public String getDriverClassName() { + return "com.ibm.db2.jcc.DB2Driver"; + } + + @Override + public String getJdbcUrl() { + return "jdbc:db2://" + getContainerIpAddress() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getDatabaseName() { + return databaseName; + } + + @Override + public Db2Container withUsername(String username) { + this.username = username; + return this; + } + + @Override + public Db2Container withPassword(String password) { + this.password = password; + return this; + } + + @Override + public Db2Container withDatabaseName(String dbName) { + this.databaseName = dbName; + return this; + } + + @Override + protected void waitUntilContainerStarted() { + getWaitStrategy().waitUntilReady(this); + } + + @Override + protected String getTestQueryString() { + return "SELECT 1 FROM SYSIBM.SYSDUMMY1"; + } +} diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java new file mode 100644 index 00000000000..5c78fdc0505 --- /dev/null +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java @@ -0,0 +1,18 @@ +package org.testcontainers.containers; + +public class Db2ContainerProvider extends JdbcDatabaseContainerProvider { + @Override + public boolean supports(String databaseType) { + return databaseType.equals(Db2Container.NAME); + } + + @Override + public JdbcDatabaseContainer newInstance() { + return newInstance(Db2Container.DEFAULT_TAG); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new Db2Container(Db2Container.DEFAULT_DB2_IMAGE_NAME + ":" + tag); + } +} diff --git a/modules/db2/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/db2/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..d433ae9fc82 --- /dev/null +++ b/modules/db2/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.containers.Db2ContainerProvider diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 4c7ab8b0974..5874787e9eb 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -11,6 +11,7 @@ dependencies { compile project(':oracle-xe') compile project(':mssqlserver') compile project(':clickhouse') + compile project(':db2') testCompile 'com.google.guava:guava:18.0' testCompile 'org.postgresql:postgresql:42.0.0' @@ -19,6 +20,7 @@ dependencies { testCompile 'com.oracle:ojdbc6:12.1.0.1-atlassian-hosted' testCompile 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8' testCompile 'ru.yandex.clickhouse:clickhouse-jdbc:0.1.41' + testCompile 'com.ibm.db2:jcc:11.1.4.4' testCompile 'com.zaxxer:HikariCP-java6:2.3.8' testCompile 'org.apache.tomcat:tomcat-jdbc:8.5.4' diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index 30b224ab6a6..0508a54e13d 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -65,6 +65,7 @@ public static Iterable data() { {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", EnumSet.of(Options.CustomIniFile)}, {"jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken)}, {"jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)}, }); } @@ -109,7 +110,12 @@ public void test() throws SQLException { } private void performSimpleTest(HikariDataSource dataSource) throws SQLException { - boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)).query("SELECT 1", rs -> { + String query = "SELECT 1"; + if (jdbcUrl.startsWith("jdbc:tc:db2:")) { + query = "SELECT 1 FROM SYSIBM.SYSDUMMY1"; + } + + boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)).query(query, rs -> { rs.next(); int resultSetInt = rs.getInt(1); assertEquals("A basic SELECT query succeeds", 1, resultSetInt); diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java new file mode 100644 index 00000000000..c686f979b79 --- /dev/null +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java @@ -0,0 +1,39 @@ +package org.testcontainers.junit; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.containers.Db2Container; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + + +public class SimpleDb2Test { + + @Rule + public Db2Container db2 = new Db2Container() + .acceptLicense(); + + @Test + public void testSimple() throws SQLException { + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setJdbcUrl(db2.getJdbcUrl()); + hikariConfig.setUsername(db2.getUsername()); + hikariConfig.setPassword(db2.getPassword()); + + HikariDataSource ds = new HikariDataSource(hikariConfig); + Statement statement = ds.getConnection().createStatement(); + statement.execute("SELECT 1 FROM SYSIBM.SYSDUMMY1"); + ResultSet resultSet = statement.getResultSet(); + + resultSet.next(); + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + +} diff --git a/modules/jdbc-test/src/test/resources/container-license-acceptance.txt b/modules/jdbc-test/src/test/resources/container-license-acceptance.txt index 8a704b9c066..4af979f0f18 100644 --- a/modules/jdbc-test/src/test/resources/container-license-acceptance.txt +++ b/modules/jdbc-test/src/test/resources/container-license-acceptance.txt @@ -1 +1,2 @@ mcr.microsoft.com/mssql/server:2017-CU12 +ibmcom/db2:11.5.0.0a diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java index 36206b89d82..e236d723c82 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java @@ -203,7 +203,7 @@ public Map getTmpfsOptions() { * @author manikmagar */ public interface Patterns { - Pattern URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z]+)(:([^:]+))?://([^\\?]+)(\\?.*)?"); + Pattern URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z0-9]+)(:([^:]+))?://([^\\?]+)(\\?.*)?"); Pattern ORACLE_URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z]+)(:([^(thin:)]+))?:thin:@([^\\?]+)(\\?.*)?"); From 371b32566ddb76e8779c802ae1ffa9afafdf5b59 Mon Sep 17 00:00:00 2001 From: Chung Nguyen Date: Tue, 16 Jul 2019 17:13:44 +0700 Subject: [PATCH 0149/4969] catch exception when try to kill dead container (#1420) Fixes #1379 --- .../java/org/testcontainers/utility/ResourceReaper.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 46550dc0af7..086cac83206 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.ConflictException; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; @@ -231,6 +232,12 @@ private void stopContainer(String containerId, String imageName) { LOGGER.trace("Stopping container: {}", containerId); dockerClient.killContainerCmd(containerId).exec(); LOGGER.trace("Stopped container: {}", imageName); + } catch (ConflictException e) { + if ( e.getMessage().startsWith("Cannot kill container: ") && e.getMessage().endsWith(containerId + " is not running")) { + LOGGER.trace("Was going to kill the container but it apparently already dead : {}", e.getMessage()); + } else { + throw e; + } } catch (DockerException e) { LOGGER.trace("Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped: {}", containerId, e.getMessage()); } From 041d5084c407d859f8740e052e1e9a36b080d2ea Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 16 Jul 2019 12:10:21 +0100 Subject: [PATCH 0150/4969] Upgrade localstack and enable new services (#1504) * Add new services to the enum Note: Some services need a newer Localstack version * Upgrade Localstack and alter endpoint URL generation to be IP-only Also extend basic tests to cover SQS * Describe rationale for adding new Localstack tests (or not) (#1509) * Update localstack to 0.9.4 --- modules/localstack/build.gradle | 1 + .../localstack/LocalStackContainer.java | 49 +++++----- .../localstack/SimpleLocalstackS3Test.java | 52 ----------- .../localstack/SimpleLocalstackTest.java | 93 +++++++++++++++++++ 4 files changed, 117 insertions(+), 78 deletions(-) delete mode 100644 modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackS3Test.java create mode 100644 modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 18a410ef1a8..e5e3efb5de3 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,4 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.479' } diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 319581e9f31..1bf0e18627d 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -28,7 +28,7 @@ */ public class LocalStackContainer extends GenericContainer { - public static final String VERSION = "0.8.6"; + public static final String VERSION = "0.9.4"; private final List services = new ArrayList<>(); @@ -82,20 +82,11 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service s final String address = getContainerIpAddress(); String ipAddress = address; try { + // resolve IP address and use that as the endpoint so that path-style access is automatically used for S3 ipAddress = InetAddress.getByName(address).getHostAddress(); } catch (UnknownHostException ignored) { } - ipAddress = ipAddress + ".nip.io"; - while (true) { - try { - //noinspection ResultOfMethodCallIgnored - InetAddress.getAllByName(ipAddress); - break; - } catch (UnknownHostException ignored) { - - } - } return new AwsClientBuilder.EndpointConfiguration( "http://" + @@ -123,23 +114,29 @@ public AWSCredentialsProvider getDefaultCredentialsProvider() { @Getter @FieldDefaults(makeFinal = true) public enum Service { - API_GATEWAY("apigateway", 4567), - KINESIS("kinesis", 4568), - DYNAMODB("dynamodb", 4569), - DYNAMODB_STREAMS("dynamodbstreams", 4570), + API_GATEWAY("apigateway", 4567), + KINESIS("kinesis", 4568), + DYNAMODB("dynamodb", 4569), + DYNAMODB_STREAMS("dynamodbstreams", 4570), // TODO: Clarify usage for ELASTICSEARCH and ELASTICSEARCH_SERVICE // ELASTICSEARCH("es", 4571), - S3("s3", 4572), - FIREHOSE("firehose", 4573), - LAMBDA("lambda", 4574), - SNS("sns", 4575), - SQS("sqs", 4576), - REDSHIFT("redshift", 4577), -// ELASTICSEARCH_SERVICE("", 4578), - SES("ses", 4579), - ROUTE53("route53", 4580), - CLOUDFORMATION("cloudformation", 4581), - CLOUDWATCH("cloudwatch", 4582); + S3("s3", 4572), + FIREHOSE("firehose", 4573), + LAMBDA("lambda", 4574), + SNS("sns", 4575), + SQS("sqs", 4576), + REDSHIFT("redshift", 4577), + // ELASTICSEARCH_SERVICE("", 4578), + SES("ses", 4579), + ROUTE53("route53", 4580), + CLOUDFORMATION("cloudformation", 4581), + CLOUDWATCH("cloudwatch", 4582), + SSM("ssm", 4583), + SECRETSMANAGER("secretsmanager", 4584), + STEPFUNCTIONS("stepsfunctions", 4585), + CLOUDWATCHLOGS("cloudwatchlogs", 4586), + STS("sts", 4592), + IAM("iam", 4593); String localStackName; diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackS3Test.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackS3Test.java deleted file mode 100644 index f00423d31b7..00000000000 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackS3Test.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.testcontainers.containers.localstack; - - -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import com.amazonaws.services.s3.model.Bucket; -import com.amazonaws.services.s3.model.ObjectListing; -import com.amazonaws.services.s3.model.S3Object; -import org.apache.commons.io.IOUtils; -import org.junit.Rule; -import org.junit.Test; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.List; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; - -public class SimpleLocalstackS3Test { - - @Rule - public LocalStackContainer localstack = new LocalStackContainer() - .withServices(S3); - - @Test - public void s3Test() throws IOException { - AmazonS3 s3 = AmazonS3ClientBuilder - .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) - .withCredentials(localstack.getDefaultCredentialsProvider()) - .build(); - - s3.createBucket("foo"); - s3.putObject("foo", "bar", "baz"); - - final List buckets = s3.listBuckets(); - assertEquals("The created bucket is present", 1, buckets.size()); - final Bucket bucket = buckets.get(0); - - assertEquals("The created bucket has the right name", "foo", bucket.getName()); - assertEquals("The created bucket has the right name", "foo", bucket.getName()); - - final ObjectListing objectListing = s3.listObjects("foo"); - assertEquals("The created bucket has 1 item in it", 1, objectListing.getObjectSummaries().size()); - - final S3Object object = s3.getObject("foo", "bar"); - final String content = IOUtils.toString(object.getObjectContent(), Charset.forName("UTF-8")); - assertEquals("The object can be retrieved", "baz", content); - - } -} diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java new file mode 100644 index 00000000000..f3495d2d8b6 --- /dev/null +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java @@ -0,0 +1,93 @@ +package org.testcontainers.containers.localstack; + + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.Bucket; +import com.amazonaws.services.s3.model.ObjectListing; +import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.sqs.AmazonSQS; +import com.amazonaws.services.sqs.AmazonSQSClientBuilder; +import com.amazonaws.services.sqs.model.CreateQueueResult; +import com.amazonaws.services.sqs.model.Message; +import org.apache.commons.io.IOUtils; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Set; + +import static java.util.stream.Collectors.toSet; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; + +/** + * The only tests that should go here are for those Localstack services that require special testcontainers code to work with them. + * For example, S3 needs a test to ensure special HTTP routing to the S3 container works. + */ +public class SimpleLocalstackTest { + + private static final String BUCKET_1 = "bucket1"; + private static final String BUCKET_2 = "bucket2"; + private static final String ITEM_KEY = "bar"; + private static final String DUMMY_CONTENT = "baz"; + + @ClassRule + public static LocalStackContainer localstack = new LocalStackContainer() + .withServices(S3, SQS); + + @Test + public void simpleS3Test() throws IOException { + AmazonS3 s3 = AmazonS3ClientBuilder + .standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) + .withCredentials(localstack.getDefaultCredentialsProvider()) + .build(); + + s3.createBucket(BUCKET_1); + s3.putObject(BUCKET_1, ITEM_KEY, DUMMY_CONTENT); + + s3.createBucket(BUCKET_2); + s3.putObject(BUCKET_2, ITEM_KEY, DUMMY_CONTENT); + + final Set bucketNames = s3.listBuckets().stream() + .map(Bucket::getName) + .collect(toSet()); + assertTrue("The created buckets have the right name", + bucketNames.contains(BUCKET_1) && bucketNames.contains(BUCKET_2)); + + assertBucketContentsCorrect(s3, BUCKET_1); + assertBucketContentsCorrect(s3, BUCKET_2); + } + + private void assertBucketContentsCorrect(AmazonS3 s3, String bucketName) throws IOException { + final ObjectListing objectListing1 = s3.listObjects(bucketName); + assertEquals("The created bucket has 1 item in it", 1, objectListing1.getObjectSummaries().size()); + + final S3Object object = s3.getObject(bucketName, ITEM_KEY); + final String content = IOUtils.toString(object.getObjectContent(), StandardCharsets.UTF_8); + assertEquals("The object can be retrieved", DUMMY_CONTENT, content); + } + + @Test + public void simpleSQSTest() { + AmazonSQS sqs = AmazonSQSClientBuilder.standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(SQS)) + .withCredentials(localstack.getDefaultCredentialsProvider()) + .build(); + + CreateQueueResult queueResult = sqs.createQueue("baz"); + String queueUrl = queueResult.getQueueUrl(); + + sqs.sendMessage(queueUrl, "ping"); + + final List messages = sqs.receiveMessage(queueUrl).getMessages(); + + assertTrue("the message queue contains a message", messages.size() > 0); + assertEquals("the first message is the one we sent", "ping", messages.get(0).getBody()); + } +} From 60b91b0b5b9331c5adfaddcf030d984033131c40 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 16 Jul 2019 13:12:45 +0200 Subject: [PATCH 0151/4969] Split AZP config into jobs rather than steps (#1613) * Split AZP config into jobs rather than steps * fix the modules task --- azure-pipelines.yml | 53 +++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index abcd155010d..d6efa593dcb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,21 +1,36 @@ -steps: -- task: Gradle@2 - displayName: Build core - inputs: - gradleWrapperFile: 'gradlew' - jdkVersionOption: '1.11' - options: '--no-daemon --continue' - tasks: 'testcontainers:check' - publishJUnitResults: true - testResultsFiles: '**/TEST-*.xml' -- task: Gradle@2 - displayName: Build modules - inputs: - gradleWrapperFile: 'gradlew' - jdkVersionOption: '1.11' - options: '--no-daemon --continue -x testcontainers:check' - tasks: 'check' - publishJUnitResults: true - testResultsFiles: '**/TEST-*.xml' +jobs: +- job: core + steps: + - task: Gradle@2 + displayName: Build & test + inputs: + gradleWrapperFile: 'gradlew' + jdkVersionOption: '1.11' + options: '--no-daemon --continue' + tasks: 'testcontainers:check' + publishJUnitResults: true + testResultsFiles: '**/TEST-*.xml' +- job: jdbc + steps: + - task: Gradle@2 + displayName: Build & test + inputs: + gradleWrapperFile: 'gradlew' + jdkVersionOption: '1.11' + options: '--no-daemon --continue' + tasks: 'jdbc-test:check' + publishJUnitResults: true + testResultsFiles: '**/TEST-*.xml' +- job: modules + steps: + - task: Gradle@2 + displayName: Build & test + inputs: + gradleWrapperFile: 'gradlew' + jdkVersionOption: '1.11' + options: '--continue -x testcontainers:check -x jdbc-test:check' + tasks: 'check' + publishJUnitResults: true + testResultsFiles: '**/TEST-*.xml' From d7852496526c0043a2a5e2c247d2da771bce0313 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 16 Jul 2019 12:56:59 +0100 Subject: [PATCH 0152/4969] Upgrade duct-tape library (#1433) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 30fd4d6167e..ee876f595c1 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -63,7 +63,7 @@ dependencies { compile 'org.apache.commons:commons-compress:1.18' // Added for JDK9 compatibility since it's missing this package compile 'javax.xml.bind:jaxb-api:2.3.1' - compile ('org.rnorth.duct-tape:duct-tape:1.0.7') { + compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') } From 1d6ab93f5881f34c5e9cec75954410fe2ac38e18 Mon Sep 17 00:00:00 2001 From: Wladimir Schmidt Date: Tue, 16 Jul 2019 14:00:41 +0200 Subject: [PATCH 0153/4969] Bumped up default version of Confluent Platform to the current 5.2.1 (Kafka container) (#1446) * Bumped up default version of Confluent Platform to the current 5.2.1 * Update KafkaContainerTest.java --- .../main/java/org/testcontainers/containers/KafkaContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 6396d6bcd7f..b1be94f1e67 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -20,7 +20,7 @@ public class KafkaContainer extends GenericContainer { protected SocatContainer proxy; public KafkaContainer() { - this("4.0.0"); + this("5.2.1"); } public KafkaContainer(String confluentPlatformVersion) { From 03ba4c8f1efbb9308c11ee4340dc5681a9d1fa30 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 16 Jul 2019 13:52:29 +0100 Subject: [PATCH 0154/4969] Make test resilient to timing issues (#1375) * Make test resilient to timing issues * Update ContainerLogsTest.java * Update ContainerLogsTest.java * ignore the failing test * Update ContainerLogsTest.java --- .../containers/output/ContainerLogsTest.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java index f95d5a06850..ad0e4c76ae2 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java @@ -1,5 +1,6 @@ package org.testcontainers.containers.output; +import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; @@ -12,14 +13,26 @@ public class ContainerLogsTest { @Test + @Ignore("fails due to the timing of the shell's decision to flush") public void getLogsReturnsAllLogsToDate() { + try (GenericContainer container = shortLivedContainer()) { + container.start(); + + final String logs = container.getLogs(); + assertEquals("stdout and stderr are reflected in the returned logs", "stdout\nstderr", logs); + } + } + + @Test + public void getLogsContainsBothOutputTypes() { try (GenericContainer container = shortLivedContainer()) { container.start(); // docsGetAllLogs { final String logs = container.getLogs(); // } - assertEquals("stdout and stderr are reflected in the returned logs", "stdout\nstderr", logs); + assertTrue("stdout is reflected in the returned logs", logs.contains("stdout")); + assertTrue("stderr is reflected in the returned logs", logs.contains("stderr")); } } @@ -31,7 +44,7 @@ public void getLogsReturnsStdOutToDate() { // docsGetStdOut { final String logs = container.getLogs(STDOUT); // } - assertEquals("stdout and stderr are reflected in the returned logs", "stdout", logs); + assertTrue("stdout is reflected in the returned logs", logs.contains("stdout")); } } @@ -43,7 +56,7 @@ public void getLogsReturnsStdErrToDate() { // docsGetStdErr { final String logs = container.getLogs(STDERR); // } - assertEquals("stdout and stderr are reflected in the returned logs", "stderr", logs); + assertTrue("stderr is reflected in the returned logs", logs.contains("stderr")); } } From 30af86b8293d8200a50e9a7f1b7ecd873cfdbd45 Mon Sep 17 00:00:00 2001 From: martingreber <31406507+martingreber@users.noreply.github.com> Date: Tue, 16 Jul 2019 23:04:48 +1000 Subject: [PATCH 0155/4969] Add rabbitmq (#1449) * Added RabbitMQ module Added RabbitMQ SSL option * Added SSL option for RabbitMQ * Update modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java Co-Authored-By: martingreber <31406507+martingreber@users.noreply.github.com> * Update modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java Co-Authored-By: martingreber <31406507+martingreber@users.noreply.github.com> * Fixed bug in enabling RabbitMQ plugin * Changed builder methods to return RabbitMQContainer * Replaced org.json with jackson * Removed option to disable plugins. It shouldn't be needed * Removed unused code * Simplified wait condition * Removed unused exception class * Use try with resources for tests * Fixed copy-paste comment bug from the Neo4JContainer. Cheers to the Neo4JContainer author, Michael J. Simons :) * Removed getLivenessCheckPortNumbers() as the super implementation is sufficient * Removed unnecessary wait from test * Refactored methods returning URLs and json string generation * Fixed bug with missing verify_peer option * Restructured code for readability * Add Lightbend to the Who is using list (#1464) * accept image, not tag * Update RabbitMQContainerTest.java --- modules/rabbitmq/build.gradle | 7 + .../containers/RabbitMQContainer.java | 367 ++++++++++++++++++ ...RabbitMQContainerJUnitIntegrationTest.java | 22 ++ .../containers/RabbitMQContainerTest.java | 233 +++++++++++ .../test/resources/certs/ca_certificate.pem | 20 + .../src/test/resources/certs/ca_key.pem | 28 ++ .../resources/certs/client_certificate.pem | 19 + .../src/test/resources/certs/client_key.p12 | Bin 0 -> 2413 bytes .../src/test/resources/certs/client_key.pem | 27 ++ .../resources/certs/server_certificate.pem | 21 + .../src/test/resources/certs/server_key.p12 | Bin 0 -> 2477 bytes .../src/test/resources/certs/server_key.pem | 27 ++ .../src/test/resources/certs/truststore.jks | Bin 0 -> 1130 bytes .../src/test/resources/rabbitmq-custom.conf | 2 + 14 files changed, 773 insertions(+) create mode 100644 modules/rabbitmq/build.gradle create mode 100644 modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java create mode 100644 modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java create mode 100644 modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java create mode 100644 modules/rabbitmq/src/test/resources/certs/ca_certificate.pem create mode 100644 modules/rabbitmq/src/test/resources/certs/ca_key.pem create mode 100644 modules/rabbitmq/src/test/resources/certs/client_certificate.pem create mode 100644 modules/rabbitmq/src/test/resources/certs/client_key.p12 create mode 100644 modules/rabbitmq/src/test/resources/certs/client_key.pem create mode 100644 modules/rabbitmq/src/test/resources/certs/server_certificate.pem create mode 100644 modules/rabbitmq/src/test/resources/certs/server_key.p12 create mode 100644 modules/rabbitmq/src/test/resources/certs/server_key.pem create mode 100644 modules/rabbitmq/src/test/resources/certs/truststore.jks create mode 100644 modules/rabbitmq/src/test/resources/rabbitmq-custom.conf diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle new file mode 100644 index 00000000000..7b9a5274a7e --- /dev/null +++ b/modules/rabbitmq/build.gradle @@ -0,0 +1,7 @@ +description = "TestContainers :: RabbitMQ" + +dependencies { + compile project(":testcontainers") + testCompile "com.rabbitmq:amqp-client:5.7.0" + testCompile 'org.assertj:assertj-core:3.12.2' +} diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java new file mode 100644 index 00000000000..98c2497c2dc --- /dev/null +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -0,0 +1,367 @@ +package org.testcontainers.containers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.jetbrains.annotations.NotNull; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.MountableFile; + +import java.io.IOException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.lang.String.join; +import static java.util.Arrays.asList; + +/** + * Testcontainer for RabbitMQ. + * + * @author Martin Greber + */ +public class RabbitMQContainer extends GenericContainer { + + /** + * The image defaults to the official RabbitmQ image: RabbitMQ. + */ + private static final String DEFAULT_IMAGE_NAME = "rabbitmq"; + private static final String DEFAULT_TAG = "3.7-management-alpine"; + + private static final int DEFAULT_AMQP_PORT = 5672; + private static final int DEFAULT_AMQPS_PORT = 5671; + private static final int DEFAULT_HTTPS_PORT = 15671; + private static final int DEFAULT_HTTP_PORT = 15672; + + private String adminPassword = "guest"; + private String adminUsername = "guest"; + private final List> values = new ArrayList<>(); + + /** + * Creates a Testcontainer using the official RabbitMQ docker image. + */ + public RabbitMQContainer() { + this(DEFAULT_IMAGE_NAME + ":" + DEFAULT_TAG); + } + + /** + * Creates a Testcontainer using a specific docker image. + * + * @param tag The docker image to use. + */ + public RabbitMQContainer(String image) { + super(image); + + addExposedPorts(DEFAULT_AMQP_PORT, DEFAULT_AMQPS_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); + + this.waitStrategy = Wait. + forLogMessage(".*Server startup complete.*", 1) + .withStartupTimeout(Duration.ofSeconds(60)); + } + + @Override + protected void configure() { + if (adminPassword != null) { + addEnv("RABBITMQ_DEFAULT_PASS", adminPassword); + } + } + + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + + values.forEach(command -> { + try { + ExecResult execResult = execInContainer(command.toArray(new String[0])); + if (execResult.getExitCode() != 0) { + logger().error("Could not execute command {}: {}", command, execResult.getStderr()); + } + } catch (IOException | InterruptedException e) { + logger().error("Could not execute command {}: {}", command, e.getMessage()); + } + }); + } + + /** + * @return The admin password for the admin account + */ + public String getAdminPassword() { + return adminPassword; + } + + public String getAdminUsername() { + return adminUsername; + } + + public Integer getAmqpPort() { + return getMappedPort(DEFAULT_AMQP_PORT); + } + + public Integer getAmqpsPort() { + return getMappedPort(DEFAULT_AMQPS_PORT); + } + + public Integer getHttpsPort() { + return getMappedPort(DEFAULT_HTTPS_PORT); + } + + public Integer getHttpPort() { + return getMappedPort(DEFAULT_HTTP_PORT); + } + + /** + * @return AMQP URL for use with AMQP clients. + */ + public String getAmqpUrl() { + return "amqp://" + getContainerIpAddress() + ":" + getAmqpPort(); + } + + /** + * @return AMQPS URL for use with AMQPS clients. + */ + public String getAmqpsUrl() { + return "amqps://" + getContainerIpAddress() + ":" + getAmqpsPort(); + } + + /** + * @return URL of the HTTP management endpoint. + */ + public String getHttpUrl() { + return "http://" + getContainerIpAddress() + ":" + getHttpPort(); + } + + /** + * @return URL of the HTTPS management endpoint. + */ + public String getHttpsUrl() { + return "https://" + getContainerIpAddress() + ":" + getHttpsPort(); + } + + /** + * Sets the password for the admin (default is

guest
) + * + * @param adminPassword The admin password. + * @return This container. + */ + public RabbitMQContainer withAdminPassword(final String adminPassword) { + this.adminPassword = adminPassword; + return this; + } + + public enum SslVerification { + VERIFY_NONE("verify_none"), VERIFY_PEER("verify_peer"); + + SslVerification(String value) { + this.value = value; + } + private final String value; + + } + + public RabbitMQContainer withSSL( + final MountableFile keyFile, + final MountableFile certFile, + final MountableFile caFile, + final SslVerification verify, + boolean failIfNoCert, + int verificationDepth) { + + return withSSL(keyFile, certFile, caFile, verify, failIfNoCert) + .withEnv("RABBITMQ_SSL_DEPTH", String.valueOf(verificationDepth)); + } + + public RabbitMQContainer withSSL( + final MountableFile keyFile, + final MountableFile certFile, + final MountableFile caFile, + final SslVerification verify, + boolean failIfNoCert) { + + return withSSL(keyFile, certFile, caFile, verify) + .withEnv("RABBITMQ_SSL_FAIL_IF_NO_PEER_CERT", String.valueOf(failIfNoCert)); + } + + public RabbitMQContainer withSSL( + final MountableFile keyFile, + final MountableFile certFile, + final MountableFile caFile, + final SslVerification verify) { + + return withEnv("RABBITMQ_SSL_CACERTFILE", "/etc/rabbitmq/ca_cert.pem") + .withEnv("RABBITMQ_SSL_CERTFILE", "/etc/rabbitmq/rabbitmq_cert.pem") + .withEnv("RABBITMQ_SSL_KEYFILE", "/etc/rabbitmq/rabbitmq_key.pem") + .withEnv("RABBITMQ_SSL_VERIFY", verify.value) + .withCopyFileToContainer(certFile, "/etc/rabbitmq/rabbitmq_cert.pem") + .withCopyFileToContainer(caFile, "/etc/rabbitmq/ca_cert.pem") + .withCopyFileToContainer(keyFile, "/etc/rabbitmq/rabbitmq_key.pem"); + } + + public RabbitMQContainer withPluginsEnabled(String... pluginNames) { + List command = new ArrayList<>(asList("rabbitmq-plugins", "enable")); + command.addAll(asList(pluginNames)); + values.add(command); + return self(); + } + + public RabbitMQContainer withBinding(String source, String destination) { + values.add(asList("rabbitmqadmin", "declare", "binding", + "source=" + source, + "destination=" + destination)); + return self(); + } + + public RabbitMQContainer withBinding(String source, String destination, Map arguments, String routingKey, String destinationType) { + values.add(asList("rabbitmqadmin", "declare", "binding", + "source=" + source, + "destination=" + destination, + "routing-key=" + routingKey, + "destination-type=" + destinationType, + "arguments=" + toJson(arguments))); + return self(); + } + + public RabbitMQContainer withParameter(String component, String name, String value) { + values.add(asList("rabbitmqadmin", "declare", "parameter", + "component=" + component, + "name=" + name, + "value=" + value)); + return self(); + } + + public RabbitMQContainer withPermission(String vhost, String user, String configure, String write, String read) { + values.add(asList("rabbitmqadmin", "declare", "permission", + "vhost=" + vhost, + "user=" + user, + "configure=" + configure, + "write=" + write, + "read=" + read)); + return self(); + } + + public RabbitMQContainer withUser(String name, String password) { + values.add(asList("rabbitmqadmin", "declare", "user", + "name=" + name, + "password=" + password, + "tags=")); + return self(); + } + + public RabbitMQContainer withUser(String name, String password, Set tags) { + values.add(asList("rabbitmqadmin", "declare", "user", + "name=" + name, + "password=" + password, + "tags=" + join(",", tags))); + return self(); + } + + public RabbitMQContainer withPolicy(String name, String pattern, Map definition) { + values.add(asList("rabbitmqadmin", "declare", "policy", + "name=" + name, + "pattern=" + pattern, + "definition=" + toJson(definition))); + return self(); + } + + public RabbitMQContainer withPolicy(String name, String pattern, Map definition, int priority, String applyTo) { + values.add(asList("rabbitmqadmin", "declare", "policy", + "name=" + name, + "pattern=" + pattern, + "priority=" + priority, + "apply-to=" + applyTo, + "definition=" + toJson(definition))); + return self(); + } + + public RabbitMQContainer withOperatorPolicy(String name, String pattern, Map definition) { + values.add(new ArrayList<>(asList("rabbitmqadmin", "declare", "operator_policy", + "name=" + name, + "pattern=" + pattern, + "definition=" + toJson(definition)))); + return self(); + } + + public RabbitMQContainer withOperatorPolicy(String name, String pattern, Map definition, int priority, String applyTo) { + values.add(asList("rabbitmqadmin", "declare", "operator_policy", + "name=" + name, + "pattern=" + pattern, + "priority=" + priority, + "apply-to=" + applyTo, + "definition=" + toJson(definition))); + return self(); + } + + public RabbitMQContainer withVhost(String name) { + values.add(asList("rabbitmqadmin", "declare", "vhost", + "name=" + name)); + return self(); + } + + public RabbitMQContainer withVhost(String name, boolean tracing) { + values.add(asList("rabbitmqadmin", "declare", "vhost", + "name=" + name, + "tracing=" + tracing)); + return self(); + } + + public RabbitMQContainer withVhostLimit(String vhost, String name, int value) { + values.add(asList("rabbitmqadmin", "declare", "vhost_limit", + "vhost=" + vhost, + "name=" + name, + "value=" + value)); + return self(); + } + + public RabbitMQContainer withQueue(String name) { + values.add(asList("rabbitmqadmin", "declare", "queue", + "name=" + name)); + return self(); + } + + public RabbitMQContainer withQueue(String name, boolean autoDelete, boolean durable, Map arguments) { + values.add(asList("rabbitmqadmin", "declare", "queue", + "name=" + name, + "auto_delete=" + autoDelete, + "durable=" + durable, + "arguments=" + toJson(arguments))); + return self(); + } + + public RabbitMQContainer withExchange(String name, String type) { + values.add(asList("rabbitmqadmin", "declare", "exchange", + "name=" + name, + "type=" + type)); + return self(); + } + + public RabbitMQContainer withExchange(String name, String type, boolean autoDelete, boolean internal, boolean durable, Map arguments) { + values.add(asList("rabbitmqadmin", "declare", "exchange", + "name=" + name, + "type=" + type, + "auto_delete=" + autoDelete, + "internal=" + internal, + "durable=" + durable, + "arguments=" + toJson(arguments))); + return self(); + } + + /** + * Overwrites the default RabbitMQ configuration file with the supplied one + * + * @param rabbitMQConf The rabbitmq.conf file to use + * @return This container. + */ + public RabbitMQContainer withRabbitMQConfig(MountableFile rabbitMQConf) { + withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom.conf"); + return withCopyFileToContainer(rabbitMQConf, "/etc/rabbitmq/rabbitmq-custom.conf"); + } + + @NotNull + private String toJson(Map arguments) { + try { + return new ObjectMapper().writeValueAsString(arguments); + } catch (JsonProcessingException e) { + throw new RuntimeException("Failed to convert arguments into json: " + e.getMessage(), e); + } + } +} diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java new file mode 100644 index 00000000000..ff71db44348 --- /dev/null +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java @@ -0,0 +1,22 @@ +package org.testcontainers.containers; + +import org.junit.ClassRule; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for basic functionality when used as a @ClassRule. + * + * @author Mrtin Greber + */ +public class RabbitMQContainerJUnitIntegrationTest { + + @ClassRule + public static RabbitMQContainer rabbitMQContainer = new RabbitMQContainer(); + + @Test + public void shouldStart() { + assertThat(rabbitMQContainer.isRunning()).isTrue(); + } +} diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java new file mode 100644 index 00000000000..4f549a6f5ed --- /dev/null +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -0,0 +1,233 @@ +package org.testcontainers.containers; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.Test; +import org.testcontainers.utility.MountableFile; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.*; +import java.security.cert.CertificateException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER; +import static org.testcontainers.utility.MountableFile.forClasspathResource; + +/** + * @author Martin Greber + */ +public class RabbitMQContainerTest { + + public static final String DEFAULT_IMAGE = "rabbitmq:3.7-management-alpine"; + public static final int DEFAULT_AMQPS_PORT = 5671; + public static final int DEFAULT_AMQP_PORT = 5672; + public static final int DEFAULT_HTTPS_PORT = 15671; + public static final int DEFAULT_HTTP_PORT = 15672; + + @Test + public void shouldCreateRabbitMQContainer() { + try (RabbitMQContainer container = new RabbitMQContainer()) { + + assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE); + assertThat(container.getAdminPassword()).isEqualTo("guest"); + assertThat(container.getAdminUsername()).isEqualTo("guest"); + + container.start(); + + assertThat(container.getAmqpsUrl()).isEqualTo( + String.format("amqps://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQPS_PORT))); + assertThat(container.getAmqpUrl()).isEqualTo( + String.format("amqp://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQP_PORT))); + assertThat(container.getHttpsUrl()).isEqualTo( + String.format("https://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTPS_PORT))); + assertThat(container.getHttpUrl()).isEqualTo( + String.format("http://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTP_PORT))); + + assertThat(container.getHttpsPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTPS_PORT)); + assertThat(container.getHttpPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTP_PORT)); + assertThat(container.getAmqpsPort()).isEqualTo(container.getMappedPort(DEFAULT_AMQPS_PORT)); + assertThat(container.getAmqpPort()).isEqualTo(container.getMappedPort(DEFAULT_AMQP_PORT)); + + assertThat(container.getLivenessCheckPortNumbers()).containsExactlyInAnyOrder( + container.getMappedPort(DEFAULT_AMQP_PORT), + container.getMappedPort(DEFAULT_AMQPS_PORT), + container.getMappedPort(DEFAULT_HTTP_PORT), + container.getMappedPort(DEFAULT_HTTPS_PORT) + ); + } + } + + @Test + public void shouldCreateRabbitMQContainerWithTag() { + try (RabbitMQContainer container = new RabbitMQContainer(DEFAULT_IMAGE)) { + assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE); + } + } + + @Test + public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException { + try (RabbitMQContainer container = new RabbitMQContainer()) { + container.withExchange("test-exchange", "direct"); + + container.start(); + + assertThat(container.execInContainer("rabbitmqctl", "list_exchanges").getStdout()) + .containsPattern("test-exchange\\s+direct"); + } + } + + @Test + public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException { + try (RabbitMQContainer container = new RabbitMQContainer()) { + + container.withQueue("queue-one") + .withQueue("queue-two", false, true, ImmutableMap.of("x-message-ttl", 1000)); + + container.start(); + + assertThat(container.execInContainer("rabbitmqctl", "list_queues", "name", "arguments").getStdout()) + .containsPattern("queue-one"); + assertThat(container.execInContainer("rabbitmqctl", "list_queues", "name", "arguments").getStdout()) + .containsPattern("queue-two\\s.*x-message-ttl"); + } + } + + @Test + public void shouldMountConfigurationFile() { + try (RabbitMQContainer container = new RabbitMQContainer()) { + + container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); + container.start(); + + assertThat(container.getLogs().contains("/etc/rabbitmq/rabbitmq-custom.conf")).isTrue(); + } + } + + @Test + public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException { + try (RabbitMQContainer container = new RabbitMQContainer()) { + container + .withVhost("vhost1") + .withVhostLimit("vhost1", "max-connections", 1) + .withVhost("vhost2", true) + .withExchange("direct-exchange", "direct") + .withExchange("topic-exchange", "topic") + .withQueue("queue1") + .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) + .withBinding("direct-exchange", "queue1") + .withUser("user1", "password1") + .withUser("user2", "password2", ImmutableSet.of("administrator")) + .withPermission("vhost1", "user1", ".*", ".*", ".*") + .withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues") + .withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct")) + .withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues") + .withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange"); + + container.start(); + + assertThat(container.execInContainer("rabbitmqadmin", "list", "queues") + .getStdout()) + .contains("queue1", "queue2"); + + assertThat(container.execInContainer("rabbitmqadmin", "list", "exchanges") + .getStdout()) + .contains("direct-exchange", "topic-exchange"); + + assertThat(container.execInContainer("rabbitmqadmin", "list", "bindings") + .getStdout()) + .contains("direct-exchange"); + + assertThat(container.execInContainer("rabbitmqadmin", "list", "users") + .getStdout()) + .contains("user1", "user2"); + + assertThat(container.execInContainer("rabbitmqadmin", "list", "policies") + .getStdout()) + .contains("max length policy", "alternate exchange policy"); + + assertThat(container.execInContainer("rabbitmqadmin", "list", "operator_policies") + .getStdout()) + .contains("operator policy 1"); + + assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_shovel", "--quiet") + .getStdout()) + .contains("rabbitmq_shovel is enabled"); + + assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_random_exchange", "--quiet") + .getStdout()) + .contains("rabbitmq_random_exchange is enabled"); + } + } + + @Test + public void shouldThrowExceptionForDodgyJson() { + try (RabbitMQContainer container = new RabbitMQContainer()) { + + assertThatCode(() -> + container.withQueue( + "queue2", + true, + false, + ImmutableMap.of("x-message-ttl", container)) + ).hasMessageStartingWith("Failed to convert arguments into json"); + + } + } + + @Test + public void shouldWorkWithSSL() { + try (RabbitMQContainer container = new RabbitMQContainer()) { + container.withSSL( + forClasspathResource("/certs/server_key.pem", 0644), + forClasspathResource("/certs/server_certificate.pem", 0644), + forClasspathResource("/certs/ca_certificate.pem", 0644), + VERIFY_PEER, + true + ); + + container.start(); + + assertThatCode(() -> { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.useSslProtocol(createSslContext( + "certs/client_key.p12", "password", + "certs/truststore.jks", "password")); + connectionFactory.enableHostnameVerification(); + connectionFactory.setUri(container.getAmqpsUrl()); + connectionFactory.setPassword(container.getAdminPassword()); + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.openChannel().orElseThrow(() -> new RuntimeException("Failed to Open channel")); + channel.close(); + connection.close(); + }).doesNotThrowAnyException(); + } + } + + private SSLContext createSslContext(String keystoreFile, String keystorePassword, String truststoreFile, String truststorePassword) + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { + ClassLoader classLoader = getClass().getClassLoader(); + + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(new FileInputStream(new File(classLoader.getResource(keystoreFile).getFile())), keystorePassword.toCharArray()); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, "password".toCharArray()); + + KeyStore trustStore = KeyStore.getInstance("PKCS12"); + trustStore.load(new FileInputStream(new File(classLoader.getResource(truststoreFile).getFile())), truststorePassword.toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(trustStore); + + SSLContext c = SSLContext.getInstance("TLSv1.2"); + c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + return c; + } +} diff --git a/modules/rabbitmq/src/test/resources/certs/ca_certificate.pem b/modules/rabbitmq/src/test/resources/certs/ca_certificate.pem new file mode 100644 index 00000000000..f22df829095 --- /dev/null +++ b/modules/rabbitmq/src/test/resources/certs/ca_certificate.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRzCCAi+gAwIBAgIJAJJIMzvZuRzlMA0GCSqGSIb3DQEBCwUAMDExIDAeBgNV +BAMMF1RMU0dlblNlbGZTaWduZWR0Um9vdENBMQ0wCwYDVQQHDAQkJCQkMCAXDTE5 +MDUwMjA3MjI0OVoYDzIxMTkwNDA4MDcyMjQ5WjAxMSAwHgYDVQQDDBdUTFNHZW5T +ZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKko8FmfzrLHyZckvdR1oiSZf80m0t66TMqtLat1Oxjh +CjsxvswwJ/m2I5dM48hwZ+0b2ufkvaudLPq/8jDGyONVfjMGlbe1YlmQMDC7YWdI +XM1nCWAZIKaOHwIkfswuVBAdBVYV4Polu6wjVt5edEpl/IWEpPicXjLOY1Fw3q67 +5tP2Mmo6TJg5YqgB4fH4SmajtP3j+H4puQ8ZPIs26mInEgfCyrMWey/oQX8qqMph +pKMEJYE7DHawriFraOooJadJYojbY5H27nmJe8yXURb3wSQSaKnFZL25cmVm2kue +/lw+n+a2wLdHdU4cmghCURalhcXUNZe7UbdRZ9e9r2cCAwEAAaNgMF4wCwYDVR0P +BAQDAgEGMB0GA1UdDgQWBBSZiNur/XHsqSfdWnB1NPi/ql5+tzAfBgNVHSMEGDAW +gBSZiNur/XHsqSfdWnB1NPi/ql5+tzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQAar/db/T7izD4pyh2titl7Dkgp2iTditfgqRlU0yVGiiB6rLmY +sYE2QAuFhgqyRLPcjVV8F39iRJHQ17SGT8e2iAaUTnbQj0AiskKjonF9+quKuVbr +TpYHk+guS0Jn2rU6HK8WQeYZOh3WdLTu4ArXkxywgwVssQQ9JmpTd9YEYePWfs7i +WZB6AQyL9CD3z1j4i1G4ft6pB1Ps5XjznqMZ2//7AUpoRTrettWqorPWwudQ9yna +B4S6KtvpnxUQSeHJW6Q4NvTrOsvHEOCa6OtwYbWmLf+qbpPb8oHt9UF3ze2PJopB +QzsQop1+gPudG0DX0SgyuQT+SsFjYlDazZdZ +-----END CERTIFICATE----- diff --git a/modules/rabbitmq/src/test/resources/certs/ca_key.pem b/modules/rabbitmq/src/test/resources/certs/ca_key.pem new file mode 100644 index 00000000000..29ed148fb01 --- /dev/null +++ b/modules/rabbitmq/src/test/resources/certs/ca_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCpKPBZn86yx8mX +JL3UdaIkmX/NJtLeukzKrS2rdTsY4Qo7Mb7MMCf5tiOXTOPIcGftG9rn5L2rnSz6 +v/IwxsjjVX4zBpW3tWJZkDAwu2FnSFzNZwlgGSCmjh8CJH7MLlQQHQVWFeD6Jbus +I1beXnRKZfyFhKT4nF4yzmNRcN6uu+bT9jJqOkyYOWKoAeHx+Epmo7T94/h+KbkP +GTyLNupiJxIHwsqzFnsv6EF/KqjKYaSjBCWBOwx2sK4ha2jqKCWnSWKI22OR9u55 +iXvMl1EW98EkEmipxWS9uXJlZtpLnv5cPp/mtsC3R3VOHJoIQlEWpYXF1DWXu1G3 +UWfXva9nAgMBAAECggEAVHUVM5o/aDGp6+WzRa2Jy/47ueEFbaDUkGjQoYeBfxV0 +t0NKAMaWXu3abUM9gyjkKpU6wYcKT/HEsFk/gazuRdq8jJtgCv3r4c3E0b/sjNWr +R/6Gxs0k6SOSRc6U5DrJS9ZBgM6hqiNGxVZLm/DK3Q54eu1UNLBVs8Yp/lJ9S/3C +oM6lhex6SoCTiZyFb3ZvVTmBAZe/ROFXZAtmVac1KORBFN8FpkXQcB3EPTkvZmNJ +sSp8dVPBLABm6gAbdJRLVqqndkHDPsopFGHLGzo4LtR7AlEklfxBdC/XlYmudZeY +peWba+ZdLH3sCybE55Xcm7nTfRRSQSLDv++r73GCCQKBgQDe/7ltr8N+gWpb1fDC +nEyBU4WHoTRp09sD+MZe3B06PX3WNRrf+3wHj9oB9UkhZ1baCq84mRzBiUKpAYrw +GrC4iL4kqbWeIZzcJqLZ7zk1zzHzW0+zzNJSjzE8dq3W26+SnuLqKDFpkxtAyIMQ +Rp9AZJIW8q9ay6ZCsZk/NNBoKwKBgQDCMYh53dXKiYtr6tAXXManWWpQ24af6WKl +3faXCw5eXG7ic5bNZD7ql+DWJzRylkI4yeLDvWAsHprtyIBYmkRki3lBAnpLeHY8 +7XWjZeOVeIpiSbG+1Fo7LrOuWi3wYGOZ61QUTjqJhvZJpzZBMEgo7cx+WQhlrioI +9BbXqPabtQKBgAZJv7jQE/slOxKL3dYfAilDaaiBazDwwGRER5O1MT3LLhk0NiXK +uZyc+dDEUeOXPmO3mWlHKABtFmwdlwVeO014zaPLBUwINpwemsj6beqOhSIPmRfA +1s1tLD5AOnasiy7fPBbOO1Z2x3X0MX3r/+GY9GWhQkCVLYMD7wZRPu8xAoGBAJMr +PNW2s+ZJtPq1Orzp17dOAU+D/xPDqLoxbEbt3xbOEE7X8Mp5lWDudzt0/L92dntZ +LNzQ8UiebSWVlQcQ6pIUTXFiMlJt2ZW1FDkf54kIkD+KwATyI+vEKfIRb81DD1i/ +yrmUy7IcMRyCd5CRya4TAa4jRUTh6ANfEMyhxTsdAoGBAIFub7nikxPQ8J4ItWq8 +EKOptyziJ38KnL2nZnFyVDu6uZDtSk9Tf1dHqWy8D4yP9K3OLshipEp7rnNG25dr +e7fkB58K77eSoaEpCZmwzPZstwkXbeBl+DHerDyC2UBXwIUWWFq+FuCdRQqCoYmU +OGiaT92l+UInN7VchZjJS7Oj +-----END PRIVATE KEY----- diff --git a/modules/rabbitmq/src/test/resources/certs/client_certificate.pem b/modules/rabbitmq/src/test/resources/certs/client_certificate.pem new file mode 100644 index 00000000000..f6d75c8c272 --- /dev/null +++ b/modules/rabbitmq/src/test/resources/certs/client_certificate.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDKDCCAhCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAxMSAwHgYDVQQDDBdUTFNH +ZW5TZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDAgFw0xOTA1MDIwNzIy +NDlaGA8yMTE5MDQwODA3MjI0OVowIzEQMA4GA1UEAwwHQzY1U1RUMjEPMA0GA1UE +CgwGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtcAse1RO +mRngQ4NNFFgyPgbq2eZc3c/ERKdg2xKi2XESMIbOreVkoBRq1IXoxkJHgQZJvPP8 +JbH7hmY+DFZcreszlEk5FI7bvxFNQM3CKsy2LeEcN9BTchSEsWgmSbwiZJ31kEB8 +u/i+/GpgTTxtwPWi/zTep+7fKM4dyzYX9WcMu8wif3jKIzqXVUqHpWopFUK9zLQf +JRnyfiD2uYbfcZYopsIG+wdL2Ebgfr8fpc+YsWn0aA0zBiEFAKYh9bewPqDIZKyg +qd4FKzeUaqGHynttNxKDJ9z0oD84PKFEOuryf7V8ODU8+kI1+y/+3C5Hlq6n92y6 +eSPn81W44+WZeQIDAQABo1cwVTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNV +HSUEDDAKBggrBgEFBQcDAjAmBgNVHREEHzAdggdDNjVTVFQyggdDNjVTVFQyggls +b2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAH3oqsmr+hIfMEpZUolPNuAl43TF +KUu14SeFyS+P8fEIQVGkHdpEpHzC0G+fvREAy4YSw0WE8upOq6tkbbjen222SP0J +C2vj0B9cCPLZUQ4kW6Z7JJD/1qryML0XB9uMPHqDeV/yBETJZW80TV0f7p8GWKXe ++spu1W13rJ0jvQQd9anNEx3VhcKTwBIcTAhTHothxFLLhX1zb/oVZcl1riBopBFm +WtrZRTCHs31o5GBnIs540uH0f2iCk7wUf8M/evxv5F1hms+NV7kfOz7fyCEXc9La +P9pDjuxTNOUeOZH815BR9Lj71txY9AdjXqEXj7JdecACLsjHc+LMEP36cls= +-----END CERTIFICATE----- diff --git a/modules/rabbitmq/src/test/resources/certs/client_key.p12 b/modules/rabbitmq/src/test/resources/certs/client_key.p12 new file mode 100644 index 0000000000000000000000000000000000000000..15ce61136e2e1239cbaa457929f35f112bcbe72f GIT binary patch literal 2413 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 literal 0 HcmV?d00001 diff --git a/modules/rabbitmq/src/test/resources/certs/server_key.pem b/modules/rabbitmq/src/test/resources/certs/server_key.pem new file mode 100644 index 00000000000..dfbfb6db7e3 --- /dev/null +++ b/modules/rabbitmq/src/test/resources/certs/server_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAqR0QXKtbKVeEuCmZGcZAlAlTBC8E/G3UuX6qKwTR1xEOvUWe +BH1n0WeXXGd/p/y6P4lRBeWNBZ9KcvIlNDeDMy05NfxnO1vnJk9E8/0xwMiY1LJd +MHzIzhmrrqXo0u3DT8MmoNR67CTcnG21gi1GrjW8a747yFF0xfukEc6FkyVqLsjt +CkHPwrc/sBHVS3aivNWGkJzAeBXBdWJAg3ZC6T9U+Y8cndWQrpYMJvek1IewlyDS +spHZDFmM1OwVwypnMt4fGgaX5IlUMnNgKmisOSuI529rxLF+mvYIQLRl5bP+1/c9 +JD5MZ5krA3SrjdwRFS3sQXC3nuHqJofFXNkbXQIDAQABAoIBAA0dxvYZCEIFmrKZ +71jzanDQ5FJvvyhA8H3OmC4r+oZ+uTDu5FmezF2OdkvhbyI9VMi2wsT9T9m+yAxw +QXhyUce3WzeXsv4Em8H55fQykBhOtqPQja/EDeMGVK2ACrXJYRufnDBfKoWEOmQb +kjddgZzjaBDHOWXJA5CTet8ysGOAJBTxyzU69k5Vj9B5abG9CofNzGOFF+Uleff5 +ip3sz7JpDXCex3oEs98veco6+8i/MZNo3BnwB5J+P+2MFFKONfPwuNyKAWBza2/X +66Lk3xXBjLJJ+Ww16jkqueTXEq6GCFXavNfdL9aonth5V5YYR/cj+2u2LM1oj9cJ +bp0xbvUCgYEA2Svq1DyR9cfTwrbc/0J2JfrjavClzDYU2oeO2fSU85WEEjJguaja +17Vdo/UsJtiUiSq4UhI1n0haaIpTBCeF2tHGXVEYZ7ZBi1zzdWbWlDxFmi+rcE57 +ytx5w+iLE366tQEMa/Jn3bly54pG5JZAr9TXkpg9sMbzWZri2ocyU/cCgYEAx1l/ +9X9C/OruDp/MhhmVwKfw/X2+RhZRuv0pPcpJu7/gIoLgaxNj41XSeLqLYMlisaRk +GFU17GFXtfRGE1a3z+jj8UPTP2sHk3w8m0yI+pgWgsvG0TJ0B+XsRfpVxFiIoaEs +3AsBaGR+hrRY1dpaJ9Cu3J9mEeToTpbCzPzVDksCgYEAzwSvWNvYY4u2UFHSvz2S +tMfBzCpUUiNno50/ToN5De4ENPhy/eh5nNDVz7qh+PHSPiNMC2gyV4E4NZlOY5Jt +Zdc8ma35brvtJTVZGxwKBsqhqsYwTeFy3kFnjZn6IX5X6r1yIuCzpEfowdEtnS+h +wDtLuAGKJR6x0UP1Zk0ka6cCgYBGE6I1rJzhx7wTi/0bjtbjuKWwlolSnfnxH5ll +zTyKMXMa7qLxQQm2Gq84HWtthJ2bEMzW+O1RwQ5SOiKAHdXT0mx+nXcfLgKlx+CO +PyNP5DLVm8iyNWgwdpTOLKgFs5GkL8JTP9Mo3VrVA4TO+EkFAgjWKXp6A9vd9IVa +Be7nbQKBgAVtFKuf9nbCMfN+W1gN0vlW2lwxCTa4w0KHgIlGIIvnYVuixSgu9fGt +uylQcQirEjqrdzdVF9L2BQ37ZcLaGh1LoCmx8XVCX/HhbwW2RP798P3Z1P7htm16 +ha5OfuPjHvoZklbYJo6EORJZQehS2VP63pjdnmUeMHPFzrPUevI5 +-----END RSA PRIVATE KEY----- diff --git a/modules/rabbitmq/src/test/resources/certs/truststore.jks b/modules/rabbitmq/src/test/resources/certs/truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..84fce84266ba154fc2278b4ef033811f2b292af7 GIT binary patch literal 1130 zcmV-w1eNWumexf~gMGVwZ001T`xi))j-ZQ$EOubqh*D$*)ZW)X?JjRo#e&H>7ZbPkK?aM3 zxgT?kuIy=K6Pi=M$2Ru7E->F5Tv$NkFFj+L|3XLVnctX2*VbI^To?RrMJtBfAG_UN zX8pY${t+sgfs-Rh=LR7d6O391Xce>OClLOoi60u)%NqM*1)S=b@V)Oi1wU*3PWAL1 z_tO_teeLE0uWZe^vilB$a~iOfEt@x9WQbK3b1RCl;!4S~>L{`x{lKB*3RVVO@I9ca zWLnX10d34+24&a)|`Ubk62WhcJcL=P8kSCH?h0pM3Fs>et!_yv&^^&Fr zsjc>(rm0!s2<72ij@Xa9=d-`Wd7DqCeor6h1`2%a8VljL66Vx=eL^>EZ!&HVH`aGO zr!D6UPjx1DpyL~flTF1TkY8!L;Ba*pCts5Q2C0e*QuY?~Ooqc_h1_ru`&_W}9a!3V zC^gOmiYX9vxc92-yWL875hvPW&E$#42@d@%ga0X8N0mBMiN?{L2OlPLkIugriPF*7 zO2?`!76&`E+Q@eoO~)2fP64ks9cD6#LGv;5*Jx{0aT?xYG6VbP*mm_{Zh*disBhjT zq+iL4)tSQ%Qwtolmqa{^qALv+#|PM@+v2^v#l*zWhk5SkH*52{@{Xx=ykh(x#qaU4 zj|~vV$2S0}9i{iYMRP_xMq2?m{o4R5#9lP)TUO%GfAR1g@7G000kvzD`j~BTjUDJr`nDNcD5{Lhyi*Pe62;2`fjeDhD^wXmsPnQ>EZCOF*0B Date: Tue, 16 Jul 2019 16:32:12 +0200 Subject: [PATCH 0156/4969] increase db2 timeout (#1617) --- .../containers/Db2Container.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index 6e45b0f7f12..429cc060094 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -36,14 +36,14 @@ public Db2Container(String imageName) { withPrivilegedMode(true); this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*Setup has completed\\..*") - .withStartupTimeout(Duration.of(3, ChronoUnit.MINUTES)); + .withStartupTimeout(Duration.of(10, ChronoUnit.MINUTES)); } - + @Override protected Set getLivenessCheckPorts() { return new HashSet<>(getMappedPort(DB2_PORT)); } - + @Override protected void configure() { // If license was not accepted programatically, check if it was accepted via resource file @@ -53,11 +53,11 @@ protected void configure() { } addExposedPort(DB2_PORT); - + addEnv("DBNAME", databaseName); addEnv("DB2INSTANCE", username); addEnv("DB2INST1_PASSWORD", password); - + // These settings help the DB2 container start faster if (!getEnvMap().containsKey("AUTOCONFIG")) addEnv("AUTOCONFIG", "false"); @@ -93,30 +93,30 @@ public String getUsername() { public String getPassword() { return password; } - + @Override public String getDatabaseName() { return databaseName; } - + @Override public Db2Container withUsername(String username) { this.username = username; return this; } - + @Override public Db2Container withPassword(String password) { this.password = password; return this; } - + @Override public Db2Container withDatabaseName(String dbName) { this.databaseName = dbName; return this; } - + @Override protected void waitUntilContainerStarted() { getWaitStrategy().waitUntilReady(this); From fbb4d8af1489d9e2c5a463e44ab25ed4dfde7eb1 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 17 Jul 2019 07:42:13 +0200 Subject: [PATCH 0157/4969] fix RabbitMQ's Javadoc --- .../java/org/testcontainers/containers/RabbitMQContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index 98c2497c2dc..f16f005df5e 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -49,7 +49,7 @@ public RabbitMQContainer() { /** * Creates a Testcontainer using a specific docker image. * - * @param tag The docker image to use. + * @param image The docker image to use. */ public RabbitMQContainer(String image) { super(image); From b840912d9df616e551a77f4b58502166df32c8cb Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 17 Jul 2019 15:19:48 +0200 Subject: [PATCH 0158/4969] Simplify Kafka container by deferring the Kafka command (#1458, Fixes #1450) * Simplify Kafka container by deferring the Kafka command * extract `startZookeeper` method, add `PORT_NOT_ASSIGNED` constant * keep network&alias for backward compatibility --- .../containers/KafkaContainer.java | 78 +++++++++++++------ 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index b1be94f1e67..b08d6611e6d 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -1,9 +1,13 @@ package org.testcontainers.containers; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import lombok.SneakyThrows; import org.testcontainers.utility.Base58; import org.testcontainers.utility.TestcontainersConfiguration; -import java.util.stream.Stream; +import java.util.concurrent.TimeUnit; /** * This container wraps Confluent Kafka and Zookeeper (optionally) @@ -15,9 +19,11 @@ public class KafkaContainer extends GenericContainer { public static final int ZOOKEEPER_PORT = 2181; + private static final int PORT_NOT_ASSIGNED = -1; + protected String externalZookeeperConnect = null; - protected SocatContainer proxy; + private int port = PORT_NOT_ASSIGNED; public KafkaContainer() { this("5.2.1"); @@ -26,6 +32,7 @@ public KafkaContainer() { public KafkaContainer(String confluentPlatformVersion) { super(TestcontainersConfiguration.getInstance().getKafkaImage() + ":" + confluentPlatformVersion); + // TODO Only for backward compatibility withNetwork(Network.newNetwork()); withNetworkAliases("kafka-" + Base58.randomString(6)); withExposedPorts(KAFKA_PORT); @@ -54,40 +61,61 @@ public KafkaContainer withExternalZookeeper(String connectString) { } public String getBootstrapServers() { - return String.format("PLAINTEXT://%s:%s", proxy.getContainerIpAddress(), proxy.getFirstMappedPort()); + if (port == PORT_NOT_ASSIGNED) { + throw new IllegalStateException("You should start Kafka container first"); + } + return String.format("PLAINTEXT://%s:%s", getContainerIpAddress(), port); } @Override protected void doStart() { - String networkAlias = getNetworkAliases().get(0); - proxy = new SocatContainer() - .withNetwork(getNetwork()) - .withTarget(KAFKA_PORT, networkAlias) - .withTarget(ZOOKEEPER_PORT, networkAlias); - - proxy.start(); - withEnv("KAFKA_ADVERTISED_LISTENERS", "BROKER://" + networkAlias + ":9092" + "," + getBootstrapServers()); + withCommand("sleep infinity"); - if (externalZookeeperConnect != null) { - withEnv("KAFKA_ZOOKEEPER_CONNECT", externalZookeeperConnect); - } else { + if (externalZookeeperConnect == null) { addExposedPort(ZOOKEEPER_PORT); - withEnv("KAFKA_ZOOKEEPER_CONNECT", "localhost:2181"); - withCommand( - "sh", - "-c", - // Use command to create the file to avoid file mounting (useful when you run your tests against a remote Docker daemon) - "printf 'clientPort=2181\ndataDir=/var/lib/zookeeper/data\ndataLogDir=/var/lib/zookeeper/log' > /zookeeper.properties" + - " && zookeeper-server-start /zookeeper.properties" + - " & /etc/confluent/docker/run" - ); } super.doStart(); } @Override - public void stop() { - Stream.of(super::stop, proxy::stop).parallel().forEach(Runnable::run); + @SneakyThrows + protected void containerIsStarting(InspectContainerResponse containerInfo) { + super.containerIsStarting(containerInfo); + + port = getMappedPort(KAFKA_PORT); + + final String zookeeperConnect; + if (externalZookeeperConnect != null) { + zookeeperConnect = externalZookeeperConnect; + } else { + zookeeperConnect = startZookeeper(); + } + + String internalIp = containerInfo.getNetworkSettings().getIpAddress(); + + ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(getContainerId()) + .withCmd("sh", "-c", "" + + "export KAFKA_ZOOKEEPER_CONNECT=" + zookeeperConnect + "\n" + + "export KAFKA_ADVERTISED_LISTENERS=" + getBootstrapServers() + "," + String.format("BROKER://%s:9092", internalIp) + "\n" + + "/etc/confluent/docker/run" + ) + .exec(); + + dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ExecStartResultCallback()).awaitStarted(10, TimeUnit.SECONDS); + } + + @SneakyThrows(InterruptedException.class) + private String startZookeeper() { + ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(getContainerId()) + .withCmd("sh", "-c", "" + + "printf 'clientPort=" + ZOOKEEPER_PORT + "\ndataDir=/var/lib/zookeeper/data\ndataLogDir=/var/lib/zookeeper/log' > /zookeeper.properties\n" + + "zookeeper-server-start /zookeeper.properties\n" + ) + .exec(); + + dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ExecStartResultCallback()).awaitStarted(10, TimeUnit.SECONDS); + + return "localhost:" + ZOOKEEPER_PORT; } } From 7ca3f9f47bee462be2481b0601a491d156f8108a Mon Sep 17 00:00:00 2001 From: Andrew Guibert Date: Wed, 17 Jul 2019 14:42:49 -0500 Subject: [PATCH 0159/4969] Add new withDockerfile methods to ImageFromDockerfile (#1535) * Add new withDockerfile methods to ImageFromDockerfile These methods are preferable to the existing withDockerfilePath methods because the docker-java API will honor .dockerignore files if withDockerfile(File) is used. * Review comments for .dockerignore support PR * Update core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java Co-Authored-By: Kevin Wittek --- .../images/builder/ImageFromDockerfile.java | 30 ++++++++++ .../images/builder/DockerfileBuildTest.java | 12 +++- .../images/builder/DockerignoreTest.java | 56 +++++++++++++++++++ .../dockerfile-build-invalid/.dockerignore | 3 + .../dockerfile-build-invalid/Dockerfile | 1 + .../dockerfile-build-test/.dockerignore | 1 + .../Dockerfile-currentdir | 2 + .../should_be_ignored.txt | 1 + .../should_not_be_ignored.txt | 1 + 9 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java create mode 100644 core/src/test/resources/dockerfile-build-invalid/.dockerignore create mode 100644 core/src/test/resources/dockerfile-build-invalid/Dockerfile create mode 100644 core/src/test/resources/dockerfile-build-test/.dockerignore create mode 100644 core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir create mode 100644 core/src/test/resources/dockerfile-build-test/should_be_ignored.txt create mode 100644 core/src/test/resources/dockerfile-build-test/should_not_be_ignored.txt diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index c7d409c0660..f4968c11ff0 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -10,6 +10,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; @@ -18,9 +19,11 @@ import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.LazyFuture; +import java.io.File; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -63,6 +66,7 @@ public class ImageFromDockerfile extends LazyFuture implements private final Map transferables = new HashMap<>(); private final Map buildArgs = new HashMap<>(); private Optional dockerFilePath = Optional.empty(); + private Optional dockerfile = Optional.empty(); public ImageFromDockerfile() { this("testcontainers/" + Base58.randomString(16).toLowerCase()); @@ -119,6 +123,8 @@ public void onNext(BuildResponseItem item) { configure(buildImageCmd); BuildImageResultCallback exec = buildImageCmd.exec(resultCallback); + + long bytesToDockerDaemon = 0; // To build an image, we have to send the context to Docker in TAR archive format try (TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(new GZIPOutputStream(out))) { @@ -128,9 +134,15 @@ public void onNext(BuildResponseItem item) { Transferable transferable = entry.getValue(); final String destination = entry.getKey(); transferable.transferTo(tarArchive, destination); + bytesToDockerDaemon += transferable.getSize(); } tarArchive.finish(); } + + log.info("Transferred {} KB to Docker daemon", FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); + if (bytesToDockerDaemon > FileUtils.ONE_MB * 50) // warn if >50MB sent to docker daemon + log.warn("A large amount of data was sent to the Docker daemon ({}). Consider using a .dockerignore file for better performance.", + FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); exec.awaitImageId(); @@ -143,6 +155,7 @@ public void onNext(BuildResponseItem item) { protected void configure(BuildImageCmd buildImageCmd) { buildImageCmd.withTag(this.getDockerImageName()); this.dockerFilePath.ifPresent(buildImageCmd::withDockerfilePath); + this.dockerfile.ifPresent(p -> buildImageCmd.withDockerfile(p.toFile())); this.buildArgs.forEach(buildImageCmd::withBuildArg); } @@ -156,8 +169,25 @@ public ImageFromDockerfile withBuildArgs(final Map args) { return this; } + /** + * Sets the Dockerfile to be used for this image. + * @deprecated It is recommended to use {@link #withDockerfile} instead because it honors + * .dockerignore files and therefore will be more efficient + * @param relativePathFromBuildRoot + */ + @Deprecated public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildRoot) { this.dockerFilePath = Optional.of(relativePathFromBuildRoot); return this; } + + /** + * Sets the Dockerfile to be used for this image. + * @param dockerfile + */ + public ImageFromDockerfile withDockerfile(Path dockerfile) { + this.dockerfile = Optional.of(dockerfile); + return this; + } + } diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java index 4c33fe9118b..9a9d647d71b 100644 --- a/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java @@ -6,6 +6,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; @@ -14,7 +15,7 @@ @RunWith(Parameterized.class) public class DockerfileBuildTest { - private static final Path RESOURCE_PATH = Paths.get("src/test/resources/dockerfile-build-test"); + static final Path RESOURCE_PATH = Paths.get("src/test/resources/dockerfile-build-test"); public String expectedFileContent; public ImageFromDockerfile image; @@ -44,6 +45,13 @@ public static Object[][] parameters() { .withDockerfilePath("./Dockerfile-buildarg") .withBuildArg("CUSTOM_ARG", "test7890") }, + + // Dockerfile build using withDockerfile(File) + new Object[]{"test4567", + new ImageFromDockerfile() + .withFileFromPath(".", RESOURCE_PATH) + .withDockerfile(RESOURCE_PATH.resolve("Dockerfile-alt")) + }, }; } @@ -57,11 +65,11 @@ public void performTest() { try (final GenericContainer container = new GenericContainer(image) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCommand("cat", "/test.txt")) { - container.start(); final String logs = container.getLogs(); assertTrue("expected file content indicates that dockerfile build steps have been run", logs.contains(expectedFileContent)); } } + } diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java new file mode 100644 index 00000000000..faf5fb950b8 --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java @@ -0,0 +1,56 @@ +package org.testcontainers.images.builder; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.rnorth.visibleassertions.VisibleAssertions.fail; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; + +import com.github.dockerjava.api.exception.DockerClientException; + +public class DockerignoreTest { + + private static final Path INVALID_DOCKERIGNORE_PATH = Paths.get("src/test/resources/dockerfile-build-invalid"); + + @Test + public void testInvalidDockerignore() throws Exception { + try { + new ImageFromDockerfile() + .withFileFromPath(".", INVALID_DOCKERIGNORE_PATH) + .withDockerfile(INVALID_DOCKERIGNORE_PATH.resolve("Dockerfile")) + .get(); + fail("Should not be able to build an image with an invalid .dockerignore file"); + } + catch (DockerClientException e) { + if (!e.getMessage().contains("Invalid pattern")) + throw e; + } + } + + @SuppressWarnings("resource") + @Test + public void testValidDockerignore() throws Exception { + ImageFromDockerfile img = new ImageFromDockerfile() + .withFileFromPath(".", DockerfileBuildTest.RESOURCE_PATH) + .withDockerfile(DockerfileBuildTest.RESOURCE_PATH.resolve("Dockerfile-currentdir")); + try( + final GenericContainer container = new GenericContainer<>(img.get()) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withCommand("ls", "/") + ) { + + container.start(); + + final String logs = container.getLogs(); + assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, + logs.contains("should_not_be_ignored.txt")); + assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, + !logs.contains("should_be_ignored.txt")); + } + } + +} diff --git a/core/src/test/resources/dockerfile-build-invalid/.dockerignore b/core/src/test/resources/dockerfile-build-invalid/.dockerignore new file mode 100644 index 00000000000..5f06037fe04 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-invalid/.dockerignore @@ -0,0 +1,3 @@ +# This is an invalid dockerignore file +*~ +[a-b-c] \ No newline at end of file diff --git a/core/src/test/resources/dockerfile-build-invalid/Dockerfile b/core/src/test/resources/dockerfile-build-invalid/Dockerfile new file mode 100644 index 00000000000..6140f575ef7 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-invalid/Dockerfile @@ -0,0 +1 @@ +FROM alpine:3.2 diff --git a/core/src/test/resources/dockerfile-build-test/.dockerignore b/core/src/test/resources/dockerfile-build-test/.dockerignore new file mode 100644 index 00000000000..a6bd49d7d81 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/.dockerignore @@ -0,0 +1 @@ +should_be_ignored.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir b/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir new file mode 100644 index 00000000000..97f80bdfa65 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir @@ -0,0 +1,2 @@ +FROM alpine:3.2 +COPY . / diff --git a/core/src/test/resources/dockerfile-build-test/should_be_ignored.txt b/core/src/test/resources/dockerfile-build-test/should_be_ignored.txt new file mode 100644 index 00000000000..6b04bcc9cec --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/should_be_ignored.txt @@ -0,0 +1 @@ +this file should be ignored by a .dockerignore file \ No newline at end of file diff --git a/core/src/test/resources/dockerfile-build-test/should_not_be_ignored.txt b/core/src/test/resources/dockerfile-build-test/should_not_be_ignored.txt new file mode 100644 index 00000000000..675ce985900 --- /dev/null +++ b/core/src/test/resources/dockerfile-build-test/should_not_be_ignored.txt @@ -0,0 +1 @@ +this file should not be ignored by a .dockerignore file \ No newline at end of file From 60269891bce2c32a51c8deee1356a5437fb45add Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2019 05:59:46 +0000 Subject: [PATCH 0160/4969] Bump aws-java-sdk-sqs from 1.11.479 to 1.11.594 in /modules/localstack (#1626) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index e5e3efb5de3..3bcfcb91714 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.479' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.594' } From a0e479ad7b26f73025e4e7926908dd39b369c619 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2019 07:38:30 +0000 Subject: [PATCH 0161/4969] Bump cucumber-java from 4.5.4 to 4.6.0 in /examples (#1620) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index fb3a1ae875c..792968df7c4 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.5.4' + implementation 'io.cucumber:cucumber-java:4.6.0' testImplementation 'io.cucumber:cucumber-junit:4.5.4' testImplementation 'org.testcontainers:selenium' } From bf764260b8d74e59f9e19bd8d42df02916a4a048 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2019 09:37:48 +0000 Subject: [PATCH 0162/4969] Bump cucumber-junit from 4.5.4 to 4.6.0 in /examples (#1619) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 792968df7c4..9907da86262 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.6.0' - testImplementation 'io.cucumber:cucumber-junit:4.5.4' + testImplementation 'io.cucumber:cucumber-junit:4.6.0' testImplementation 'org.testcontainers:selenium' } From 6dd9c44140ed19fd3f46dd3aace0fd6799c37b9a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2019 15:21:59 +0200 Subject: [PATCH 0163/4969] Bump amqp-client from 5.7.1 to 5.7.2 in /core (#1588) Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.7.1...v5.7.2) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index ee876f595c1..77620f6e98e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -102,7 +102,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.0.1' - testCompile 'com.rabbitmq:amqp-client:5.7.1' + testCompile 'com.rabbitmq:amqp-client:5.7.2' testCompile 'org.mongodb:mongo-java-driver:3.10.2' testCompile ('org.mockito:mockito-core:2.28.2') { exclude(module: 'hamcrest-core') From 4373d1fb3540aea5be684daf32ab4b0eec7cb0cb Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 19 Jul 2019 15:22:33 +0200 Subject: [PATCH 0164/4969] Fail fast if `container_name` is set in Docker Compose file (#1581) * Fail fast if `container_name` is set in Docker Compose file * Update DockerComposeContainer.java --- core/build.gradle | 4 + .../containers/DockerComposeContainer.java | 86 +++++++++++++++---- .../DockerComposeFileValidationTest.java | 70 +++++++++++++++ .../docker-compose-container-name-v1.yml | 3 + 4 files changed, 147 insertions(+), 16 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java create mode 100644 core/src/test/resources/docker-compose-container-name-v1.yml diff --git a/core/build.gradle b/core/build.gradle index 77620f6e98e..f400b5e3c1c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -92,6 +92,8 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } + shaded "org.yaml:snakeyaml:1.21" + shaded 'com.squareup.okhttp3:okhttp:3.14.2' shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' @@ -110,6 +112,8 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') + testCompile 'org.assertj:assertj-core:3.12.2' + jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 46f4c561e5d..06a8bd9d597 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -2,17 +2,19 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Container; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.Maps; import com.google.common.util.concurrent.Uninterruptibles; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; @@ -22,11 +24,14 @@ import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.lifecycle.Startable; import org.testcontainers.utility.*; +import org.yaml.snakeyaml.Yaml; import org.zeroturnaround.exec.InvalidExitValueException; import org.zeroturnaround.exec.ProcessExecutor; import org.zeroturnaround.exec.stream.slf4j.Slf4jStream; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -49,6 +54,7 @@ /** * Container which launches Docker Compose, for the purposes of launching a defined set of containers. */ +@Slf4j public class DockerComposeContainer> extends FailureDetectingExternalResource implements Startable { /** @@ -147,7 +153,7 @@ public void start() { try { pullImages(); } catch (ContainerLaunchException e) { - logger().warn("Exception while pulling images, using local images if available", e); + log.warn("Exception while pulling images, using local images if available", e); } } applyScaling(); // scale before up, so that all scaled instances are available first for linking @@ -187,7 +193,7 @@ private void createServiceInstance(Container container) { String containerId = containerInstance.getContainerId(); if (tailChildContainers) { - followLogs(containerId, new Slf4jLogConsumer(logger()).withPrefix(container.getNames()[0])); + followLogs(containerId, new Slf4jLogConsumer(log).withPrefix(container.getNames()[0])); } //follow logs using registered consumers for this service logConsumers.getOrDefault(serviceName, Collections.emptyList()).forEach(consumer -> followLogs(containerId, consumer)); @@ -208,6 +214,13 @@ private String getServiceNameFromContainer(Container container) { } private void runWithCompose(String cmd) { + checkNotNull(composeFiles); + checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided"); + + for (File composeFile : composeFiles) { + validate(composeFile); + } + final DockerCompose dockerCompose; if (localCompose) { dockerCompose = new LocalDockerCompose(composeFiles, project); @@ -221,6 +234,60 @@ private void runWithCompose(String cmd) { .invoke(); } + @SuppressWarnings("unchecked") + private static void validate(File composeFile) { + Yaml yaml = new Yaml(); + try (FileInputStream fileInputStream = FileUtils.openInputStream(composeFile)) { + Object template = yaml.load(fileInputStream); + validate(template, composeFile.getAbsolutePath()); + } catch (IOException e) { + log.warn("Failed to read YAML from {}", composeFile.getAbsolutePath(), e); + } + } + + @VisibleForTesting + static void validate(Object template, String identifier) { + if (!(template instanceof Map)) { + return; + } + + Map map = (Map) template; + + final Map servicesMap; + if (map.containsKey("version")) { + if (!map.containsKey("services")) { + log.debug("Compose file {} has an unknown format: 'version' is set but 'services' is not defined", identifier); + return; + } + Object services = map.get("services"); + if (!(services instanceof Map)) { + log.debug("Compose file {} has an unknown format: 'services' is not Map", identifier); + return; + } + + servicesMap = (Map) services; + } else { + servicesMap = map; + } + + for (Map.Entry entry : servicesMap.entrySet()) { + String serviceName = entry.getKey(); + Object serviceDefinition = entry.getValue(); + if (!(serviceDefinition instanceof Map)) { + log.debug("Compose file {} has an unknown format: service '{}' is not Map", identifier, serviceName); + break; + } + + if (((Map) serviceDefinition).containsKey("container_name")) { + throw new IllegalStateException(String.format( + "Compose file %s has 'container_name' property set for service '%s' but this property is not supported by Testcontainers, consider removing it", + identifier, + serviceName + )); + } + } + } + private void applyScaling() { // Apply scaling if (!scalingPreferences.isEmpty()) { @@ -254,10 +321,6 @@ private void startAmbassadorContainers() { } } - private Logger logger() { - return LoggerFactory.getLogger(DockerComposeContainer.class); - } - @Override public void stop() { synchronized (MUTEX) { @@ -476,11 +539,6 @@ interface DockerCompose { DockerCompose withEnv(Map env); void invoke(); - - default void validateFileList(List composeFiles) { - checkNotNull(composeFiles); - checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided"); - } } /** @@ -497,8 +555,6 @@ class ContainerisedDockerCompose extends GenericContainer composeFiles, String identifier) { super(TestcontainersConfiguration.getInstance().getDockerComposeContainerImage()); - validateFileList(composeFiles); - addEnv(ENV_PROJECT_NAME, identifier); // Map the docker compose file into the container @@ -599,8 +655,6 @@ class LocalDockerCompose implements DockerCompose { private Map env = new HashMap<>(); public LocalDockerCompose(List composeFiles, String identifier) { - validateFileList(composeFiles); - this.composeFiles = composeFiles; this.identifier = identifier; } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java new file mode 100644 index 00000000000..7a3121dcd32 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java @@ -0,0 +1,70 @@ +package org.testcontainers.containers; + +import com.google.common.collect.ImmutableMap; +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import java.io.File; + +import static java.util.Collections.emptyList; + +public class DockerComposeFileValidationTest { + + @Test + public void shouldValidate() { + File file = new File("src/test/resources/docker-compose-container-name-v1.yml"); + try (DockerComposeContainer container = new DockerComposeContainer<>(file)) { + Assertions.assertThatThrownBy(container::start) + .hasMessageContaining(file.getAbsolutePath()) + .hasMessageContaining("'container_name' property set for service 'redis'"); + } + } + + @Test + public void shouldRejectContainerNameV1() { + Assertions + .assertThatThrownBy(() -> { + DockerComposeContainer.validate(ImmutableMap.of( + "redis", ImmutableMap.of("container_name", "redis") + ), ""); + }) + .hasMessageContaining("'container_name' property set for service 'redis'"); + } + + @Test + public void shouldRejectContainerNameV2() { + Assertions + .assertThatThrownBy(() -> { + DockerComposeContainer.validate(ImmutableMap.of( + "version", "2", + "services", ImmutableMap.of( + "redis", ImmutableMap.of("container_name", "redis") + ) + ), ""); + }) + .hasMessageContaining("'container_name' property set for service 'redis'"); + } + + @Test + public void shouldIgnoreUnknownStructure() { + // Everything is a list + DockerComposeContainer.validate(emptyList(), ""); + + // services is not a map but List + DockerComposeContainer.validate(ImmutableMap.of( + "version", "2", + "services", emptyList() + ), ""); + + // services is not a collection + DockerComposeContainer.validate(ImmutableMap.of( + "version", "2", + "services", true + ), ""); + + // no services while version is defined + DockerComposeContainer.validate(ImmutableMap.of( + "version", "9000" + ), ""); + } +} diff --git a/core/src/test/resources/docker-compose-container-name-v1.yml b/core/src/test/resources/docker-compose-container-name-v1.yml new file mode 100644 index 00000000000..96af67248a0 --- /dev/null +++ b/core/src/test/resources/docker-compose-container-name-v1.yml @@ -0,0 +1,3 @@ +redis: + image: redis + container_name: redis From 151b93ac065a420d0a803d2ebb8ba6d152c783a4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sun, 21 Jul 2019 08:38:12 +0100 Subject: [PATCH 0165/4969] Allow tests to be disabled when Docker is unavailable (#1530) This commit introduces a new attribute, disabledWithoutDocker, on @Testcontainers that defaults to false. When set to true the class's tests are disabled when Docker in unavailable. --- modules/junit-jupiter/build.gradle | 3 + .../junit/jupiter/Testcontainers.java | 5 ++ .../jupiter/TestcontainersExtension.java | 41 ++++++++++- .../jupiter/TestcontainersExtensionTests.java | 72 +++++++++++++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index baab3b68bb8..08bdedc6620 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,6 +9,9 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'redis.clients:jedis:3.0.1' testCompile 'org.apache.httpcomponents:httpclient:4.5.9' + testCompile ('org.mockito:mockito-core:2.28.2') { + exclude(module: 'hamcrest-core') + } testRuntime 'org.postgresql:postgresql:42.2.6' testRuntime 'mysql:mysql-connector-java:8.0.16' diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java index ecf59ff1399..6a364cd19e6 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java @@ -53,4 +53,9 @@ @Retention(RetentionPolicy.RUNTIME) @ExtendWith(TestcontainersExtension.class) public @interface Testcontainers { + + /** + * Whether tests should be disabled (rather than failing) when Docker is not available. + */ + boolean disabledWithoutDocker() default false; } diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java index 7f6183cc74d..e6ce10f8541 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java @@ -5,8 +5,10 @@ import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; import org.junit.platform.commons.support.AnnotationSupport; +import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; +import org.testcontainers.DockerClientFactory; import org.testcontainers.lifecycle.Startable; import java.lang.reflect.Field; @@ -16,7 +18,7 @@ import java.util.function.Predicate; import java.util.stream.Stream; -class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, TestInstancePostProcessor { +class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, ExecutionCondition, TestInstancePostProcessor { private static final Namespace NAMESPACE = Namespace.create(TestcontainersExtension.class); @@ -48,6 +50,43 @@ public void beforeEach(final ExtensionContext context) { .getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start())); } + @Override + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + return findTestcontainers(context).map(this::evaluate) + .orElseThrow(() -> new ExtensionConfigurationException("@Testcontainers not found")); + } + + private Optional findTestcontainers(ExtensionContext context) { + Optional current = Optional.of(context); + while (current.isPresent()) { + Optional testcontainers = AnnotationUtils.findAnnotation(current.get().getRequiredTestClass(), Testcontainers.class); + if (testcontainers.isPresent()) { + return testcontainers; + } + current = current.get().getParent(); + } + return Optional.empty(); + } + + private ConditionEvaluationResult evaluate(Testcontainers testcontainers) { + if (testcontainers.disabledWithoutDocker()) { + if (isDockerAvailable()) { + return ConditionEvaluationResult.enabled("Docker is available"); + } + return ConditionEvaluationResult.disabled("disabledWithoutDocker is true and Docker is not available"); + } + return ConditionEvaluationResult.enabled("disabledWithoutDocker is false"); + } + + boolean isDockerAvailable() { + try { + DockerClientFactory.instance().client(); + return true; + } catch (Throwable ex) { + return false; + } + } + private Set collectParentTestInstances(final ExtensionContext context) { Set testInstances = new LinkedHashSet<>(); Optional current = Optional.of(context); diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java new file mode 100644 index 00000000000..f3aea9bb850 --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java @@ -0,0 +1,72 @@ +package org.testcontainers.junit.jupiter; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExtensionContext; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class TestcontainersExtensionTests { + + @Test + void whenDisabledWithoutDockerAndDockerIsAvailableTestsAreEnabled() { + ConditionEvaluationResult result = new TestTestcontainersExtension(true) + .evaluateExecutionCondition(extensionContext(DisabledWithoutDocker.class)); + assertFalse(result.isDisabled()); + } + + @Test + void whenDisabledWithoutDockerAndDockerIsUnavailableTestsAreDisabled() { + ConditionEvaluationResult result = new TestTestcontainersExtension(false) + .evaluateExecutionCondition(extensionContext(DisabledWithoutDocker.class)); + assertTrue(result.isDisabled()); + } + + @Test + void whenEnabledWithoutDockerAndDockerIsAvailableTestsAreEnabled() { + ConditionEvaluationResult result = new TestTestcontainersExtension(true) + .evaluateExecutionCondition(extensionContext(EnabledWithoutDocker.class)); + assertFalse(result.isDisabled()); + } + + @Test + void whenEnabledWithoutDockerAndDockerIsUnavailableTestsAreEnabled() { + ConditionEvaluationResult result = new TestTestcontainersExtension(false) + .evaluateExecutionCondition(extensionContext(EnabledWithoutDocker.class)); + assertFalse(result.isDisabled()); + } + + private ExtensionContext extensionContext(Class clazz) { + ExtensionContext extensionContext = mock(ExtensionContext.class); + when(extensionContext.getRequiredTestClass()).thenReturn(clazz); + return extensionContext; + } + + @Testcontainers(disabledWithoutDocker = true) + static final class DisabledWithoutDocker { + + } + + @Testcontainers + static final class EnabledWithoutDocker { + + } + + static final class TestTestcontainersExtension extends TestcontainersExtension { + + private final boolean dockerAvailable; + + private TestTestcontainersExtension(boolean dockerAvailable) { + this.dockerAvailable = dockerAvailable; + } + + boolean isDockerAvailable() { + return dockerAvailable; + } + + } + +} From f1565f1ba842ccfa9d8ed9ee00276f38b7a2546f Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 21 Jul 2019 10:01:38 +0100 Subject: [PATCH 0166/4969] Fail gracefully if no JDBC driver found (#1434) * WIP * Simplify code * Ensure that HikariCP uses the correct driver (Auto-selected driver on classpath seems to be MariaDB; seemingly not compatible with 8.0.16 of MySQL) * Cleanup old Hikari pools after use to avoid reconnection attempts to dead containers after test has already completed * Update following review comments --- .../containers/ContainerLaunchException.java | 4 +- core/src/test/resources/logback-test.xml | 2 - .../src/test/resources/logback-test.xml | 14 --- .../src/test/resources/logback-test.xml | 10 +-- .../src/test/resources/logback-test.xml | 14 ++- .../src/test/resources/logback-test.xml | 10 +-- .../src/test/resources/logback-test.xml | 10 +-- .../src/test/resources/logback-test.xml | 10 +-- .../spock/src/test/resources/logback-test.xml | 13 +-- .../src/test/resources/logback-test.xml | 7 +- .../src/test/resources/logback-test.xml | 3 +- .../src/test/resources/logback-test.xml | 13 +-- .../src/test/resources/logback-test.xml | 14 +-- .../src/test/resources/logback-test.xml | 5 +- .../src/test/resources/logback-test.xml | 12 +-- .../junit/AbstractContainerDatabaseTest.java | 16 +++- .../src/test/resources/logback-test.xml | 13 +-- .../containers/JdbcDatabaseContainer.java | 89 ++++++++++++------- .../jdbc/MissingJdbcDriverTest.java | 86 ++++++++++++++++++ .../jdbc/src/test/resources/logback-test.xml | 16 ++++ .../src/test/resources/logback-test.xml | 5 +- .../kafka/src/test/resources/logback-test.xml | 4 +- .../src/test/resources/logback-test.xml | 17 +--- .../neo4j/src/test/resources/logback-test.xml | 4 +- .../nginx/src/test/resources/logback-test.xml | 13 +-- .../src/test/resources/logback-test.xml | 13 +-- .../containers/PostgreSQLContainer.java | 3 +- .../src/test/resources/logback-test.xml | 4 +- .../src/test/resources/logback-test.xml | 13 +-- .../spock/src/test/resources/logback-test.xml | 5 +- .../vault/src/test/resources/logback-test.xml | 14 +-- 31 files changed, 229 insertions(+), 227 deletions(-) create mode 100644 modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java create mode 100644 modules/jdbc/src/test/resources/logback-test.xml diff --git a/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java b/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java index 9943d9f612b..bf407c16808 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java @@ -9,7 +9,7 @@ public ContainerLaunchException(String message) { super(message); } - public ContainerLaunchException(String message, Exception exception) { - super(message, exception); + public ContainerLaunchException(String message, Throwable cause) { + super(message, cause); } } diff --git a/core/src/test/resources/logback-test.xml b/core/src/test/resources/logback-test.xml index 57a53cdd3aa..5e96a70b244 100644 --- a/core/src/test/resources/logback-test.xml +++ b/core/src/test/resources/logback-test.xml @@ -14,10 +14,8 @@ - - diff --git a/docs/examples/src/test/resources/logback-test.xml b/docs/examples/src/test/resources/logback-test.xml index 49da0be9709..62bc2c43d3a 100644 --- a/docs/examples/src/test/resources/logback-test.xml +++ b/docs/examples/src/test/resources/logback-test.xml @@ -1,5 +1,4 @@ - @@ -11,17 +10,4 @@ - - - - - - - - - - - PROFILER - DENY - diff --git a/examples/disque-job-queue/src/test/resources/logback-test.xml b/examples/disque-job-queue/src/test/resources/logback-test.xml index c53f381fca5..be4ebaed2c8 100644 --- a/examples/disque-job-queue/src/test/resources/logback-test.xml +++ b/examples/disque-job-queue/src/test/resources/logback-test.xml @@ -4,15 +4,11 @@ - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n - + - - - - - \ No newline at end of file + diff --git a/examples/linked-container/src/test/resources/logback-test.xml b/examples/linked-container/src/test/resources/logback-test.xml index 23f40bbec32..be4ebaed2c8 100644 --- a/examples/linked-container/src/test/resources/logback-test.xml +++ b/examples/linked-container/src/test/resources/logback-test.xml @@ -1,16 +1,14 @@ + + - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n - + - - - - - - \ No newline at end of file + diff --git a/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml b/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml index c53f381fca5..be4ebaed2c8 100644 --- a/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml +++ b/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml @@ -4,15 +4,11 @@ - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n - + - - - - - \ No newline at end of file + diff --git a/examples/redis-backed-cache/src/test/resources/logback-test.xml b/examples/redis-backed-cache/src/test/resources/logback-test.xml index c53f381fca5..be4ebaed2c8 100644 --- a/examples/redis-backed-cache/src/test/resources/logback-test.xml +++ b/examples/redis-backed-cache/src/test/resources/logback-test.xml @@ -4,15 +4,11 @@ - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n - + - - - - - \ No newline at end of file + diff --git a/examples/selenium-container/src/test/resources/logback-test.xml b/examples/selenium-container/src/test/resources/logback-test.xml index c53f381fca5..be4ebaed2c8 100644 --- a/examples/selenium-container/src/test/resources/logback-test.xml +++ b/examples/selenium-container/src/test/resources/logback-test.xml @@ -4,15 +4,11 @@ - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n - + - - - - - \ No newline at end of file + diff --git a/examples/spock/src/test/resources/logback-test.xml b/examples/spock/src/test/resources/logback-test.xml index 6e7cfd092de..535e406fc13 100644 --- a/examples/spock/src/test/resources/logback-test.xml +++ b/examples/spock/src/test/resources/logback-test.xml @@ -12,16 +12,5 @@ - - - - - - - - - - PROFILER - DENY - + diff --git a/examples/spring-boot/src/test/resources/logback-test.xml b/examples/spring-boot/src/test/resources/logback-test.xml index 86c4c861a78..5431cb6200b 100644 --- a/examples/spring-boot/src/test/resources/logback-test.xml +++ b/examples/spring-boot/src/test/resources/logback-test.xml @@ -1,8 +1,3 @@ - - - - - - \ No newline at end of file + diff --git a/modules/cassandra/src/test/resources/logback-test.xml b/modules/cassandra/src/test/resources/logback-test.xml index fc48b14c7de..535e406fc13 100644 --- a/modules/cassandra/src/test/resources/logback-test.xml +++ b/modules/cassandra/src/test/resources/logback-test.xml @@ -13,5 +13,4 @@ - - \ No newline at end of file + diff --git a/modules/couchbase/src/test/resources/logback-test.xml b/modules/couchbase/src/test/resources/logback-test.xml index d163f3ececb..535e406fc13 100644 --- a/modules/couchbase/src/test/resources/logback-test.xml +++ b/modules/couchbase/src/test/resources/logback-test.xml @@ -8,18 +8,9 @@ - + - - - - - - - - - - + diff --git a/modules/dynalite/src/test/resources/logback-test.xml b/modules/dynalite/src/test/resources/logback-test.xml index 5d27573a3cb..535e406fc13 100644 --- a/modules/dynalite/src/test/resources/logback-test.xml +++ b/modules/dynalite/src/test/resources/logback-test.xml @@ -8,17 +8,9 @@ - + - - - - - - - - - - \ No newline at end of file + + diff --git a/modules/elasticsearch/src/test/resources/logback-test.xml b/modules/elasticsearch/src/test/resources/logback-test.xml index 6d3eb183989..535e406fc13 100644 --- a/modules/elasticsearch/src/test/resources/logback-test.xml +++ b/modules/elasticsearch/src/test/resources/logback-test.xml @@ -8,10 +8,9 @@ - + - - + diff --git a/modules/influxdb/src/test/resources/logback-test.xml b/modules/influxdb/src/test/resources/logback-test.xml index e8f35ff1c79..535e406fc13 100644 --- a/modules/influxdb/src/test/resources/logback-test.xml +++ b/modules/influxdb/src/test/resources/logback-test.xml @@ -8,17 +8,9 @@ - + - - - - - - - - - + diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java index a01146fe7a3..7230759382d 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java @@ -2,15 +2,20 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; +import org.junit.After; import org.testcontainers.containers.JdbcDatabaseContainer; import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.HashSet; +import java.util.Set; abstract class AbstractContainerDatabaseTest { + private final Set datasourcesForCleanup = new HashSet<>(); + ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLException { DataSource ds = getDataSource(container); Statement statement = ds.getConnection().createStatement(); @@ -26,7 +31,16 @@ DataSource getDataSource(JdbcDatabaseContainer container) { hikariConfig.setJdbcUrl(container.getJdbcUrl()); hikariConfig.setUsername(container.getUsername()); hikariConfig.setPassword(container.getPassword()); + hikariConfig.setDriverClassName(container.getDriverClassName()); + + final HikariDataSource dataSource = new HikariDataSource(hikariConfig); + datasourcesForCleanup.add(dataSource); + + return dataSource; + } - return new HikariDataSource(hikariConfig); + @After + public void teardown() { + datasourcesForCleanup.forEach(HikariDataSource::close); } } diff --git a/modules/jdbc-test/src/test/resources/logback-test.xml b/modules/jdbc-test/src/test/resources/logback-test.xml index b0f6b00e3e0..535e406fc13 100644 --- a/modules/jdbc-test/src/test/resources/logback-test.xml +++ b/modules/jdbc-test/src/test/resources/logback-test.xml @@ -8,18 +8,9 @@ - + - - - - - - - - - - + diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index e480070168f..36a6461aa74 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -1,11 +1,8 @@ package org.testcontainers.containers; -import lombok.NonNull; import com.github.dockerjava.api.command.InspectContainerResponse; +import lombok.NonNull; import org.jetbrains.annotations.NotNull; -import org.rnorth.ducttape.ratelimits.RateLimiter; -import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; -import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.delegate.DatabaseDelegate; import org.testcontainers.ext.ScriptUtils; @@ -19,7 +16,6 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; /** * Base class for containers that expose a JDBC connection @@ -33,11 +29,6 @@ public abstract class JdbcDatabaseContainer parameters = new HashMap<>(); - private static final RateLimiter DB_CONNECT_RATE_LIMIT = RateLimiterBuilder.newBuilder() - .withRate(10, TimeUnit.SECONDS) - .withConstantThroughput() - .build(); - private int startupTimeoutSeconds = 120; private int connectTimeoutSeconds = 120; @@ -123,26 +114,39 @@ public SELF withInitScript(String initScriptPath) { @Override protected void waitUntilContainerStarted() { - // Repeatedly try and open a connection to the DB and execute a test query - logger().info("Waiting for database connection to become available at {} using query '{}'", getJdbcUrl(), getTestQueryString()); - Unreliables.retryUntilSuccess(getStartupTimeoutSeconds(), TimeUnit.SECONDS, () -> { - if (!isRunning()) { - throw new ContainerLaunchException("Container failed to start"); - } - - try (Connection connection = createConnection("")) { - boolean success = connection.createStatement().execute(JdbcDatabaseContainer.this.getTestQueryString()); - - if (success) { - logger().info("Obtained a connection to container ({})", JdbcDatabaseContainer.this.getJdbcUrl()); - return null; - } else { - throw new SQLException("Failed to execute test query"); + // Repeatedly try and open a connection to the DB and execute a test query + long start = System.currentTimeMillis(); + try { + while (System.currentTimeMillis() < start + (1000 * startupTimeoutSeconds)) { + try { + if (!isRunning()) { + Thread.sleep(100L); + continue; // Don't attempt to connect yet + } + + try (Connection connection = createConnection("")) { + boolean testQuerySucceeded = connection.createStatement().execute(this.getTestQueryString()); + if (testQuerySucceeded) { + break; + } + } + } catch (NoDriverFoundException e) { + // we explicitly want this exception to fail fast without retries + throw e; + } catch (Exception e) { + // ignore so that we can try again + logger().debug("Failure when trying test query", e); + Thread.sleep(100L); } } - }); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ContainerLaunchException("Container startup wait was interrupted", e); + } + + logger().info("Container is started (JDBC URL: {})", JdbcDatabaseContainer.this.getJdbcUrl()); } @Override @@ -155,14 +159,14 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { * * @return a JDBC Driver */ - public Driver getJdbcDriverInstance() { + public Driver getJdbcDriverInstance() throws NoDriverFoundException { synchronized (DRIVER_LOAD_MUTEX) { if (driver == null) { try { driver = (Driver) Class.forName(this.getDriverClassName()).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - throw new RuntimeException("Could not get Driver", e); + throw new NoDriverFoundException("Could not get Driver", e); } } } @@ -178,7 +182,7 @@ public Driver getJdbcDriverInstance() { * @return a Connection * @throws SQLException if there is a repeated failure to create the connection */ - public Connection createConnection(String queryString) throws SQLException { + public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException { final Properties info = new Properties(); info.put("user", this.getUsername()); info.put("password", this.getPassword()); @@ -186,13 +190,24 @@ public Connection createConnection(String queryString) throws SQLException { final Driver jdbcDriverInstance = getJdbcDriverInstance(); + SQLException lastException = null; try { - return Unreliables.retryUntilSuccess(getConnectTimeoutSeconds(), TimeUnit.SECONDS, () -> - DB_CONNECT_RATE_LIMIT.getWhenReady(() -> - jdbcDriverInstance.connect(url, info))); - } catch (Exception e) { - throw new SQLException("Could not create new connection", e); + long start = System.currentTimeMillis(); + // give up if we hit the time limit or the container stops running for some reason + while (System.currentTimeMillis() < start + (1000 * connectTimeoutSeconds) && isRunning()) { + try { + logger().debug("Trying to create JDBC connection using {} to {} with properties: {}", driver.getClass().getName(), url, info); + + return jdbcDriverInstance.connect(url, info); + } catch (SQLException e) { + lastException = e; + Thread.sleep(100L); + } + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } + throw new SQLException("Could not create new connection", lastException); } /** @@ -256,4 +271,10 @@ protected int getConnectTimeoutSeconds() { protected DatabaseDelegate getDatabaseDelegate() { return new JdbcDatabaseDelegate(this, ""); } + + public static class NoDriverFoundException extends RuntimeException { + public NoDriverFoundException(String message, Throwable e) { + super(message, e); + } + } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java new file mode 100644 index 00000000000..38ae38095eb --- /dev/null +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java @@ -0,0 +1,86 @@ +package org.testcontainers.jdbc; + +import com.google.common.base.Throwables; +import org.junit.Test; +import org.testcontainers.containers.JdbcDatabaseContainer; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.rnorth.visibleassertions.VisibleAssertions.fail; + +public class MissingJdbcDriverTest { + + @Test + public void shouldFailFastIfNoDriverFound() { + + final MissingDriverContainer container = new MissingDriverContainer(); + + try { + container.start(); + fail("The container is expected to fail to start"); + } catch (Exception e) { + final Throwable rootCause = Throwables.getRootCause(e); + assertTrue("ClassNotFoundException is the root cause", rootCause instanceof ClassNotFoundException); + } finally { + container.stop(); + } + + assertEquals("only one connection attempt should have been made", 1, container.getConnectionAttempts()); + } + + /** + * Container class for the purposes of testing, with a known non-existent driver + */ + static class MissingDriverContainer extends JdbcDatabaseContainer { + private final AtomicInteger connectionAttempts = new AtomicInteger(); + + MissingDriverContainer() { + super("mysql:5.7.22"); + withEnv("MYSQL_ROOT_PASSWORD", "test"); + withExposedPorts(3306); + } + + @Override + public String getDriverClassName() { + return "nonexistent.ClassName"; + } + + @Override + public String getJdbcUrl() { + return ""; + } + + @Override + public String getUsername() { + return "root"; + } + + @Override + public String getPassword() { + return "test"; + } + + @Override + protected String getTestQueryString() { + return ""; + } + + @Override + public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException { + connectionAttempts.incrementAndGet(); // + return super.createConnection(queryString); + } + + /** + * test window + * @return how many times a connection was attempted + */ + int getConnectionAttempts() { + return connectionAttempts.get(); + } + } +} diff --git a/modules/jdbc/src/test/resources/logback-test.xml b/modules/jdbc/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/jdbc/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/junit-jupiter/src/test/resources/logback-test.xml b/modules/junit-jupiter/src/test/resources/logback-test.xml index 1d1a7695915..535e406fc13 100644 --- a/modules/junit-jupiter/src/test/resources/logback-test.xml +++ b/modules/junit-jupiter/src/test/resources/logback-test.xml @@ -8,8 +8,9 @@ - + - \ No newline at end of file + + diff --git a/modules/kafka/src/test/resources/logback-test.xml b/modules/kafka/src/test/resources/logback-test.xml index 7bd6a94d827..535e406fc13 100644 --- a/modules/kafka/src/test/resources/logback-test.xml +++ b/modules/kafka/src/test/resources/logback-test.xml @@ -13,6 +13,4 @@ - - - \ No newline at end of file + diff --git a/modules/localstack/src/test/resources/logback-test.xml b/modules/localstack/src/test/resources/logback-test.xml index cc69fdf0ce0..535e406fc13 100644 --- a/modules/localstack/src/test/resources/logback-test.xml +++ b/modules/localstack/src/test/resources/logback-test.xml @@ -8,20 +8,9 @@ - + - - - - - - - - - - - - - \ No newline at end of file + + diff --git a/modules/neo4j/src/test/resources/logback-test.xml b/modules/neo4j/src/test/resources/logback-test.xml index 7bd6a94d827..535e406fc13 100644 --- a/modules/neo4j/src/test/resources/logback-test.xml +++ b/modules/neo4j/src/test/resources/logback-test.xml @@ -13,6 +13,4 @@ - - - \ No newline at end of file + diff --git a/modules/nginx/src/test/resources/logback-test.xml b/modules/nginx/src/test/resources/logback-test.xml index b0f6b00e3e0..535e406fc13 100644 --- a/modules/nginx/src/test/resources/logback-test.xml +++ b/modules/nginx/src/test/resources/logback-test.xml @@ -8,18 +8,9 @@ - + - - - - - - - - - - + diff --git a/modules/oracle-xe/src/test/resources/logback-test.xml b/modules/oracle-xe/src/test/resources/logback-test.xml index b0f6b00e3e0..535e406fc13 100644 --- a/modules/oracle-xe/src/test/resources/logback-test.xml +++ b/modules/oracle-xe/src/test/resources/logback-test.xml @@ -8,18 +8,9 @@ - + - - - - - - - - - - + diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index eb7b78b1864..a9429210261 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -59,7 +59,8 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + "/" + databaseName; + // Disable Postgres driver use of java.util.logging to reduce noise at startup time + return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + "/" + databaseName + "?loggerLevel=OFF"; } @Override diff --git a/modules/pulsar/src/test/resources/logback-test.xml b/modules/pulsar/src/test/resources/logback-test.xml index 7bd6a94d827..535e406fc13 100644 --- a/modules/pulsar/src/test/resources/logback-test.xml +++ b/modules/pulsar/src/test/resources/logback-test.xml @@ -13,6 +13,4 @@ - - - \ No newline at end of file + diff --git a/modules/selenium/src/test/resources/logback-test.xml b/modules/selenium/src/test/resources/logback-test.xml index b0f6b00e3e0..535e406fc13 100644 --- a/modules/selenium/src/test/resources/logback-test.xml +++ b/modules/selenium/src/test/resources/logback-test.xml @@ -8,18 +8,9 @@ - + - - - - - - - - - - + diff --git a/modules/spock/src/test/resources/logback-test.xml b/modules/spock/src/test/resources/logback-test.xml index 1d1a7695915..535e406fc13 100644 --- a/modules/spock/src/test/resources/logback-test.xml +++ b/modules/spock/src/test/resources/logback-test.xml @@ -8,8 +8,9 @@ - + - \ No newline at end of file + + diff --git a/modules/vault/src/test/resources/logback-test.xml b/modules/vault/src/test/resources/logback-test.xml index 5d27573a3cb..535e406fc13 100644 --- a/modules/vault/src/test/resources/logback-test.xml +++ b/modules/vault/src/test/resources/logback-test.xml @@ -8,17 +8,9 @@ - + - - - - - - - - - - \ No newline at end of file + + From 67501e83ffb759256d4f1752683e77e17d1fbf70 Mon Sep 17 00:00:00 2001 From: Jameel Al-Aziz <247849+jalaziz@users.noreply.github.com> Date: Sun, 21 Jul 2019 02:42:35 -0700 Subject: [PATCH 0167/4969] Add container stopping and stopped hooks (#1610) Add pre-stop and post-stop hooks to the GenericContainer. This provides symmetry to the equavilent starting/started hooks and allows custom behaviour to be defined in sub-classes. --- .../containers/GenericContainer.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 8045d47c720..7e37839979b 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -333,7 +333,9 @@ public void stop() { imageName = ""; } + containerIsStopping(containerInfo); ResourceReaper.instance().stopAndRemoveContainer(containerId, imageName); + containerIsStopped(containerInfo); } finally { containerId = null; containerInfo = null; @@ -382,6 +384,24 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { protected void containerIsStarted(InspectContainerResponse containerInfo) { } + /** + * A hook that is executed before the container is stopped with {@link #stop()}. + * Warning! This hook won't be executed if the container is terminated during + * the JVM's shutdown hook or by Ryuk. + */ + @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) + protected void containerIsStopping(InspectContainerResponse containerInfo) { + } + + /** + * A hook that is executed after the container is stopped with {@link #stop()}. + * Warning! This hook won't be executed if the container is terminated during + * the JVM's shutdown hook or by Ryuk. + */ + @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) + protected void containerIsStopped(InspectContainerResponse containerInfo) { + } + /** * @return the port on which to check if the container is ready * @deprecated see {@link GenericContainer#getLivenessCheckPorts()} for replacement From 908a4ecebddf7cc2b053f64f7bf0550192c041a4 Mon Sep 17 00:00:00 2001 From: kellen Date: Mon, 22 Jul 2019 05:06:53 -0400 Subject: [PATCH 0168/4969] Enable command override for PostgreSQLContainer (#938) --- .../junit/SimplePostgreSQLTest.java | 30 +++++++++++++++---- .../containers/PostgreSQLContainer.java | 3 +- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java index c6685343c29..4624268cb2b 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java @@ -7,10 +7,8 @@ import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; -/** - * @author richardnorth - */ public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { @Test @@ -19,16 +17,36 @@ public void testSimple() throws SQLException { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT 1"); - int resultSetInt = resultSet.getInt(1); assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } + @Test + public void testCommandOverride() throws SQLException { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42")) { + postgres.start(); + + ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); + String result = resultSet.getString(1); + assertEquals("max_connections should be overriden", "42", result); + } + } + + @Test + public void testUnsetCommand() throws SQLException { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42").withCommand()) { + postgres.start(); + + ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); + String result = resultSet.getString(1); + assertNotEquals("max_connections should not be overriden", "42", result); + } + } + @Test public void testExplicitInitScript() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>() - .withInitScript("somepath/init_postgresql.sql")) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withInitScript("somepath/init_postgresql.sql")) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index a9429210261..85ad910aa17 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -34,6 +34,7 @@ public PostgreSQLContainer(final String dockerImageName) { .withRegEx(".*database system is ready to accept connections.*\\s") .withTimes(2) .withStartupTimeout(Duration.of(60, SECONDS)); + this.setCommand("postgres", "-c", FSYNC_OFF_OPTION); } @NotNull @@ -44,12 +45,10 @@ protected Set getLivenessCheckPorts() { @Override protected void configure() { - addExposedPort(POSTGRESQL_PORT); addEnv("POSTGRES_DB", databaseName); addEnv("POSTGRES_USER", username); addEnv("POSTGRES_PASSWORD", password); - setCommand("postgres", "-c", FSYNC_OFF_OPTION); } @Override From 4df20c2d1d090d8f2d3129ec24b0988faecbe896 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 22 Jul 2019 17:47:59 +0100 Subject: [PATCH 0169/4969] Improve image pull handling, with better logging and timeout behaviour (#1320) --- .../testcontainers/DockerClientFactory.java | 15 ++- .../containers/DockerComposeContainer.java | 8 +- .../containers/GenericContainer.java | 46 ++++++- .../images/LoggedPullImageResultCallback.java | 121 ++++++++++++++++++ .../images/RemoteDockerImage.java | 98 +++++++------- ...eLimitedLoggedPullImageResultCallback.java | 117 +++++++++++++++++ .../images/builder/ImageFromDockerfile.java | 23 ++-- .../utility/RegistryAuthLocator.java | 8 +- .../utility/TestcontainersConfiguration.java | 4 + .../dockerclient/ImagePullTest.java | 1 + docs/features/configuration.md | 4 + 11 files changed, 362 insertions(+), 83 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java create mode 100644 core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 72cff0217cd..928b4cad291 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -4,12 +4,17 @@ import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; -import com.github.dockerjava.api.model.*; +import com.github.dockerjava.api.model.AccessMode; +import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.Image; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.api.model.Version; +import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.core.command.ExecStartResultCallback; -import com.github.dockerjava.core.command.PullImageResultCallback; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import lombok.Getter; +import lombok.SneakyThrows; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.hamcrest.BaseMatcher; @@ -17,6 +22,7 @@ import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; +import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.ResourceReaper; @@ -125,7 +131,7 @@ public DockerClient client() { ryukContainerId = ResourceReaper.start(hostIpAddress, client); log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit"); } - + boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks(); if (checksEnabled) { VisibleAssertions.info("Checking the system..."); @@ -215,10 +221,11 @@ private boolean checkMountableFile() { /** * Check whether the image is available locally and pull it otherwise */ + @SneakyThrows public void checkAndPullImage(DockerClient client, String image) { List images = client.listImagesCmd().withImageNameFilter(image).exec(); if (images.isEmpty()) { - client.pullImageCmd(image).exec(new PullImageResultCallback()).awaitSuccess(); + client.pullImageCmd(image).exec(new TimeLimitedLoggedPullImageResultCallback(log)).awaitCompletion(); } } diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 06a8bd9d597..b21e160d892 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -19,9 +19,7 @@ import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.containers.wait.strategy.WaitAllStrategy; -import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.containers.wait.strategy.*; import org.testcontainers.lifecycle.Startable; import org.testcontainers.utility.*; import org.yaml.snakeyaml.Yaml; @@ -32,9 +30,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; +import java.nio.file.*; import java.time.Duration; import java.util.AbstractMap.SimpleEntry; import java.util.*; diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 7e37839979b..c2701c2f87e 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -3,9 +3,22 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.InspectContainerResponse; -import com.github.dockerjava.api.model.*; +import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.ContainerNetwork; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.api.model.Link; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Volume; +import com.github.dockerjava.api.model.VolumesFrom; import com.google.common.base.Strings; -import lombok.*; +import lombok.AccessLevel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.Setter; +import lombok.SneakyThrows; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; @@ -33,13 +46,34 @@ import org.testcontainers.lifecycle.Startable; import org.testcontainers.lifecycle.TestDescription; import org.testcontainers.lifecycle.TestLifecycleAware; -import org.testcontainers.utility.*; - -import java.io.*; +import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerLoggerFactory; +import org.testcontainers.utility.DockerMachineClient; +import org.testcontainers.utility.MountableFile; +import org.testcontainers.utility.PathUtils; +import org.testcontainers.utility.ResourceReaper; +import org.testcontainers.utility.TestcontainersConfiguration; +import org.testcontainers.utility.ThrowingFunction; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.nio.charset.Charset; import java.nio.file.Path; import java.time.Duration; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; diff --git a/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java b/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java new file mode 100644 index 00000000000..71b797298aa --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java @@ -0,0 +1,121 @@ +package org.testcontainers.images; + +import com.github.dockerjava.api.model.PullResponseItem; +import com.github.dockerjava.core.command.PullImageResultCallback; +import org.slf4j.Logger; + +import java.io.Closeable; +import java.time.Duration; +import java.time.Instant; +import java.util.*; + +import static java.lang.String.format; +import static org.apache.commons.io.FileUtils.byteCountToDisplaySize; + +/** + * {@link PullImageResultCallback} with improved logging of pull progress. + */ +class LoggedPullImageResultCallback extends PullImageResultCallback { + private final Logger logger; + + private final Set allLayers = new HashSet<>(); + private final Set downloadedLayers = new HashSet<>(); + private final Set pulledLayers = new HashSet<>(); + private final Map totalSizes = new HashMap<>(); + private final Map currentSizes = new HashMap<>(); + private boolean completed; + private Instant start; + + LoggedPullImageResultCallback(final Logger logger) { + this.logger = logger; + } + + @Override + public void onStart(final Closeable stream) { + super.onStart(stream); + start = Instant.now(); + + logger.info("Starting to pull image"); + } + + @Override + public void onNext(final PullResponseItem item) { + super.onNext(item); + + final String statusLowercase = item.getStatus() != null ? item.getStatus().toLowerCase() : ""; + final String id = item.getId(); + + if (item.getProgressDetail() != null) { + allLayers.add(id); + } + + if (statusLowercase.equalsIgnoreCase("download complete")) { + downloadedLayers.add(id); + } + + if (statusLowercase.equalsIgnoreCase("pull complete")) { + pulledLayers.add(id); + } + + if (item.getProgressDetail() != null) { + Long total = item.getProgressDetail().getTotal(); + Long current = item.getProgressDetail().getCurrent(); + + if (total != null && total > totalSizes.getOrDefault(id, 0L)) { + totalSizes.put(id, total); + } + if (current != null && current > currentSizes.getOrDefault(id, 0L)) { + currentSizes.put(id, current); + } + } + + if (statusLowercase.startsWith("pulling from" ) || statusLowercase.contains("complete" )) { + + long totalSize = totalLayerSize(); + long currentSize = downloadedLayerSize(); + + int pendingCount = allLayers.size() - downloadedLayers.size(); + String friendlyTotalSize; + if (pendingCount > 0) { + friendlyTotalSize = "? MB"; + } else { + friendlyTotalSize = byteCountToDisplaySize(totalSize); + } + + logger.info("Pulling image layers: {} pending, {} downloaded, {} extracted, ({}/{})", + format("%2d", pendingCount), + format("%2d", downloadedLayers.size()), + format("%2d", pulledLayers.size()), + byteCountToDisplaySize(currentSize), + friendlyTotalSize); + } + + if (statusLowercase.contains("complete")) { + completed = true; + } + } + + @Override + public void onComplete() { + super.onComplete(); + + final long downloadedLayerSize = downloadedLayerSize(); + final long duration = Duration.between(start, Instant.now()).getSeconds(); + + if (completed) { + logger.info("Pull complete. {} layers, pulled in {}s (downloaded {} at {}/s)", + allLayers.size(), + duration, + byteCountToDisplaySize(downloadedLayerSize), + byteCountToDisplaySize(downloadedLayerSize / duration)); + } + } + + private long downloadedLayerSize() { + return currentSizes.values().stream().filter(Objects::nonNull).mapToLong(it -> it).sum(); + } + + private long totalLayerSize() { + return totalSizes.values().stream().filter(Objects::nonNull).mapToLong(it -> it).sum(); + } +} diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index d0bc47d6b12..7aff7918f6d 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -24,6 +24,10 @@ @ToString public class RemoteDockerImage extends LazyFuture { + /** + * @deprecated this field will become private in a later release + */ + @Deprecated public static final Set AVAILABLE_IMAGE_NAME_CACHE = new HashSet<>(); private DockerImageName imageName; @@ -42,59 +46,47 @@ protected final String resolve() { DockerClient dockerClient = DockerClientFactory.instance().client(); try { - int attempts = 0; - Exception lastException = null; - while (true) { - // Does our cache already know the image? - if (AVAILABLE_IMAGE_NAME_CACHE.contains(imageName)) { - logger.trace("{} is already in image name cache", imageName); - break; - } - - // Update the cache - ListImagesCmd listImagesCmd = dockerClient.listImagesCmd(); - - if (Boolean.parseBoolean(System.getProperty("useFilter"))) { - listImagesCmd = listImagesCmd.withImageNameFilter(imageName.toString()); - } - - List updatedImages = listImagesCmd.exec(); - updatedImages.stream() - .map(Image::getRepoTags) - .filter(Objects::nonNull) - .flatMap(Stream::of) - .map(DockerImageName::new) - .collect(Collectors.toCollection(() -> AVAILABLE_IMAGE_NAME_CACHE)); - - // And now? - if (AVAILABLE_IMAGE_NAME_CACHE.contains(imageName)) { - logger.trace("{} is in image name cache following listing of images", imageName); - break; - } - - // Log only on first attempt - if (attempts == 0) { - logger.info("Pulling docker image: {}. Please be patient; this may take some time but only needs to be done once.", imageName); - } - - if (attempts++ >= 3) { - logger.error("Retry limit reached while trying to pull image: {}. Please check output of `docker pull {}`", imageName, imageName); - throw new ContainerFetchException("Retry limit reached while trying to pull image: " + imageName, lastException); - } - - // The image is not available locally - pull it - try { - final PullImageResultCallback callback = new PullImageResultCallback(); - dockerClient - .pullImageCmd(imageName.getUnversionedPart()) - .withTag(imageName.getVersionPart()) - .exec(callback); - callback.awaitCompletion(); - AVAILABLE_IMAGE_NAME_CACHE.add(imageName); - break; - } catch (Exception e) { - lastException = e; - } + // Does our cache already know the image? + if (AVAILABLE_IMAGE_NAME_CACHE.contains(imageName)) { + logger.trace("{} is already in image name cache", imageName); + return imageName.toString(); + } + + // Update the cache + ListImagesCmd listImagesCmd = dockerClient.listImagesCmd(); + + if (Boolean.parseBoolean(System.getProperty("useFilter"))) { + listImagesCmd = listImagesCmd.withImageNameFilter(imageName.toString()); + } + + List updatedImages = listImagesCmd.exec(); + updatedImages.stream() + .map(Image::getRepoTags) + .filter(Objects::nonNull) + .flatMap(Stream::of) + .map(DockerImageName::new) + .collect(Collectors.toCollection(() -> AVAILABLE_IMAGE_NAME_CACHE)); + + // And now? + if (AVAILABLE_IMAGE_NAME_CACHE.contains(imageName)) { + logger.trace("{} is in image name cache following listing of images", imageName); + return imageName.toString(); + } + + logger.info("Pulling docker image: {}. Please be patient; this may take some time but only needs to be done once.", imageName); + + // The image is not available locally - pull it + try { + final PullImageResultCallback callback = new TimeLimitedLoggedPullImageResultCallback(logger); + dockerClient + .pullImageCmd(imageName.getUnversionedPart()) + .withTag(imageName.getVersionPart()) + .exec(callback); + callback.awaitCompletion(); + AVAILABLE_IMAGE_NAME_CACHE.add(imageName); + } catch (Exception e) { + logger.error("Failed to pull image: {}. Please check output of `docker pull {}`", imageName, imageName); + throw new ContainerFetchException("Failed to pull image: " + imageName, e); } return imageName.toString(); diff --git a/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java new file mode 100644 index 00000000000..20b7de6c666 --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java @@ -0,0 +1,117 @@ +package org.testcontainers.images; + +import com.github.dockerjava.api.model.PullResponseItem; +import com.github.dockerjava.core.command.PullImageResultCallback; +import org.slf4j.Logger; +import org.testcontainers.utility.TestcontainersConfiguration; + +import java.io.Closeable; +import java.io.IOException; +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.testcontainers.DockerClientFactory.TESTCONTAINERS_THREAD_GROUP; + +/** + * {@link PullImageResultCallback} with improved logging of pull progress and a 'watchdog' which will abort the pull + * if progress is not being made, to prevent a hanging test + */ +public class TimeLimitedLoggedPullImageResultCallback extends LoggedPullImageResultCallback { + + private static final AtomicInteger THREAD_ID = new AtomicInteger(0); + private static final ScheduledExecutorService PROGRESS_WATCHDOG_EXECUTOR = + Executors.newScheduledThreadPool(0, runnable -> { + Thread t = new Thread(TESTCONTAINERS_THREAD_GROUP, runnable); + t.setDaemon(true); + t.setName("testcontainers-pull-watchdog-" + THREAD_ID.incrementAndGet()); + return t; + }); + private static final Duration PULL_PAUSE_TOLERANCE = Duration.ofSeconds(TestcontainersConfiguration.getInstance().getImagePullPauseTimeout()); + private final Logger logger; + + // A future which, if it ever fires, will kill the pull + private ScheduledFuture nextCheckForProgress; + + // All threads that are 'awaiting' this pull + private final Set waitingThreads = new HashSet<>(); + + public TimeLimitedLoggedPullImageResultCallback(Logger logger) { + super(logger); + this.logger = logger; + } + + @Override + public PullImageResultCallback awaitCompletion() throws InterruptedException { + waitingThreads.add(Thread.currentThread()); + return super.awaitCompletion(); + } + + @Override + public boolean awaitCompletion(long timeout, TimeUnit timeUnit) throws InterruptedException { + waitingThreads.add(Thread.currentThread()); + return super.awaitCompletion(timeout, timeUnit); + } + + @Override + public void onNext(PullResponseItem item) { + if (item.getProgressDetail() != null) { + resetProgressWatchdog(false); + } + super.onNext(item); + } + + @Override + public void onStart(Closeable stream) { + resetProgressWatchdog(false); + super.onStart(stream); + } + + @Override + public void onError(Throwable throwable) { + resetProgressWatchdog(true); + super.onError(throwable); + } + + @Override + public void onComplete() { + resetProgressWatchdog(true); + super.onComplete(); + } + + + /* + * This method schedules a future task which will interrupt the waiting waiting threads if ever fired. + * Every time this method is called (from onStart or onNext), the task is cancelled and recreated 30s in the future, + * ensuring that it will only fire if the method stops being called regularly (e.g. if the pull has hung). + */ + private void resetProgressWatchdog(boolean isFinished) { + if (nextCheckForProgress != null && ! nextCheckForProgress.isCancelled()) { + nextCheckForProgress.cancel(false); + } + if (!isFinished) { + nextCheckForProgress = PROGRESS_WATCHDOG_EXECUTOR.schedule( + this::abortPull, + PULL_PAUSE_TOLERANCE.getSeconds(), + TimeUnit.SECONDS + ); + } + } + + private void abortPull() { + logger.error("Docker image pull has not made progress in {}s - aborting pull", PULL_PAUSE_TOLERANCE.getSeconds()); + // Interrupt any threads that are waiting, before closing streams, because the stream can take + // an indeterminate amount of time to close + waitingThreads.forEach(Thread::interrupt); + try { + close(); + } catch (IOException ignored) { + // no action + } + } +} diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index f4968c11ff0..8c653718a69 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -14,12 +14,15 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; -import org.testcontainers.images.builder.traits.*; +import org.testcontainers.images.builder.traits.BuildContextBuilderTrait; +import org.testcontainers.images.builder.traits.ClasspathTrait; +import org.testcontainers.images.builder.traits.DockerfileTrait; +import org.testcontainers.images.builder.traits.FilesTrait; +import org.testcontainers.images.builder.traits.StringsTrait; import org.testcontainers.utility.Base58; import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.LazyFuture; -import java.io.File; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; @@ -123,7 +126,7 @@ public void onNext(BuildResponseItem item) { configure(buildImageCmd); BuildImageResultCallback exec = buildImageCmd.exec(resultCallback); - + long bytesToDockerDaemon = 0; // To build an image, we have to send the context to Docker in TAR archive format @@ -138,10 +141,10 @@ public void onNext(BuildResponseItem item) { } tarArchive.finish(); } - + log.info("Transferred {} KB to Docker daemon", FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); if (bytesToDockerDaemon > FileUtils.ONE_MB * 50) // warn if >50MB sent to docker daemon - log.warn("A large amount of data was sent to the Docker daemon ({}). Consider using a .dockerignore file for better performance.", + log.warn("A large amount of data was sent to the Docker daemon ({}). Consider using a .dockerignore file for better performance.", FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); exec.awaitImageId(); @@ -170,8 +173,8 @@ public ImageFromDockerfile withBuildArgs(final Map args) { } /** - * Sets the Dockerfile to be used for this image. - * @deprecated It is recommended to use {@link #withDockerfile} instead because it honors + * Sets the Dockerfile to be used for this image. + * @deprecated It is recommended to use {@link #withDockerfile} instead because it honors * .dockerignore files and therefore will be more efficient * @param relativePathFromBuildRoot */ @@ -180,14 +183,14 @@ public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildRoot) this.dockerFilePath = Optional.of(relativePathFromBuildRoot); return this; } - + /** - * Sets the Dockerfile to be used for this image. + * Sets the Dockerfile to be used for this image. * @param dockerfile */ public ImageFromDockerfile withDockerfile(Path dockerfile) { this.dockerfile = Optional.of(dockerfile); return this; } - + } diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index a1be23eb82e..5b248aea04e 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -209,7 +209,7 @@ private Map.Entry findAuthNode(final JsonNode config, final St private AuthConfig runCredentialProvider(String hostName, String helperOrStoreName) throws Exception { if (isBlank(hostName)) { - log.debug("There is no point to locate AuthConfig for blank hostName. Return NULL to allow fallback"); + log.debug("There is no point in locating AuthConfig for blank hostName. Returning NULL to allow fallback"); return null; } @@ -228,9 +228,9 @@ private AuthConfig runCredentialProvider(String hostName, String helperOrStoreNa if (!isBlank(responseErrorMsg)) { String credentialsNotFoundMsg = getGenericCredentialsNotFoundMsg(credentialProgramName); if (credentialsNotFoundMsg != null && credentialsNotFoundMsg.equals(responseErrorMsg)) { - log.info("Credentials not found for host ({}) when using credential helper/store ({})", - hostName, - credentialProgramName); + log.info("Credential helper/store ({}) does not have credentials for {}", + credentialProgramName, + hostName); return null; } diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index f87b02a17d3..608d02716d0 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -82,6 +82,10 @@ public String getTransportType() { return properties.getProperty("transport.type", "okhttp"); } + public Integer getImagePullPauseTimeout() { + return Integer.parseInt((String) properties.getOrDefault("pull.pause.timeout", "30")); + } + @Synchronized public boolean updateGlobalConfig(@NonNull String prop, @NonNull String value) { try { diff --git a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java index 47ad456dc26..6e319838888 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java @@ -24,6 +24,7 @@ public static String[] parameters() { "quay.io/testcontainers/ryuk:latest", "quay.io/testcontainers/ryuk:0.2.3", "quay.io/testcontainers/ryuk@sha256:bb5a635cac4bd96c93cc476969ce11dc56436238ec7cd028d0524462f4739dd9", +// "ibmcom/db2express-c", // Big image for testing with slow networks }; } diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 72b5cac65f7..2ef7e4997a3 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -59,3 +59,7 @@ but does not allow starting privileged containers, you can turn off the Ryuk con !!!tip Note that Testcontainers will continue doing the cleanup at JVM's shutdown, unless you `kill -9` your JVM process. +## Customizing image pull behaviour + +> **pull.pause.timeout = 30** +> By default Testcontainers will abort the pull of an image if the pull appears stalled (no data transferred) for longer than this duration (in seconds). From 1d686a1d99050a213572891702e531cacb372ad6 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 23 Jul 2019 10:15:36 +0200 Subject: [PATCH 0170/4969] Implement `dependsOn` for cross-container dependencies (#1404) * Implement `dependsOn` for cross-container dependencies * Add transitive test case * fix the compilation on JDK 11 * avoid a recursive update in `computeIfAbsent` * javadocs, add a test case for the diamond graph --- .../containers/GenericContainer.java | 37 ++++- .../testcontainers/lifecycle/Startable.java | 7 + .../testcontainers/lifecycle/Startables.java | 76 ++++++++++ .../junit/DependenciesTest.java | 142 ++++++++++++++++++ 4 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/testcontainers/lifecycle/Startables.java create mode 100644 core/src/test/java/org/testcontainers/junit/DependenciesTest.java diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index c2701c2f87e..14ce129c9a5 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -44,6 +44,7 @@ import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.images.builder.Transferable; import org.testcontainers.lifecycle.Startable; +import org.testcontainers.lifecycle.Startables; import org.testcontainers.lifecycle.TestDescription; import org.testcontainers.lifecycle.TestLifecycleAware; import org.testcontainers.utility.Base58; @@ -74,6 +75,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -88,7 +90,6 @@ * Base class for that allows a container to be launched and controlled. */ @Data -@EqualsAndHashCode(callSuper = false) public class GenericContainer> extends FailureDetectingExternalResource implements Container, AutoCloseable, WaitStrategyTarget, Startable { @@ -165,6 +166,8 @@ public class GenericContainer> private Map copyToFileContainerPathMap = new HashMap<>(); + protected final Set dependencies = new HashSet<>(); + /* * Unique instance of DockerClient for use by this container object. */ @@ -232,6 +235,26 @@ public GenericContainer(@NonNull final Future image) { this.image = image; } + /** + * @see #dependsOn(List) + */ + public SELF dependsOn(Startable... startables) { + Collections.addAll(dependencies, startables); + return self(); + } + + /** + * Delays this container's creation and start until provided {@link Startable}s start first. + * Note that the circular dependencies are not supported. + * + * @param startables a list of {@link Startable} to depend on + * @see Startables#deepStart(Collection) + */ + public SELF dependsOn(List startables) { + dependencies.addAll(startables); + return self(); + } + public String getContainerId() { return containerId; } @@ -240,10 +263,12 @@ public String getContainerId() { * Starts the container using docker, pulling an image if necessary. */ @Override + @SneakyThrows({InterruptedException.class, ExecutionException.class}) public void start() { if (containerId != null) { return; } + Startables.deepStart(dependencies).get(); doStart(); } @@ -1221,6 +1246,16 @@ public SELF withTmpFs(Map mapping) { return self(); } + @Override + public boolean equals(Object o) { + return this == o; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + /** * Convenience class with access to non-public members of GenericContainer. * diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startable.java b/core/src/main/java/org/testcontainers/lifecycle/Startable.java index fa2bfd9dfc5..3e73968d06e 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/Startable.java +++ b/core/src/main/java/org/testcontainers/lifecycle/Startable.java @@ -1,7 +1,14 @@ package org.testcontainers.lifecycle; +import java.util.Collections; +import java.util.Set; + public interface Startable extends AutoCloseable { + default Set getDependencies() { + return Collections.emptySet(); + } + void start(); void stop(); diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startables.java b/core/src/main/java/org/testcontainers/lifecycle/Startables.java new file mode 100644 index 00000000000..0e6452c1914 --- /dev/null +++ b/core/src/main/java/org/testcontainers/lifecycle/Startables.java @@ -0,0 +1,76 @@ +package org.testcontainers.lifecycle; + +import lombok.experimental.UtilityClass; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; + +@UtilityClass +public class Startables { + + private static final Executor EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() { + + private final AtomicLong COUNTER = new AtomicLong(0); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "testcontainers-lifecycle-" + COUNTER.getAndIncrement()); + thread.setDaemon(true); + return thread; + } + }); + + /** + * @see #deepStart(Stream) + */ + public CompletableFuture deepStart(Collection startables) { + return deepStart(startables.stream()); + } + + /** + * Start every {@link Startable} recursively and asynchronously and join on the result. + * + * Performance note: + * The method uses and returns {@link CompletableFuture}s to resolve as many {@link Startable}s at once as possible. + * This way, for the following graph: + * / b \ + * a e + * c / + * d / + * "a", "c" and "d" will resolve in parallel, then "b". + * + * If we would call blocking {@link Startable#start()}, "e" would wait for "b", "b" for "a", and only then "c", and then "d". + * But, since "c" and "d" are independent from "a", there is no point in waiting for "a" to be resolved first. + * + * @param startables a {@link Stream} of {@link Startable}s to start and scan for transitive dependencies. + * @return a {@link CompletableFuture} that resolves once all {@link Startable}s have started. + */ + public CompletableFuture deepStart(Stream startables) { + return deepStart(new HashMap<>(), startables); + } + + /** + * + * @param started an intermediate storage for already started {@link Startable}s to prevent multiple starts. + * @param startables a {@link Stream} of {@link Startable}s to start and scan for transitive dependencies. + */ + private CompletableFuture deepStart(Map> started, Stream startables) { + CompletableFuture[] futures = startables + .map(it -> { + // avoid a recursive update in `computeIfAbsent` + Map> subStarted = new HashMap<>(started); + CompletableFuture future = started.computeIfAbsent(it, startable -> { + return deepStart(subStarted, startable.getDependencies().stream()).thenRunAsync(startable::start, EXECUTOR); + }); + started.putAll(subStarted); + return future; + }) + .toArray(CompletableFuture[]::new); + + return CompletableFuture.allOf(futures); + } +} diff --git a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java new file mode 100644 index 00000000000..df7e85a31f8 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java @@ -0,0 +1,142 @@ +package org.testcontainers.junit; + +import lombok.Getter; +import org.junit.Test; +import org.rnorth.visibleassertions.VisibleAssertions; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.lifecycle.Startable; +import org.testcontainers.lifecycle.Startables; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; + +public class DependenciesTest { + + @Test + public void shouldWorkWithSimpleDependency() { + InvocationCountingStartable startable = new InvocationCountingStartable(); + + try ( + GenericContainer container = new GenericContainer() + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .dependsOn(startable) + ) { + container.start(); + } + + VisibleAssertions.assertEquals("Started once", 1, startable.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("Does not trigger .stop()", 0, startable.getStopInvocationCount().intValue()); + } + + @Test + public void shouldWorkWithMutlipleDependencies() { + InvocationCountingStartable startable1 = new InvocationCountingStartable(); + InvocationCountingStartable startable2 = new InvocationCountingStartable(); + + try ( + GenericContainer container = new GenericContainer() + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .dependsOn(startable1, startable2) + ) { + container.start(); + } + + VisibleAssertions.assertEquals("Startable1 started once", 1, startable1.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("Startable2 started once", 1, startable2.getStartInvocationCount().intValue()); + } + + @Test + public void shouldStartEveryTime() { + InvocationCountingStartable startable = new InvocationCountingStartable(); + + try ( + GenericContainer container = new GenericContainer() + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .dependsOn(startable) + ) { + container.start(); + container.stop(); + + container.start(); + container.stop(); + + container.start(); + } + + VisibleAssertions.assertEquals("Started multiple times", 3, startable.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("Does not trigger .stop()", 0, startable.getStopInvocationCount().intValue()); + } + + @Test + public void shouldStartTransitiveDependencies() { + InvocationCountingStartable transitiveOfTransitiveStartable = new InvocationCountingStartable(); + InvocationCountingStartable transitiveStartable = new InvocationCountingStartable(); + transitiveStartable.getDependencies().add(transitiveOfTransitiveStartable); + + InvocationCountingStartable startable = new InvocationCountingStartable(); + startable.getDependencies().add(transitiveStartable); + + try ( + GenericContainer container = new GenericContainer() + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .dependsOn(startable) + ) { + container.start(); + container.stop(); + } + + VisibleAssertions.assertEquals("Root started", 1, startable.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("Transitive started", 1, transitiveStartable.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("Transitive of transitive started", 1, transitiveOfTransitiveStartable.getStartInvocationCount().intValue()); + } + + @Test + public void shouldHandleDiamondDependencies() throws Exception { + InvocationCountingStartable a = new InvocationCountingStartable(); + InvocationCountingStartable b = new InvocationCountingStartable(); + InvocationCountingStartable c = new InvocationCountingStartable(); + InvocationCountingStartable d = new InvocationCountingStartable(); + // / b \ + // a d + // \ c / + b.getDependencies().add(a); + c.getDependencies().add(a); + + d.getDependencies().add(b); + d.getDependencies().add(c); + + Startables.deepStart(Stream.of(d)).get(1, TimeUnit.SECONDS); + + VisibleAssertions.assertEquals("A started", 1, a.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("B started", 1, b.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("C started", 1, c.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals("D started", 1, d.getStartInvocationCount().intValue()); + } + + private static class InvocationCountingStartable implements Startable { + + @Getter + Set dependencies = new HashSet<>(); + + @Getter + AtomicLong startInvocationCount = new AtomicLong(0); + + @Getter + AtomicLong stopInvocationCount = new AtomicLong(0); + + @Override + public void start() { + startInvocationCount.getAndIncrement(); + + } + + @Override + public void stop() { + stopInvocationCount.getAndIncrement(); + } + } +} From 64dcf7aa632b388cc5d20da2286b3eea99b003a1 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 23 Jul 2019 10:56:04 +0200 Subject: [PATCH 0171/4969] use DigitalOcean for the build cache --- settings.gradle | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/settings.gradle b/settings.gradle index e68987a50b9..272daa5699d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.4.1" + classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.9.0" } } @@ -19,8 +19,10 @@ buildCache { } remote(ch.myniva.gradle.caching.s3.AwsS3BuildCache) { - region = 'us-east-1' - bucket = 'testcontainers-build-cache' + endpoint = 'fra1.digitaloceanspaces.com' + region = 'fra1' + bucket = 'testcontainers' + path = 'cache' push = isMasterBuild } } @@ -38,4 +40,4 @@ file('modules').eachDir { dir -> } include "docs-examples" -project(":docs-examples").projectDir = file("docs/examples") \ No newline at end of file +project(":docs-examples").projectDir = file("docs/examples") From fcfff1a675d3e211b969584e842ba07f603b12ea Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 23 Jul 2019 11:53:35 +0100 Subject: [PATCH 0172/4969] Improve splitting of SQL scripts into statements (#1627) Fixes #1547 --- modules/database-commons/build.gradle | 2 + .../org/testcontainers/ext/ScriptUtils.java | 51 ++- .../ext/ScriptSplittingTest.java | 294 ++++++++++++++++++ .../testcontainers/ext/ScriptUtilsTest.java | 48 --- .../src/test/resources/splittable.sql | 45 --- 5 files changed, 337 insertions(+), 103 deletions(-) create mode 100644 modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java delete mode 100644 modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java delete mode 100644 modules/database-commons/src/test/resources/splittable.sql diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 8b9c288b9d4..27d1aeeb5e6 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -2,4 +2,6 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') + + testCompile 'org.assertj:assertj-core:3.12.2' } diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java index eb041708fb6..d30064af28e 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java @@ -163,10 +163,10 @@ public static void splitSqlScript(String resource, String script, String separat } final boolean inComment = inLineComment || inBlockComment; - if (!inLiteral && !inComment && containsSubstringAtOffset(lowerCaseScriptContent, "BEGIN", i)) { + if (!inLiteral && !inComment && containsKeywordsAtOffset(lowerCaseScriptContent, "BEGIN", i, separator, commentPrefix, blockCommentStartDelimiter)) { compoundStatementDepth++; } - if (!inLiteral && !inComment && containsSubstringAtOffset(lowerCaseScriptContent, "END", i)) { + if (!inLiteral && !inComment && containsKeywordsAtOffset(lowerCaseScriptContent, "END", i, separator, commentPrefix, blockCommentStartDelimiter)) { compoundStatementDepth--; } final boolean inCompoundStatement = compoundStatementDepth != 0; @@ -174,10 +174,7 @@ public static void splitSqlScript(String resource, String script, String separat if (!inLiteral && !inCompoundStatement) { if (script.startsWith(separator, i)) { // we've reached the end of the current statement - if (sb.length() > 0) { - statements.add(sb.toString()); - sb = new StringBuilder(); - } + sb = flushStringBuilder(sb, statements); i += separator.length() - 1; continue; } @@ -199,6 +196,7 @@ else if (script.startsWith(blockCommentStartDelimiter, i)) { int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); if (indexOfCommentEnd > i) { i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; + inBlockComment = false; continue; } else { @@ -218,24 +216,57 @@ else if (c == ' ' || c == '\n' || c == '\t' || c == '\r') { } sb.append(c); } - if (StringUtils.isNotEmpty(sb.toString())) { - statements.add(sb.toString()); + flushStringBuilder(sb, statements); + } + + private static StringBuilder flushStringBuilder(StringBuilder sb, List statements) { + if (sb.length() == 0) { + return sb; } + + final String s = sb.toString().trim(); + if (StringUtils.isNotEmpty(s)) { + statements.add(s); + } + + return new StringBuilder(); } + private static boolean isSeperator(char c, String separator, String commentPrefix, + String blockCommentStartDelimiter) { + return c == ' ' || c == '\r' || c == '\n' || c == '\t' || + c == separator.charAt(0) || c == separator.charAt(separator.length() - 1) || + c == commentPrefix.charAt(0) || c == blockCommentStartDelimiter.charAt(0) || + c == blockCommentStartDelimiter.charAt(blockCommentStartDelimiter.length() - 1); + } + private static boolean containsSubstringAtOffset(String lowercaseString, String substring, int offset) { String lowercaseSubstring = substring.toLowerCase(); return lowercaseString.startsWith(lowercaseSubstring, offset); } + private static boolean containsKeywordsAtOffset(String lowercaseString, String keywords, int offset, + String separator, String commentPrefix, + String blockCommentStartDelimiter) { + String lowercaseKeywords = keywords.toLowerCase(); + + boolean backSeperated = (offset == 0) || isSeperator(lowercaseString.charAt(offset - 1), + separator, commentPrefix, blockCommentStartDelimiter); + boolean frontSeperated = (offset >= (lowercaseString.length() - keywords.length())) || + isSeperator(lowercaseString.charAt(offset + keywords.length()), + separator, commentPrefix, blockCommentStartDelimiter); + + return backSeperated && frontSeperated && lowercaseString.startsWith(lowercaseKeywords, offset); + } + private static void checkArgument(boolean expression, String errorMessage) { if (!expression) { throw new IllegalArgumentException(errorMessage); } } - /** + /** * Does the provided SQL script contain the specified delimiter? * @param script the SQL script * @param delim String delimiting each statement - typically a ';' character @@ -356,7 +387,7 @@ public ScriptLoadException(String message, Throwable cause) { } } - private static class ScriptParseException extends RuntimeException { + public static class ScriptParseException extends RuntimeException { public ScriptParseException(String format, String scriptPath) { super(String.format(format, scriptPath)); } diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java new file mode 100644 index 00000000000..0836592b91e --- /dev/null +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java @@ -0,0 +1,294 @@ +package org.testcontainers.ext; + +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.junit.Assert.fail; +import static org.testcontainers.ext.ScriptUtils.*; + +public class ScriptSplittingTest { + + @Test + public void testStringDemarcation() { + String script = "SELECT 'foo `bar`'; SELECT 'foo -- `bar`'; SELECT 'foo /* `bar`';"; + + List expected = asList( + "SELECT 'foo `bar`'", + "SELECT 'foo -- `bar`'", + "SELECT 'foo /* `bar`'" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testIssue1547Case1() { + String script = "create database if not exists ttt;\n" + + "\n" + + "use ttt;\n" + + "\n" + + "create table aaa\n" + + "(\n" + + " id bigint auto_increment primary key,\n" + + " end_time datetime null COMMENT 'end_time',\n" + + " data_status varchar(16) not null\n" + + ") comment 'aaa';\n" + + "\n" + + "create table bbb\n" + + "(\n" + + " id bigint auto_increment primary key\n" + + ") comment 'bbb';"; + + List expected = asList( + "create database if not exists ttt", + "use ttt", + "create table aaa ( id bigint auto_increment primary key, end_time datetime null COMMENT 'end_time', data_status varchar(16) not null ) comment 'aaa'", + "create table bbb ( id bigint auto_increment primary key ) comment 'bbb'" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testIssue1547Case2() { + String script = "CREATE TABLE bar (\n" + + " end_time VARCHAR(255)\n" + + ");\n" + + "CREATE TABLE bar (\n" + + " end_time VARCHAR(255)\n" + + ");"; + + List expected = asList( + "CREATE TABLE bar ( end_time VARCHAR(255) )", + "CREATE TABLE bar ( end_time VARCHAR(255) )" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testUnusualSemicolonPlacement() { + String script = "SELECT 1;;;;;SELECT 2;\n;SELECT 3\n; SELECT 4;\n SELECT 5"; + + List expected = asList( + "SELECT 1", + "SELECT 2", + "SELECT 3", + "SELECT 4", + "SELECT 5" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testCommentedSemicolon() { + String script = "CREATE TABLE bar (\n" + + " foo VARCHAR(255)\n" + + "); \nDROP PROCEDURE IF EXISTS -- ;\n" + + " count_foo"; + + List expected = asList( + "CREATE TABLE bar ( foo VARCHAR(255) )", + "DROP PROCEDURE IF EXISTS count_foo" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testStringEscaping() { + String script = "SELECT \"a /* string literal containing comment characters like -- here\";\n" + + "SELECT \"a 'quoting' \\\"scenario ` involving BEGIN keyword\\\" here\";\n" + + "SELECT * from `bar`;"; + + List expected = asList( + "SELECT \"a /* string literal containing comment characters like -- here\"", + "SELECT \"a 'quoting' \\\"scenario ` involving BEGIN keyword\\\" here\"", + "SELECT * from `bar`" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testBlockCommentExclusion() { + String script = "INSERT INTO bar (foo) /* ; */ VALUES ('hello world');"; + + List expected = asList( + "INSERT INTO bar (foo) VALUES ('hello world')" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testBeginEndKeywordCorrectDetection() { + String script = "INSERT INTO something_end (begin_with_the_token, another_field) /*end*/ VALUES /* end */ (' begin ', `end`)-- begin\n;"; + + List expected = asList( + "INSERT INTO something_end (begin_with_the_token, another_field) VALUES (' begin ', `end`)" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testCommentInStrings() { + String script = "CREATE TABLE bar (foo VARCHAR(255));\n" + + "\n" + + "/* Insert Values */\n" + + "INSERT INTO bar (foo) values ('--1');\n" + + "INSERT INTO bar (foo) values ('--2');\n" + + "INSERT INTO bar (foo) values ('/* something */');\n" + + "/* INSERT INTO bar (foo) values (' */'); -- '*/;\n" + // purposefully broken, to see if it breaks our splitting + "INSERT INTO bar (foo) values ('foo');"; + + List expected = asList( + "CREATE TABLE bar (foo VARCHAR(255))", + "INSERT INTO bar (foo) values ('--1')", + "INSERT INTO bar (foo) values ('--2')", + "INSERT INTO bar (foo) values ('/* something */')", + "'); -- '*/", + "INSERT INTO bar (foo) values ('foo')" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testMultipleBeginEndDetection() { + String script = "CREATE TABLE bar (foo VARCHAR(255));\n" + + "\n" + + "CREATE TABLE gender (gender VARCHAR(255));\n" + + "CREATE TABLE ending (ending VARCHAR(255));\n" + + "CREATE TABLE end2 (end2 VARCHAR(255));\n" + + "CREATE TABLE end_2 (end2 VARCHAR(255));\n" + + "\n" + + "BEGIN\n" + + " INSERT INTO ending values ('ending');\n" + + "END;\n" + + "\n" + + "BEGIN\n" + + " INSERT INTO ending values ('ending');\n" + + "END/*hello*/;\n" + + "\n" + + "BEGIN--Hello\n" + + " INSERT INTO ending values ('ending');\n" + + "END;\n" + + "\n" + + "/*Hello*/BEGIN\n" + + " INSERT INTO ending values ('ending');\n" + + "END;\n" + + "\n" + + "CREATE TABLE foo (bar VARCHAR(255));"; + + List expected = asList( + "CREATE TABLE bar (foo VARCHAR(255))", + "CREATE TABLE gender (gender VARCHAR(255))", + "CREATE TABLE ending (ending VARCHAR(255))", + "CREATE TABLE end2 (end2 VARCHAR(255))", + "CREATE TABLE end_2 (end2 VARCHAR(255))", + "BEGIN\n" + + " INSERT INTO ending values ('ending');\n" + + "END", + "BEGIN\n" + + " INSERT INTO ending values ('ending');\n" + + "END", + "BEGIN--Hello\n" + + " INSERT INTO ending values ('ending');\n" + + "END", + "BEGIN\n" + + " INSERT INTO ending values ('ending');\n" + + "END", + "CREATE TABLE foo (bar VARCHAR(255))" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testProcedureBlock() { + String script = "CREATE PROCEDURE count_foo()\n" + + " BEGIN\n" + + "\n" + + " BEGIN\n" + + " SELECT *\n" + + " FROM bar;\n" + + " SELECT 1\n" + + " FROM dual;\n" + + " END;\n" + + "\n" + + " BEGIN\n" + + " select * from bar;\n" + + " END;\n" + + "\n" + + " -- we can do comments\n" + + "\n" + + " /* including block\n" + + " comments\n" + + " */\n" + + "\n" + + " /* what if BEGIN appears inside a comment? */\n" + + "\n" + + " select \"or what if BEGIN appears inside a literal?\";\n" + + "\n" + + " END /*; */;"; + + List expected = asList( + "CREATE PROCEDURE count_foo() BEGIN\n" + + "\n" + + " BEGIN\n" + + " SELECT *\n" + + " FROM bar;\n" + + " SELECT 1\n" + + " FROM dual;\n" + + " END;\n" + + "\n" + + " BEGIN\n" + + " select * from bar;\n" + + " END;\n" + + "\n" + + " -- we can do comments\n" + + "\n" + + " /* including block\n" + + " comments\n" + + " */\n" + + "\n" + + " /* what if BEGIN appears inside a comment? */\n" + + "\n" + + " select \"or what if BEGIN appears inside a literal?\";\n" + + "\n" + + " END" + ); + + splitAndCompare(script, expected); + } + + @Test + public void testUnclosedBlockComment() { + String script = "SELECT 'foo `bar`'; /*"; + + try { + doSplit(script); + fail("Should have thrown!"); + } catch (ScriptUtils.ScriptParseException expected) { + // ignore expected exception + } + } + + private void splitAndCompare(String script, List expected) { + final List statements = doSplit(script); + Assertions.assertThat(statements).isEqualTo(expected); + } + + private List doSplit(String script) { + final List statements = new ArrayList<>(); + ScriptUtils.splitSqlScript("ignored", script, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_COMMENT_PREFIX, DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements); + return statements; + } +} diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java deleted file mode 100644 index c9b1218321b..00000000000 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptUtilsTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.testcontainers.ext; - -import com.google.common.base.Charsets; -import com.google.common.io.Resources; -import org.junit.Test; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertEquals; - -public class ScriptUtilsTest { - - /* - * Test ScriptUtils script splitting with some ugly/hard-to-split cases - */ - @Test - public void testSplit() throws IOException { - final String script = Resources.toString(Resources.getResource("splittable.sql"), Charsets.UTF_8); - - final List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript("resourcename", script, ";", "--", "/*", "*/", statements); - - assertEquals(7, statements.size()); - assertEquals("SELECT \"a /* string literal containing comment characters like -- here\"", statements.get(2)); - assertEquals("SELECT \"a 'quoting' \\\"scenario ` involving BEGIN keyword\\\" here\"", statements.get(3)); - assertEquals("SELECT * from `bar`", statements.get(4)); - assertEquals("INSERT INTO bar (foo) VALUES ('hello world')", statements.get(6)); - } - - /* - * Test ScriptUtils script splitting with some ugly/hard-to-split cases and linux line endings - */ - @Test - public void testSplitWithWidnwosLineEnding() throws IOException { - final String script = Resources.toString(Resources.getResource("splittable.sql"), Charsets.UTF_8); - final String scriptWithWindowsLineEndings = script.replaceAll("\n", "\r\n"); - final List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript("resourcename", scriptWithWindowsLineEndings, ";", "--", "/*", "*/", statements); - - assertEquals(7, statements.size()); - assertEquals("SELECT \"a /* string literal containing comment characters like -- here\"", statements.get(2)); - assertEquals("SELECT \"a 'quoting' \\\"scenario ` involving BEGIN keyword\\\" here\"", statements.get(3)); - assertEquals("SELECT * from `bar`", statements.get(4)); - assertEquals("INSERT INTO bar (foo) VALUES ('hello world')", statements.get(6)); - } -} diff --git a/modules/database-commons/src/test/resources/splittable.sql b/modules/database-commons/src/test/resources/splittable.sql deleted file mode 100644 index addede19dd7..00000000000 --- a/modules/database-commons/src/test/resources/splittable.sql +++ /dev/null @@ -1,45 +0,0 @@ -CREATE TABLE bar ( - foo VARCHAR(255) -); - -DROP PROCEDURE IF EXISTS -- ; - count_foo; - -SELECT "a /* string literal containing comment characters like -- here"; -SELECT "a 'quoting' \"scenario ` involving BEGIN keyword\" here"; -SELECT * from `bar`; - --- What about a line comment containing imbalanced string delimiters? " - -CREATE PROCEDURE count_foo() - BEGIN - - BEGIN - SELECT * - FROM bar; - SELECT 1 - FROM dual; - END; - - BEGIN - select * from bar; - END; - - -- we can do comments - - /* including block - comments - */ - - /* what if BEGIN appears inside a comment? */ - - select "or what if BEGIN appears inside a literal?"; - - END /*; */; - -/* or a block comment - containing imbalanced string delimiters? - ' " - */ - -INSERT INTO bar (foo) /* ; */ VALUES ('hello world'); From 195339b127abd8036b3a995ff21c18a0b388fecf Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2019 21:39:36 +0200 Subject: [PATCH 0173/4969] Bump docker-java from 3.1.0-rc-4 to 3.1.5 (#1649) * Bump docker-java from 3.1.0-rc-4 to 3.1.5 in /core Bumps [docker-java](https://github.com/docker-java/docker-java) from 3.1.0-rc-4 to 3.1.5. - [Release notes](https://github.com/docker-java/docker-java/releases) - [Changelog](https://github.com/docker-java/docker-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/docker-java/docker-java/compare/3.1.0-rc-4...3.1.5) Signed-off-by: dependabot-preview[bot] * remove `FiltersEncoder` (backported to docker-java) * run jdbc checks separately on Travis * fix jdbc -> jdbc-test fixes #1548 --- .travis.yml | 5 +++- core/build.gradle | 2 +- .../dockerjava/core/util/FiltersEncoder.java | 27 ------------------ .../core/util/FiltersEncoderTest.java | 28 ------------------- 4 files changed, 5 insertions(+), 57 deletions(-) delete mode 100644 core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java delete mode 100644 core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java diff --git a/.travis.yml b/.travis.yml index 575aa50b208..0c03c4931bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,10 @@ jobs: script: ./gradlew selenium:check --scan --no-daemon - env: [ NAME=modules ] - script: ./gradlew check -x testcontainers:check -x selenium:check --scan --no-daemon + script: ./gradlew check -x testcontainers:check -x selenium:check -x jdbc-test:check --scan --no-daemon + + - env: [ NAME=jdbc ] + script: ./gradlew jdbc-test:check --scan --no-daemon - env: [ NAME=examples ] script: cd examples && ../gradlew check --no-daemon diff --git a/core/build.gradle b/core/build.gradle index f400b5e3c1c..545780c0bc7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -79,7 +79,7 @@ dependencies { exclude(group: "net.java.dev.jna") } - shaded ('com.github.docker-java:docker-java:3.1.0-rc-4') { + shaded ('com.github.docker-java:docker-java:3.1.5') { exclude(group: 'org.glassfish.jersey.core') exclude(group: 'org.glassfish.jersey.connectors') exclude(group: 'org.glassfish.jersey.inject') diff --git a/core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java b/core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java deleted file mode 100644 index 2a6f185462e..00000000000 --- a/core/src/main/java/com/github/dockerjava/core/util/FiltersEncoder.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.dockerjava.core.util; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.util.List; -import java.util.Map; - -/** - * Monkey patched {@link FiltersEncoder} to avoid a use of jaxrs. - * See https://github.com/docker-java/docker-java/issues/1176 - */ -public class FiltersEncoder { - - private FiltersEncoder() { - } - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - public static String jsonEncode(Map> filters) { - try { - return OBJECT_MAPPER.writeValueAsString(filters); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } -} diff --git a/core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java b/core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java deleted file mode 100644 index 353133ae148..00000000000 --- a/core/src/test/java/com/github/dockerjava/core/util/FiltersEncoderTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.github.dockerjava.core.util; - -import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.model.Image; -import org.junit.Test; -import org.rnorth.visibleassertions.VisibleAssertions; -import org.testcontainers.DockerClientFactory; - -import java.util.List; -import java.util.UUID; - -/** - * This test checks that our custom monkey-patched version works - * and does not throw {@link ClassNotFoundException}. - */ -public class FiltersEncoderTest { - - @Test - public void filtersShouldWork() throws Exception { - DockerClient client = DockerClientFactory.instance().client(); - - List images = client.listImagesCmd() - .withLabelFilter("com.example=" + UUID.randomUUID().toString()) - .exec(); - - VisibleAssertions.assertTrue("List is empty", images.isEmpty()); - } -} From 365856d2b23f6ca2529ec557329719e3276c3166 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2019 22:25:15 +0000 Subject: [PATCH 0174/4969] Bump neo4j from 3.5.7 to 3.5.8 in /modules/neo4j (#1640) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 9c5410aa179..1ea0ab3fb23 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -25,7 +25,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.7" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.8" compile project(":testcontainers") From 1d0f022aa367c91ab0ce6217964805445bd814cd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2019 00:57:58 +0000 Subject: [PATCH 0175/4969] Bump junit-jupiter-engine from 5.5.0 to 5.5.1 in /modules/junit-jupiter (#1642) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 08bdedc6620..53eec4bece1 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.6' testRuntime 'mysql:mysql-connector-java:8.0.16' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.0' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.1' } test { From 505731a854e3c2df583416e3acc7012ea08ab1bc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2019 03:35:08 +0000 Subject: [PATCH 0176/4969] Bump junit-jupiter-api from 5.5.0 to 5.5.1 in /modules/junit-jupiter (#1638) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 53eec4bece1..198d67764c7 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.5.0' + compile 'org.junit.jupiter:junit-jupiter-api:5.5.1' testCompile project(':mysql') testCompile project(':postgresql') From 65f4ee7ea65ca5039943675131075a6c95facd8e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2019 05:08:34 +0000 Subject: [PATCH 0177/4969] Bump aws-java-sdk-sqs from 1.11.594 to 1.11.597 in /modules/localstack (#1654) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3bcfcb91714..fd51e51a9c8 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.594' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.597' } From eb7d96b6c78afb463c746dddfe7775cbc16842e5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2019 06:37:37 +0000 Subject: [PATCH 0178/4969] Bump mysql-connector-java from 8.0.16 to 8.0.17 in /modules/mysql (#1633) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 2540df73c3f..3647fe11cc6 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { compile project(':jdbc') - testCompile 'mysql:mysql-connector-java:8.0.16' + testCompile 'mysql:mysql-connector-java:8.0.17' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.22' testCompile 'commons-dbutils:commons-dbutils:1.7' From 1010b8955f36a31c2c5d05e7a650d5ba1cbf9ba8 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 24 Jul 2019 10:19:38 +0200 Subject: [PATCH 0179/4969] Add "housekeeping" category to the release drafter config (#1652) --- .github/release-drafter.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 1bfa59ca589..ed8939a3117 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -11,5 +11,9 @@ categories: label: type/bug - title: 📖 Documentation label: type/docs + - title: 🧹 Housekeeping + labels: + - type/housekeeping + - type/test-improvement - title: 📦 Dependency updates label: dependencies From 46041742b048cd93da5e94e13807053e70466a67 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 24 Jul 2019 10:20:13 +0100 Subject: [PATCH 0180/4969] Add link to DB2 module docs, and add incubating note to page (#1660) --- docs/contributing.md | 4 ++-- docs/modules/databases/db2.md | 3 +++ mkdocs.yml | 13 +++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 9d2c63b030c..70cd452b143 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -86,7 +86,7 @@ We currently believe 3 months is a fair period of time, but may change this. New modules should have the following warning at the top of their documentation pages: -!!! warning - This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. We will evaluate incubating modules periodically, and remove the label when appropriate. diff --git a/docs/modules/databases/db2.md b/docs/modules/databases/db2.md index b7871e636d0..bc25b343072 100644 --- a/docs/modules/databases/db2.md +++ b/docs/modules/databases/db2.md @@ -1,5 +1,8 @@ # DB2 Module +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. ## Usage example diff --git a/mkdocs.yml b/mkdocs.yml index 6b38d82eff4..de9819f102f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -39,17 +39,18 @@ nav: - Modules: - Databases: - modules/databases/index.md - - modules/databases/mysql.md - - modules/databases/mariadb.md - - modules/databases/postgres.md - - modules/databases/oraclexe.md - - modules/databases/mssqlserver.md - modules/databases/cassandra.md - modules/databases/couchbase.md - modules/databases/clickhouse.md - - modules/databases/influxdb.md + - modules/databases/db2.md - modules/databases/dynalite.md + - modules/databases/influxdb.md + - modules/databases/mariadb.md + - modules/databases/mssqlserver.md + - modules/databases/mysql.md - modules/databases/neo4j.md + - modules/databases/oraclexe.md + - modules/databases/postgres.md - modules/webdriver_containers.md - modules/docker_compose.md - modules/elasticsearch.md From e95bdd5a3e503b2120ecc4a01ea4501ca72c3fc7 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 24 Jul 2019 17:51:10 +0100 Subject: [PATCH 0181/4969] Add a basic documentation page for RabbitMQ module (#1661) --- docs/modules/rabbitmq.md | 21 +++++++++++++++++++++ mkdocs.yml | 7 ++++--- 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 docs/modules/rabbitmq.md diff --git a/docs/modules/rabbitmq.md b/docs/modules/rabbitmq.md new file mode 100644 index 00000000000..92275ad765b --- /dev/null +++ b/docs/modules/rabbitmq.md @@ -0,0 +1,21 @@ +# RabbitMQ Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:rabbitmq:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + rabbitmq + {{latest_version}} + test + +``` diff --git a/mkdocs.yml b/mkdocs.yml index de9819f102f..044489d1e50 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,16 +51,17 @@ nav: - modules/databases/neo4j.md - modules/databases/oraclexe.md - modules/databases/postgres.md - - modules/webdriver_containers.md - modules/docker_compose.md - modules/elasticsearch.md - modules/kafka.md - - modules/pulsar.md - modules/localstack.md - modules/mockserver.md - - modules/toxiproxy.md - modules/nginx.md + - modules/pulsar.md + - modules/rabbitmq.md + - modules/toxiproxy.md - modules/vault.md + - modules/webdriver_containers.md - Test framework integration: - test_framework_integration/junit_4.md - test_framework_integration/junit_5.md From bf84ace9e4841bba56555e26c7d4b041080ff994 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2019 05:59:58 +0000 Subject: [PATCH 0182/4969] Bump aws-java-sdk-sqs from 1.11.597 to 1.11.598 in /modules/localstack (#1664) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index fd51e51a9c8..46b9b059a6a 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.597' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.598' } From cde3d464a63845868d43ea20c9e5448432437524 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2019 05:59:26 +0000 Subject: [PATCH 0183/4969] Bump aws-java-sdk-sqs from 1.11.598 to 1.11.599 in /modules/localstack (#1667) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 46b9b059a6a..5481ea1696c 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.598' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.599' } From f9453ddee1a5b15c43f3290e9136eee4a1a251fc Mon Sep 17 00:00:00 2001 From: Michael Irwin Date: Fri, 26 Jul 2019 05:43:17 -0400 Subject: [PATCH 0184/4969] Add networking documentation (#1651) * Add networking documentation Resolves #1159 * Use code snippet from NetworkTest in networking documentation Issue #1159 * Removed example no longer being used Issue #1159 --- .../org/testcontainers/containers/NetworkTest.java | 5 ++++- docs/features/networking.md | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/src/test/java/org/testcontainers/containers/NetworkTest.java b/core/src/test/java/org/testcontainers/containers/NetworkTest.java index 04edf42c6d1..b717b8dc81a 100644 --- a/core/src/test/java/org/testcontainers/containers/NetworkTest.java +++ b/core/src/test/java/org/testcontainers/containers/NetworkTest.java @@ -5,6 +5,7 @@ import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.Network; import static org.rnorth.visibleassertions.VisibleAssertions.*; import static org.testcontainers.containers.Network.newNetwork; @@ -39,8 +40,9 @@ public static class WithoutRules { @Test public void testNetworkSupport() throws Exception { + // useCustomNetwork { try ( - Network network = newNetwork(); + Network network = Network.newNetwork(); GenericContainer foo = new GenericContainer() .withNetwork(network) @@ -57,6 +59,7 @@ public void testNetworkSupport() throws Exception { String response = bar.execInContainer("wget", "-O", "-", "http://foo:8080").getStdout(); assertEquals("received response", "yay", response); } + // } } @Test diff --git a/docs/features/networking.md b/docs/features/networking.md index d0007df878b..75dd924d6bc 100644 --- a/docs/features/networking.md +++ b/docs/features/networking.md @@ -75,3 +75,15 @@ For example, here we construct an HTTP URL for our local web application and tel [Accessing the exposed host port from a container](../examples/src/test/java/generic/HostPortExposedTest.java) inside_block:useHostExposedPort + + +## Advanced networking + +Docker provides the ability for you to create custom networks and place containers on one or more networks. Then, communication can occur between networked containers without the need of exposing ports through the host. With Testcontainers, you can do this as well. + +!!! warning + Note that Testcontainers currently only allows a container to be on a single network. + + +[Creating custom networks](../../core/src/test/java/org/testcontainers/containers/NetworkTest.java) inside_block:useCustomNetwork + \ No newline at end of file From c094a034f733215bfd88d41538089699caab1616 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2019 07:02:56 +0000 Subject: [PATCH 0185/4969] Bump cucumber-java from 4.6.0 to 4.7.1 in /examples (#1677) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 9907da86262..08626f9e257 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.6.0' + implementation 'io.cucumber:cucumber-java:4.7.1' testImplementation 'io.cucumber:cucumber-junit:4.6.0' testImplementation 'org.testcontainers:selenium' } From b12f6526fef4b05bbcc3ff8e267b9ceda437b820 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2019 09:30:40 +0000 Subject: [PATCH 0186/4969] Bump mysql-connector-java from 8.0.16 to 8.0.17 in /modules/spock (#1634) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 74c6b6fd5db..f9353314c1b 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -14,5 +14,5 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testRuntime 'org.postgresql:postgresql:42.2.6' - testRuntime 'mysql:mysql-connector-java:8.0.16' + testRuntime 'mysql:mysql-connector-java:8.0.17' } From 2d11d80034c47f6d6538e036e77f50c0ede98018 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2019 10:56:46 +0000 Subject: [PATCH 0187/4969] Bump mysql-connector-java in /modules/junit-jupiter (#1658) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 198d67764c7..9c668a208a1 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -14,7 +14,7 @@ dependencies { } testRuntime 'org.postgresql:postgresql:42.2.6' - testRuntime 'mysql:mysql-connector-java:8.0.16' + testRuntime 'mysql:mysql-connector-java:8.0.17' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.1' } From 5cbf6d556166b56ef9c59c859f748444023b236a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 06:05:06 +0000 Subject: [PATCH 0188/4969] Bump assertj-core from 3.12.2 to 3.13.1 in /modules/kafka (#1683) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 10013a6e11e..f9b94304b98 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.3.0' - testCompile 'org.assertj:assertj-core:3.12.2' + testCompile 'org.assertj:assertj-core:3.13.1' testCompile 'com.google.guava:guava:23.0' } From 56499c7291ca7dcdc3d7f4e64bfd77463f570747 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 07:57:40 +0000 Subject: [PATCH 0189/4969] Bump aws-java-sdk-sqs from 1.11.599 to 1.11.601 in /modules/localstack (#1682) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 5481ea1696c..ecb7ecd4345 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.599' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.601' } From aeb1ebf4e37dc519890279c53739695801cad8e5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 10:37:48 +0000 Subject: [PATCH 0190/4969] Bump assertj-core from 3.12.2 to 3.13.1 in /modules/neo4j (#1681) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 1ea0ab3fb23..5eaae90325f 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -30,5 +30,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.12.2' + testCompile 'org.assertj:assertj-core:3.13.1' } From fa324f5072485e899f9eff7cf2d241aea8465976 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 11:47:25 +0000 Subject: [PATCH 0191/4969] Bump cucumber-junit from 4.6.0 to 4.7.1 in /examples (#1676) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 08626f9e257..069e0a8881a 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.7.1' - testImplementation 'io.cucumber:cucumber-junit:4.6.0' + testImplementation 'io.cucumber:cucumber-junit:4.7.1' testImplementation 'org.testcontainers:selenium' } From 0605014353a680f1efed7f6d663feab2cf65ad6d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 12:36:33 +0000 Subject: [PATCH 0192/4969] Bump assertj-core from 3.12.2 to 3.13.1 in /modules/pulsar (#1684) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 301d6f81da2..b493976c9d6 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,5 +4,5 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.2' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.2' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.13.1' } From ba96952e1a53cdfbf58e9781463adbbccf951f30 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 13:22:19 +0000 Subject: [PATCH 0193/4969] Bump jedis from 3.0.1 to 3.1.0 in /modules/junit-jupiter (#1657) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 9c668a208a1..5710b48fd15 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' - testCompile 'redis.clients:jedis:3.0.1' + testCompile 'redis.clients:jedis:3.1.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile ('org.mockito:mockito-core:2.28.2') { exclude(module: 'hamcrest-core') From ec00eaf93ac63cd574ab69331d1621470624f8b8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 15:20:04 +0000 Subject: [PATCH 0194/4969] Bump assertj-core from 3.12.2 to 3.13.1 in /modules/database-commons (#1685) --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 27d1aeeb5e6..a7ccab63fa9 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.12.2' + testCompile 'org.assertj:assertj-core:3.13.1' } From f7e0eedd64843ada2afe61c67117b3557c190fd9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2019 16:55:09 +0000 Subject: [PATCH 0195/4969] Bump jedis from 3.0.1 to 3.1.0 in /examples (#1686) --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 5075c10e7df..6446bc43497 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.26' - implementation 'redis.clients:jedis:3.0.1' + implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 692841ae7d7..f9239984a9a 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.26' - implementation 'redis.clients:jedis:3.0.1' + implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 0a1789c944a..3c73816f578 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.0.1' + implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.26' From cf7a0499dec246c854387694da8c74e3e81e1855 Mon Sep 17 00:00:00 2001 From: William Delanoue Date: Fri, 2 Aug 2019 21:22:50 +0200 Subject: [PATCH 0196/4969] Update copyright dates (#1691) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8f18b9edd6d..317bc0c749d 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ See [LICENSE](LICENSE). ## Copyright -Copyright (c) 2015 - 2018 Richard North and other authors. +Copyright (c) 2015 - 2019 Richard North and other authors. -MS SQL Server module is (c) 2017 - 2018 G DATA Software AG and other authors. +MS SQL Server module is (c) 2017 - 2019 G DATA Software AG and other authors. -Hashicorp Vault module is (c) 2017 Capital One Services, LLC and other authors. +Hashicorp Vault module is (c) 2017 - 2019 Capital One Services, LLC and other authors. See [contributors](https://github.com/testcontainers/testcontainers-java/graphs/contributors) for all contributors. From 9ce2d4a94397fe4ec1940073dd5721deca644713 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2019 06:03:01 +0000 Subject: [PATCH 0197/4969] Bump aws-java-sdk-sqs from 1.11.601 to 1.11.604 in /modules/localstack (#1709) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ecb7ecd4345..8d91198c27b 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.601' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.604' } From 42fd8c7edcf80a8ce7284b5876994967739aa996 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2019 08:42:23 +0000 Subject: [PATCH 0198/4969] Bump assertj-core from 3.13.1 to 3.13.2 in /modules/pulsar (#1703) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index b493976c9d6..d0d89d3666c 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,5 +4,5 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.2' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.13.1' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.13.2' } From 8042f9c40b89b66bce2b50f50386d6cf60d015d8 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 6 Aug 2019 11:22:46 +0100 Subject: [PATCH 0199/4969] Add Maven Central as a fallback for dependency download (#1710) To reduce flaky CI builds when JCenter is experiencing a blip --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 235c1ae22f1..988844f4c90 100644 --- a/build.gradle +++ b/build.gradle @@ -51,6 +51,7 @@ subprojects { repositories { jcenter() + mavenCentral() } shadowJar { From bdb82b76a86b57a9789731430cddf3858f41388a Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 6 Aug 2019 12:38:37 +0100 Subject: [PATCH 0200/4969] JUnit rule for flaky test retry (#1680) --- build.gradle | 40 ++-- core/build.gradle | 2 +- .../junit/GenericContainerRuleTest.java | 27 +-- modules/couchbase/build.gradle | 2 + .../couchbase/BaseCouchbaseContainerTest.java | 9 + modules/jdbc-test/build.gradle | 1 + .../jdbc/DatabaseDriverTmpfsTest.java | 14 +- settings.gradle | 2 + test-support/build.gradle | 4 + .../org/testcontainers/testsupport/Flaky.java | 34 ++++ .../testsupport/FlakyTestJUnit4RetryRule.java | 99 +++++++++ .../testsupport/FlakyRuleTest.java | 190 ++++++++++++++++++ .../src/test/resources/logback-test.xml | 16 ++ 13 files changed, 394 insertions(+), 46 deletions(-) create mode 100644 test-support/build.gradle create mode 100644 test-support/src/main/java/org/testcontainers/testsupport/Flaky.java create mode 100644 test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java create mode 100644 test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java create mode 100644 test-support/src/test/resources/logback-test.xml diff --git a/build.gradle b/build.gradle index 988844f4c90..b3e96b265b5 100644 --- a/build.gradle +++ b/build.gradle @@ -12,8 +12,6 @@ subprojects { apply plugin: 'idea' apply plugin: 'io.franzbecker.gradle-lombok' apply plugin: 'com.github.johnrengelman.shadow' - apply from: "$rootDir/gradle/publishing.gradle" - apply from: "$rootDir/gradle/bintray.gradle" group = "org.testcontainers" @@ -35,9 +33,29 @@ subprojects { } } - project.tasks.sourceJar.from(delombok) + repositories { + jcenter() + mavenCentral() + } + + // specific modules should be excluded from publication + if ( ! ["test-support", "jdbc-test", "docs-examples"].contains(it.name) ) { + apply from: "$rootDir/gradle/publishing.gradle" + apply from: "$rootDir/gradle/bintray.gradle" + + project.tasks.sourceJar.from(delombok) + + publishing { + publications { + mavenJava(MavenPublication) { publication -> + artifacts.removeAll { it.classifier == null } + artifact project.tasks.shadowJar + } + } + } - task release(dependsOn: bintrayUpload) + task release(dependsOn: bintrayUpload) + } test { defaultCharacterEncoding = "UTF-8" @@ -49,11 +67,6 @@ subprojects { } } - repositories { - jcenter() - mavenCentral() - } - shadowJar { configurations = [] classifier = null @@ -87,15 +100,6 @@ subprojects { } } - publishing { - publications { - mavenJava(MavenPublication) { publication -> - artifacts.removeAll { it.classifier == null } - artifact project.tasks.shadowJar - } - } - } - dependencies { testCompile 'ch.qos.logback:logback-classic:1.2.3' } diff --git a/core/build.gradle b/core/build.gradle index 545780c0bc7..42c2dcc5794 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -113,7 +113,7 @@ dependencies { testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') testCompile 'org.assertj:assertj-core:3.12.2' - + testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index 6bbd71961a6..6c51713b6b1 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -14,6 +14,7 @@ import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.utility.Base58; import org.testcontainers.utility.TestEnvironment; @@ -128,29 +129,6 @@ public static void setupContent() throws FileNotFoundException { .withExtraHost("somehost", "192.168.1.10") .withCommand("/bin/sh", "-c", "while true; do cat /etc/hosts | nc -l -p 80; done"); -// @Test -// public void simpleRedisTest() { -// String ipAddress = redis.getContainerIpAddress(); -// Integer port = redis.getMappedPort(REDIS_PORT); -// -// // Use Redisson to obtain a List that is backed by Redis -// Config redisConfig = new Config(); -// redisConfig.useSingleServer().setAddress(ipAddress + ":" + port); -// -// Redisson redisson = Redisson.create(redisConfig); -// -// List testList = redisson.getList("test"); -// testList.add("foo"); -// testList.add("bar"); -// testList.add("baz"); -// -// List testList2 = redisson.getList("test"); -// assertEquals("The list contains the expected number of items (redis is working!)", 3, testList2.size()); -// assertTrue("The list contains an item that was put in (redis is working!)", testList2.contains("foo")); -// assertTrue("The list contains an item that was put in (redis is working!)", testList2.contains("bar")); -// assertTrue("The list contains an item that was put in (redis is working!)", testList2.contains("baz")); -// } - @Test public void testIsRunning() { try (GenericContainer container = new GenericContainer().withCommand("top")) { @@ -404,7 +382,8 @@ public void addExposedPortAfterWithExposedPortsTest() { @Test public void sharedMemorySetTest() { try (GenericContainer containerWithSharedMemory = new GenericContainer() - .withSharedMemorySize(42L * FileUtils.ONE_MB)) { + .withSharedMemorySize(42L * FileUtils.ONE_MB) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy())) { containerWithSharedMemory.start(); diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 6635462818f..753e93adb75 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,4 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') compile 'com.couchbase.client:java-client:2.7.7' + + testCompile project(':test-support') } diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java index 845d9bfaf5e..1c5e702727a 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java @@ -9,7 +9,10 @@ import com.couchbase.client.java.view.View; import com.google.common.collect.Lists; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; +import org.testcontainers.testsupport.Flaky; +import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; import java.util.List; @@ -25,7 +28,11 @@ public abstract class BaseCouchbaseContainerTest extends AbstractCouchbaseTest { private static final String DOCUMENT = "{\"name\":\"toto\"}"; + @Rule + public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); + @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-10-01") public void shouldInsertDocument() { RawJsonDocument expected = RawJsonDocument.create(ID, DOCUMENT); getBucket().upsert(expected); @@ -34,6 +41,7 @@ public void shouldInsertDocument() { } @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-10-01") public void shouldExecuteN1ql() { getBucket().query(N1qlQuery.simple("INSERT INTO " + TEST_BUCKET + " (KEY, VALUE) VALUES ('" + ID + "', " + DOCUMENT + ")")); @@ -46,6 +54,7 @@ public void shouldExecuteN1ql() { } @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-10-01") public void shouldCreateView() { View view = DefaultView.create(VIEW_NAME, VIEW_FUNCTION); DesignDocument document = DesignDocument.create(VIEW_NAME, Lists.newArrayList(view)); diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 5874787e9eb..9300ba49a4d 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -28,4 +28,5 @@ dependencies { testCompile 'commons-dbutils:commons-dbutils:1.6' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' + testCompile project(':test-support') } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java index 07b70020733..38c97686679 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -1,18 +1,26 @@ package org.testcontainers.jdbc; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.containers.Container; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.testsupport.Flaky; +import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; + import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import org.junit.Test; -import org.testcontainers.containers.Container; -import org.testcontainers.containers.JdbcDatabaseContainer; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class DatabaseDriverTmpfsTest { + @Rule + public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); + @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1687", reviewDate = "2019-10-01") public void tmpfs() throws IOException, InterruptedException, SQLException { final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw"; try (Connection ignored = DriverManager.getConnection(jdbcUrl)) { diff --git a/settings.gradle b/settings.gradle index 272daa5699d..72e7d312555 100644 --- a/settings.gradle +++ b/settings.gradle @@ -41,3 +41,5 @@ file('modules').eachDir { dir -> include "docs-examples" project(":docs-examples").projectDir = file("docs/examples") +include 'test-support' + diff --git a/test-support/build.gradle b/test-support/build.gradle new file mode 100644 index 00000000000..7cc1bb6d1d4 --- /dev/null +++ b/test-support/build.gradle @@ -0,0 +1,4 @@ +dependencies { + implementation 'junit:junit:4.12' + implementation 'org.slf4j:slf4j-api:1.7.26' +} diff --git a/test-support/src/main/java/org/testcontainers/testsupport/Flaky.java b/test-support/src/main/java/org/testcontainers/testsupport/Flaky.java new file mode 100644 index 00000000000..cc5f6f947fa --- /dev/null +++ b/test-support/src/main/java/org/testcontainers/testsupport/Flaky.java @@ -0,0 +1,34 @@ +package org.testcontainers.testsupport; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation for test methods that should be retried in the event of failure. See {@link FlakyTestJUnit4RetryRule} for + * more details. + */ +@Retention(RUNTIME) +@Target({METHOD}) +public @interface Flaky { + + /** + * @return a URL for a GitHub issue where this flaky test can be discussed, and where actions to resolve it can be + * coordinated. + */ + String githubIssueUrl(); + + /** + * @return a date at which this should be reviewed, in {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE} + * format (e.g. {@code 2020-12-03}). Now + 3 months is suggested. Once this date has passed, retries will no longer + * be applied. + */ + String reviewDate(); + + /** + * @return the total number of times to try running this test (default 3) + */ + int maxTries() default 3; +} diff --git a/test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java b/test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java new file mode 100644 index 00000000000..aa1a3ed3c5f --- /dev/null +++ b/test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java @@ -0,0 +1,99 @@ +package org.testcontainers.testsupport; + +import lombok.extern.slf4j.Slf4j; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.MultipleFailureException; +import org.junit.runners.model.Statement; + +import java.time.LocalDate; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * JUnit 4 @Rule that implements retry for flaky tests (tests that suffer from sporadic random failures). + *

+ *

+ * This rule should be used in conjunction with the @{@link Flaky} annotation. When this Rule is applied to a test + * class, any test method with this annotation will be invoked up to 3 times or until it succeeds. + *

+ *

+ * Tests should not be marked @{@link Flaky} for a long period of time. Every usage should be + * accompanied by a GitHub issue URL, and should be subject to review at a suitable point in the (near) future. + * Should the review date pass without the test's instability being fixed, the retry behaviour will cease to have an + * effect and the test will be allowed to sporadically fail again. + *

+ */ +@Slf4j +public class FlakyTestJUnit4RetryRule implements TestRule { + + @Override + public Statement apply(Statement base, Description description) { + + final Flaky annotation = description.getAnnotation(Flaky.class); + + if (annotation == null) { + // leave the statement as-is + return base; + } + + if (annotation.githubIssueUrl().trim().length() == 0) { + throw new IllegalArgumentException("A GitHub issue URL must be set for usages of the @Flaky annotation"); + } + + final int maxTries = annotation.maxTries(); + + if (maxTries < 1) { + throw new IllegalArgumentException("@Flaky annotation maxTries must be at least one"); + } + + final LocalDate reviewDate; + try { + reviewDate = LocalDate.parse(annotation.reviewDate()); + } catch (DateTimeParseException e) { + throw new IllegalArgumentException("@Flaky reviewDate could not be parsed. Please provide a date in yyyy-mm-dd format"); + } + + // the annotation should only have an effect before the review date, to encourage review and resolution + if ( LocalDate.now().isBefore(reviewDate) ) { + return new RetryingStatement(base, description, maxTries); + } else { + return base; + } + } + + private static class RetryingStatement extends Statement { + private final Statement base; + private final Description description; + private final int maxTries; + + RetryingStatement(Statement base, Description description, int maxTries) { + this.base = base; + this.description = description; + this.maxTries = maxTries; + } + + @Override + public void evaluate() { + + int attempts = 0; + final List causes = new ArrayList<>(); + + while (++attempts <= maxTries) { + try { + base.evaluate(); + return; + } catch (Throwable throwable) { + log.warn("Retrying @Flaky-annotated test: {}", description.getDisplayName()); + causes.add(throwable); + } + } + + throw new IllegalStateException( + "@Flaky-annotated test failed despite retries.", + new MultipleFailureException(causes)); + } + } +} diff --git a/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java b/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java new file mode 100644 index 00000000000..07b0ffe1fa8 --- /dev/null +++ b/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java @@ -0,0 +1,190 @@ +package org.testcontainers.testsupport; + +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.lang.annotation.Annotation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class FlakyRuleTest { + + private static final String VALID_URL = "http://some.url/here"; + private static final String INVALID_URL = ""; + + private static final String VALID_DATE_IN_FAR_FUTURE = "2063-04-05"; + private static final String VALID_DATE_IN_PAST = "1991-08-16"; + private static final String INVALID_DATE = "91-01-45"; + private static final int DEFAULT_TRIES = 3; + + private FlakyTestJUnit4RetryRule rule = new FlakyTestJUnit4RetryRule(); + + @Test + public void testIgnoresMethodWithoutAnnotation() throws Throwable { + final Description description = newDescriptionWithoutAnnotation(); + final DummyStatement statement = newStatement(3); + try { + rule.apply(statement, description).evaluate(); + fail("Should not reach here"); + } catch (Exception ignored) { + + } + assertEquals("The statement should only be invoked once, even if it throws", 1, statement.invocationCount); + } + + @Test + public void testRetriesMethodWithAnnotationUntilFailure() throws Throwable { + final Description description = newDescriptionWithAnnotation(); + + final DummyStatement statement = newStatement(3); + try { + rule.apply(statement, description).evaluate(); + fail("Should not reach here"); + } catch (Exception ignored) { + + } + assertEquals("The statement should be invoked three times", 3, statement.invocationCount); + } + + @Test + public void testCustomRetryCount() throws Throwable { + final Description description = newDescriptionWithAnnotationAndCustomTries(10); + + final DummyStatement statement = newStatement(10); + try { + rule.apply(statement, description).evaluate(); + fail("Should not reach here"); + } catch (Exception ignored) { + + } + assertEquals("The statement should be invoked ten times", 10, statement.invocationCount); + } + + @Test + public void testRetriesMethodWithAnnotationUntilSuccess() throws Throwable { + final Description description = newDescriptionWithAnnotation(); + + final DummyStatement statement = newStatement(2); + + rule.apply(statement, description).evaluate(); + + assertEquals("The statement should be invoked three times, and succeed the third time", 3, statement.invocationCount); + } + + @Test + public void testDoesNotRetryMethodWithAnnotationIfNotThrowing() throws Throwable { + final Description description = newDescriptionWithAnnotation(); + + final DummyStatement statement = newStatement(0); + + rule.apply(statement, description).evaluate(); + + assertEquals("The statement should be invoked once", 1, statement.invocationCount); + } + + @Test + public void testTreatsExpiredAnnotationAsNoAnnotation() throws Throwable { + final Description description = newDescriptionWithExpiredAnnotation(); + final DummyStatement statement = newStatement(3); + try { + rule.apply(statement, description).evaluate(); + fail("Should not reach here"); + } catch (Exception ignored) { + + } + assertEquals("The statement should only be invoked once, even if it throws", 1, statement.invocationCount); + } + + @Test + public void testThrowsOnInvalidDateFormat() throws Throwable { + final Description description = newDescriptionWithAnnotation(INVALID_DATE, VALID_URL); + final DummyStatement statement = newStatement(3); + try { + rule.apply(statement, description).evaluate(); + fail("Should not reach here"); + } catch (IllegalArgumentException ignored) { + + } + assertEquals("The statement should not be invoked if the annotation is invalid", 0, statement.invocationCount); + } + + @Test + public void testThrowsOnInvalidGitHubUrl() throws Throwable { + final Description description = newDescriptionWithAnnotation(VALID_DATE_IN_FAR_FUTURE, INVALID_URL); + final DummyStatement statement = newStatement(3); + try { + rule.apply(statement, description).evaluate(); + fail("Should not reach here"); + } catch (IllegalArgumentException ignored) { + + } + assertEquals("The statement should not be invoked if the annotation is invalid", 0, statement.invocationCount); + } + + private Description newDescriptionWithAnnotation(String reviewDate, String gitHubUrl) { + return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(reviewDate, gitHubUrl, DEFAULT_TRIES)); + } + + private Description newDescriptionWithoutAnnotation() { + return Description.createTestDescription("SomeTestClass", "someMethod"); + } + + private Description newDescriptionWithAnnotation() { + return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(VALID_DATE_IN_FAR_FUTURE, VALID_URL, DEFAULT_TRIES)); + } + + private Description newDescriptionWithAnnotationAndCustomTries(int maxTries) { + return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(VALID_DATE_IN_FAR_FUTURE, VALID_URL, maxTries)); + } + + private Description newDescriptionWithExpiredAnnotation() { + return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(VALID_DATE_IN_PAST, VALID_URL, DEFAULT_TRIES)); + } + + private Flaky newAnnotation(final String reviewDate, String gitHubUrl, int tries) { + return new Flaky() { + @Override + public Class annotationType() { + return Flaky.class; + } + + @Override + public String githubIssueUrl() { + return gitHubUrl; + } + + @Override + public String reviewDate() { + return reviewDate; + } + + @Override + public int maxTries() { + return tries; + } + }; + } + + private DummyStatement newStatement(int timesToThrow) { + final DummyStatement statement = new DummyStatement(); + statement.shouldThrowTimes = timesToThrow; + return statement; + } + + private static class DummyStatement extends Statement { + int shouldThrowTimes = -1; + int invocationCount = 0; + + @Override + public void evaluate() { + invocationCount++; + + if (shouldThrowTimes > 0) { + shouldThrowTimes--; + throw new RuntimeException(); + } + } + } +} diff --git a/test-support/src/test/resources/logback-test.xml b/test-support/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/test-support/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From fbf50922adf98716835b6bb5c8ad9804788c2394 Mon Sep 17 00:00:00 2001 From: Michael Irwin Date: Tue, 6 Aug 2019 11:08:13 -0400 Subject: [PATCH 0201/4969] Add docker-compose.yml to simplify local doc development (#1653) Co-Authored-By: Richard North --- docker-compose.yml | 11 +++++++++++ docs/contributing_docs.md | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000000..822956457f7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3.7" + +services: + docs: + image: python:3.6 + command: sh -c "pip install -r requirements.txt && mkdocs serve -a 0.0.0.0:8000" + working_dir: /docs + volumes: + - ./:/docs + ports: + - 8000:8000 diff --git a/docs/contributing_docs.md b/docs/contributing_docs.md index 294ae54e0de..9ed4b08169c 100644 --- a/docs/contributing_docs.md +++ b/docs/contributing_docs.md @@ -9,7 +9,11 @@ We publish our documentation using Netlify. ## Previewing rendered content -### Previewing docs locally +### Using Docker locally + +The root of the project contains a `docker-compose.yml` file. Simply run `docker-compose up` and then access the docs at [http://localhost:8000](http://localhost:8000). + +### Using Python locally * Ensure that you have Python 3.6.0 or higher. * Set up a virtualenv and run `pip install -r requirements.txt` in the `testcontainers-java` root directory. From 28b2032afa97c9e8e2787d3d771a4342574c97a0 Mon Sep 17 00:00:00 2001 From: Graeme Rocher Date: Wed, 7 Aug 2019 22:02:20 +0200 Subject: [PATCH 0202/4969] Add Micronaut Data to who is using (#1717) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 89e70611f37..657c2446a55 100644 --- a/docs/index.md +++ b/docs/index.md @@ -73,6 +73,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Lightbend](https://www.lightbend.com/) - Testing [Alpakka Kafka](https://doc.akka.io/docs/alpakka-kafka/current/) and support in [Alpakka Kafka Testkit](https://doc.akka.io/docs/alpakka-kafka/current/testing.html#testing-with-kafka-in-docker) * [Zalando SE](https://corporate.zalando.com/en) - Testing core business services * [Europace AG](https://tech.europace.de/) - Integration testing for databases and micro services +* [Micronaut Data](https://github.com/micronaut-projects/micronaut-data/) - Testing of Micronaut Data JDBC, a database access toolkit ## License From 4d1ba9e7095483c0636138aff7831935a8b8e5d9 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 10 Aug 2019 20:33:33 +0100 Subject: [PATCH 0203/4969] =?UTF-8?q?Amend=20container=20shutdown=20to=20c?= =?UTF-8?q?atch=20and=20log=20for=20all=20Exception=20cla=E2=80=A6=20(#166?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Amend container shutdown to catch and log for all Exception classes Replacement for #1420 to fix incomplete error handling Refs #1379 * Log root cause exception message rather than immediate exception's message --- .../utility/ResourceReaper.java | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 086cac83206..53f7693149b 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -2,9 +2,6 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse; -import com.github.dockerjava.api.exception.ConflictException; -import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.ExposedPort; @@ -13,6 +10,7 @@ import com.github.dockerjava.api.model.Ports; import com.github.dockerjava.api.model.Volume; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Throwables; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; @@ -218,12 +216,14 @@ private void stopContainer(String containerId, String imageName) { boolean running; try { InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); - running = containerInfo.getState().getRunning(); + running = containerInfo.getState() != null && Boolean.TRUE.equals(containerInfo.getState().getRunning()); } catch (NotFoundException e) { LOGGER.trace("Was going to stop container but it apparently no longer exists: {}", containerId); return; - } catch (DockerException e) { - LOGGER.trace("Error encountered when checking container for shutdown (ID: {}) - it may not have been stopped, or may already be stopped: {}", containerId, e.getMessage()); + } catch (Exception e) { + LOGGER.trace("Error encountered when checking container for shutdown (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", + containerId, + Throwables.getRootCause(e).getMessage()); return; } @@ -232,34 +232,28 @@ private void stopContainer(String containerId, String imageName) { LOGGER.trace("Stopping container: {}", containerId); dockerClient.killContainerCmd(containerId).exec(); LOGGER.trace("Stopped container: {}", imageName); - } catch (ConflictException e) { - if ( e.getMessage().startsWith("Cannot kill container: ") && e.getMessage().endsWith(containerId + " is not running")) { - LOGGER.trace("Was going to kill the container but it apparently already dead : {}", e.getMessage()); - } else { - throw e; - } - } catch (DockerException e) { - LOGGER.trace("Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped: {}", containerId, e.getMessage()); + } catch (Exception e) { + LOGGER.trace("Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", + containerId, + Throwables.getRootCause(e).getMessage()); } } try { dockerClient.inspectContainerCmd(containerId).exec(); - } catch (NotFoundException e) { + } catch (Exception e) { LOGGER.trace("Was going to remove container but it apparently no longer exists: {}", containerId); return; } try { LOGGER.trace("Removing container: {}", containerId); - try { - dockerClient.removeContainerCmd(containerId).withRemoveVolumes(true).withForce(true).exec(); - LOGGER.debug("Removed container and associated volume(s): {}", imageName); - } catch (InternalServerErrorException e) { - LOGGER.trace("Exception when removing container with associated volume(s): {} (due to {})", imageName, e.getMessage()); - } - } catch (DockerException e) { - LOGGER.trace("Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped: {}", containerId, e.getMessage()); + dockerClient.removeContainerCmd(containerId).withRemoveVolumes(true).withForce(true).exec(); + LOGGER.debug("Removed container and associated volume(s): {}", imageName); + } catch (Exception e) { + LOGGER.trace("Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", + containerId, + Throwables.getRootCause(e).getMessage()); } } From e3dffc2a88adceb3a954978b3e6b61db5b9cd103 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 06:42:25 +0000 Subject: [PATCH 0204/4969] Bump aws-java-sdk-sqs from 1.11.604 to 1.11.608 in /modules/localstack (#1728) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8d91198c27b..a943a47d4d0 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.604' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.608' } From 032495ad49ff55d1b1b0546f420e2909e4fd26d5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 08:56:02 +0000 Subject: [PATCH 0205/4969] Bump assertj-core from 3.13.1 to 3.13.2 in /modules/database-commons (#1705) --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index a7ccab63fa9..7c820909d61 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.13.1' + testCompile 'org.assertj:assertj-core:3.13.2' } From 6a90c2f8bfef66585eca0240bcd6f6bb67c666a6 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 10:25:15 +0000 Subject: [PATCH 0206/4969] Bump assertj-core from 3.13.1 to 3.13.2 in /modules/neo4j (#1708) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 5eaae90325f..c7227a2d9ac 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -30,5 +30,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.13.1' + testCompile 'org.assertj:assertj-core:3.13.2' } From 7534938bdb0bb5e9d314c0da6aa64a692b7709fc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 12:30:17 +0000 Subject: [PATCH 0207/4969] Bump pulsar-client from 2.3.2 to 2.4.0 in /modules/pulsar (#1729) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index d0d89d3666c..34cde96a33e 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.3.2' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.4.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.13.2' } From 5f154008ad80f3f109241b3232d511ec69b5c5a5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 14:52:55 +0000 Subject: [PATCH 0208/4969] Bump slf4j-api from 1.7.26 to 1.7.28 in /examples (#1730) --- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index ce0eff58a28..6bf099030ec 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { jcenter() } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.26' + compileOnly 'org.slf4j:slf4j-api:1.7.28' implementation 'com.squareup.okhttp3:okhttp:3.14.2' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.6' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 6446bc43497..777ca2d9511 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.26' + compileOnly 'org.slf4j:slf4j-api:1.7.28' implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index f9239984a9a..8b1a5638243 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.26' + compileOnly 'org.slf4j:slf4j-api:1.7.28' implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 3c73816f578..26a437909fe 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:1.7.26' + compileOnly 'org.slf4j:slf4j-api:1.7.28' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:testcontainers' From 67672a1b1144beae0254040ea49cb045bc6c77ed Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 16:30:24 +0000 Subject: [PATCH 0209/4969] Bump mariadb-java-client from 2.4.2 to 2.4.3 in /modules/mariadb (#1704) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index a501b44f04d..aa85a5d1f5e 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.2' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.3' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.22' From 1693d796fa8976b9112bc775873d542152909e73 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 17:41:52 +0000 Subject: [PATCH 0210/4969] Bump assertj-core from 3.13.1 to 3.13.2 in /modules/kafka (#1707) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index f9b94304b98..9d86482cf2f 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.3.0' - testCompile 'org.assertj:assertj-core:3.13.1' + testCompile 'org.assertj:assertj-core:3.13.2' testCompile 'com.google.guava:guava:23.0' } From 7a7c2fcd64a4a241241594870c378630465b3158 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 13 Aug 2019 06:03:22 +0000 Subject: [PATCH 0211/4969] Bump aws-java-sdk-sqs from 1.11.608 to 1.11.609 in /modules/localstack (#1735) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index a943a47d4d0..fd5ef14c600 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.608' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.609' } From e9e45bcb4cc8dca1e93a63b112e5c9588feddde3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2019 06:06:21 +0000 Subject: [PATCH 0212/4969] Bump aws-java-sdk-sqs from 1.11.609 to 1.11.610 in /modules/localstack (#1741) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index fd5ef14c600..46b805f2f69 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.609' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.610' } From 983d7eba8ba46b7d9c692d2d28fed17790d0c00a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2019 07:21:09 +0000 Subject: [PATCH 0213/4969] Bump lettuce-core from 5.1.7.RELEASE to 5.1.8.RELEASE in /examples (#1696) --- examples/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spock/build.gradle b/examples/spock/build.gradle index cc04f74c90d..147e1eaf079 100644 --- a/examples/spock/build.gradle +++ b/examples/spock/build.gradle @@ -8,7 +8,7 @@ repositories { } dependencies { - compile "io.lettuce:lettuce-core:5.1.7.RELEASE" + compile "io.lettuce:lettuce-core:5.1.8.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' testImplementation 'org.testcontainers:spock' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From d9ca8ef90e6c98f912ab4a099a208b939dcc2497 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2019 09:34:25 +0000 Subject: [PATCH 0214/4969] Bump java-client from 2.7.7 to 2.7.9 in /modules/couchbase (#1714) --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 753e93adb75..063b12c9d8e 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.7' + compile 'com.couchbase.client:java-client:2.7.9' testCompile project(':test-support') } From 49b526cfd172d43a8c7164cfa3d882d0e5aa4a01 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2019 11:10:41 +0000 Subject: [PATCH 0215/4969] Bump org.springframework.boot in /examples (#1736) --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index d4f3c132896..22198984e33 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.6.RELEASE' + id 'org.springframework.boot' version '2.1.7.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 52767c7a9ca..7af6b9d26da 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.6.RELEASE' + id 'org.springframework.boot' version '2.1.7.RELEASE' } apply plugin: 'io.spring.dependency-management' From 9a9684106dafe06af47c85bd076d62f9074ae38e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2019 06:03:53 +0000 Subject: [PATCH 0216/4969] Bump aws-java-sdk-sqs from 1.11.610 to 1.11.611 in /modules/localstack (#1747) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 46b805f2f69..2acbdff6541 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.610' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.611' } From 828a14b77aef6fcaa05dc6bd5abed07404363205 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 16 Aug 2019 06:00:18 +0000 Subject: [PATCH 0217/4969] Bump aws-java-sdk-sqs from 1.11.611 to 1.11.612 in /modules/localstack (#1750) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 2acbdff6541..3e9eadf36e5 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.611' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.612' } From f65a5902b2d3a123caef497faf7f09867e436d0c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2019 07:17:08 +0000 Subject: [PATCH 0218/4969] Bump tomcat-jdbc from 9.0.22 to 9.0.24 in /modules/mariadb (#1753) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index aa85a5d1f5e..eb778c6c827 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.3' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.22' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.24' testCompile 'org.vibur:vibur-dbcp:22.2' } From 07154353019f88eee81fa67864bd141ba4956d3b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2019 09:06:53 +0000 Subject: [PATCH 0219/4969] Bump aws-java-sdk-sqs from 1.11.612 to 1.11.613 in /modules/localstack (#1754) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3e9eadf36e5..6384d7e4d50 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.612' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.613' } From 8689f849209e4808681955488763419e4346f804 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2019 10:53:35 +0000 Subject: [PATCH 0220/4969] Bump tomcat-jdbc from 9.0.22 to 9.0.24 in /modules/mysql (#1755) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 3647fe11cc6..d5a366825b9 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.17' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.22' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.24' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From 22030eace3f4bafc735ccb0e402c1202329a95d1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2019 06:18:59 +0000 Subject: [PATCH 0221/4969] Bump aws-java-sdk-sqs from 1.11.613 to 1.11.615 in /modules/localstack (#1762) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 6384d7e4d50..9e7824ef7ce 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.613' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.615' } From 246332d347475fa1f1d3665f9c267e7bb4dd4524 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 06:06:34 +0000 Subject: [PATCH 0222/4969] Bump aws-java-sdk-sqs from 1.11.615 to 1.11.616 in /modules/localstack (#1768) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9e7824ef7ce..d950467e502 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.615' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.616' } From 62d646afbd3aa28da11ce572146b2ebafe71d942 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 22 Aug 2019 14:59:49 +0100 Subject: [PATCH 0223/4969] Reinstate retries for image pulls (#1712) * Reinstate retries for image pulls * Adopt time limit for retries instead of a fixed number of retries * Only retry image pull failures that could potentially succeed next time * Qualify usages of `Instant` and `Duration` --- .../images/RemoteDockerImage.java | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index 7aff7918f6d..257bacc9961 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.ListImagesCmd; import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.model.Image; import com.github.dockerjava.core.command.PullImageResultCallback; import lombok.NonNull; @@ -14,6 +15,8 @@ import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.LazyFuture; +import java.time.Duration; +import java.time.Instant; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -29,6 +32,7 @@ public class RemoteDockerImage extends LazyFuture { */ @Deprecated public static final Set AVAILABLE_IMAGE_NAME_CACHE = new HashSet<>(); + private static final Duration PULL_RETRY_TIME_LIMIT = Duration.ofMinutes(2); private DockerImageName imageName; @@ -73,23 +77,34 @@ protected final String resolve() { return imageName.toString(); } + // The image is not available locally - pull it logger.info("Pulling docker image: {}. Please be patient; this may take some time but only needs to be done once.", imageName); - // The image is not available locally - pull it - try { - final PullImageResultCallback callback = new TimeLimitedLoggedPullImageResultCallback(logger); - dockerClient - .pullImageCmd(imageName.getUnversionedPart()) - .withTag(imageName.getVersionPart()) - .exec(callback); - callback.awaitCompletion(); - AVAILABLE_IMAGE_NAME_CACHE.add(imageName); - } catch (Exception e) { - logger.error("Failed to pull image: {}. Please check output of `docker pull {}`", imageName, imageName); - throw new ContainerFetchException("Failed to pull image: " + imageName, e); + Exception lastFailure = null; + final Instant lastRetryAllowed = Instant.now().plus(PULL_RETRY_TIME_LIMIT); + + while (Instant.now().isBefore(lastRetryAllowed)) { + try { + final PullImageResultCallback callback = new TimeLimitedLoggedPullImageResultCallback(logger); + dockerClient + .pullImageCmd(imageName.getUnversionedPart()) + .withTag(imageName.getVersionPart()) + .exec(callback); + callback.awaitCompletion(); + AVAILABLE_IMAGE_NAME_CACHE.add(imageName); + + return imageName.toString(); + } catch (InterruptedException | InternalServerErrorException e) { + // these classes of exception often relate to timeout/connection errors so should be retried + lastFailure = e; + logger.warn("Retrying pull for image: {} ({}s remaining)", + imageName, + Duration.between(Instant.now(), lastRetryAllowed).getSeconds()); + } } + logger.error("Failed to pull image: {}. Please check output of `docker pull {}`", imageName, imageName, lastFailure); - return imageName.toString(); + throw new ContainerFetchException("Failed to pull image: " + imageName, lastFailure); } catch (DockerClientException e) { throw new ContainerFetchException("Failed to get Docker client for " + imageName, e); } From 2d1df1648c41c7dcb3508fae130bbbdf5faf47dd Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 23 Aug 2019 08:43:33 +0100 Subject: [PATCH 0224/4969] Refs #1769: mark toxiproxy tests as flaky pending further analysis (#1772) --- modules/toxiproxy/build.gradle | 2 ++ .../java/org/testcontainers/containers/ToxiproxyTest.java | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index 0d004fd32bf..293b8f8f190 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -6,4 +6,6 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + + testCompile project(':test-support') } diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index 34861f68f7a..8fa28431ab5 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -3,6 +3,8 @@ import eu.rekawek.toxiproxy.model.ToxicDirection; import org.junit.Rule; import org.junit.Test; +import org.testcontainers.testsupport.Flaky; +import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; import redis.clients.jedis.Jedis; import redis.clients.jedis.exceptions.JedisConnectionException; @@ -30,6 +32,9 @@ public class ToxiproxyTest { .withNetwork(network); // } + @Rule + public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); + @Test public void testDirect() { final Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getFirstMappedPort()); @@ -40,6 +45,7 @@ public void testDirect() { } @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-10-01") public void testLatencyViaProxy() throws IOException { // obtainProxyObject { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); @@ -66,6 +72,7 @@ public void testLatencyViaProxy() throws IOException { } @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-10-01") public void testConnectionCut() { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); final Jedis jedis = new Jedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); @@ -90,6 +97,7 @@ public void testConnectionCut() { } @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-10-01") public void testMultipleProxiesCanBeCreated() { try (GenericContainer secondRedis = new GenericContainer("redis:5.0.4") .withExposedPorts(6379) From ad5f1f63719c19b01c78746a4efd07eab7ca01c0 Mon Sep 17 00:00:00 2001 From: Evan Gilbert Date: Sun, 25 Aug 2019 10:30:12 -0500 Subject: [PATCH 0225/4969] Exclude jna transitive dependency from visible-assertions to reconcile versions (#1744) --- core/build.gradle | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 42c2dcc5794..c39bb183e82 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -67,7 +67,10 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } - compile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + compile ('org.rnorth.visible-assertions:visible-assertions:2.1.2') { + // Excluded in favor of jna-platform below + exclude(group: "net.java.dev.jna", module: "jna") + } compile ('org.rnorth:tcp-unix-socket-proxy:1.0.2') { exclude(group: "log4j", module: "log4j") From d5f15774187eac4e83346cb59fb00197f07ac5c4 Mon Sep 17 00:00:00 2001 From: Rob Szewczyk Date: Sun, 25 Aug 2019 11:33:15 -0400 Subject: [PATCH 0226/4969] :bug: Fix credentials when using a helper that returns a token (#1734) --- .../utility/RegistryAuthLocator.java | 14 +++++++---- .../utility/RegistryAuthLocatorTest.java | 9 ++++++++ .../config-with-helper-using-token.json | 11 +++++++++ .../auth-config/docker-credential-fake | 23 +++++++++++++++---- .../win/docker-credential-fake.bat | 23 +++++++++++++++---- 5 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 core/src/test/resources/auth-config/config-with-helper-using-token.json diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index 5b248aea04e..e8651167221 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -251,10 +251,16 @@ private AuthConfig runCredentialProvider(String hostName, String helperOrStoreNa final JsonNode helperResponse = OBJECT_MAPPER.readTree(data); log.debug("Credential helper/store provided auth config for: {}", hostName); - return new AuthConfig() - .withRegistryAddress(helperResponse.at("/ServerURL").asText()) - .withUsername(helperResponse.at("/Username").asText()) - .withPassword(helperResponse.at("/Secret").asText()); + final String username = helperResponse.at("/Username").asText(); + final String password = helperResponse.at("/Secret").asText(); + if ("".equals(username)) { + return new AuthConfig().withIdentityToken(password); + } else { + return new AuthConfig() + .withRegistryAddress(helperResponse.at("/ServerURL").asText()) + .withUsername(username) + .withPassword(password); + } } private String getCredentialProgramName(String credHelper) { diff --git a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java index fe930cf78b7..e1cb595e903 100644 --- a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java +++ b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java @@ -69,6 +69,15 @@ public void lookupAuthConfigUsingHelper() throws URISyntaxException { assertEquals("Correct secret is obtained from a credential store", "secret", authConfig.getPassword()); } + @Test + public void lookupAuthConfigUsingHelperWithToken() throws URISyntaxException { + final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-helper-using-token.json"); + + final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registrytoken.example.com/org/repo"), new AuthConfig()); + + assertEquals("Correct identitytoken is obtained from a credential store", "secret", authConfig.getIdentitytoken()); + } + @Test public void lookupUsingHelperEmptyAuth() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-empty-auth-with-helper.json"); diff --git a/core/src/test/resources/auth-config/config-with-helper-using-token.json b/core/src/test/resources/auth-config/config-with-helper-using-token.json new file mode 100644 index 00000000000..63b10a1ef5e --- /dev/null +++ b/core/src/test/resources/auth-config/config-with-helper-using-token.json @@ -0,0 +1,11 @@ +{ + "auths": { + "registrytoken.example.com": {} + }, + "HttpHeaders": { + "User-Agent": "Docker-Client/18.03.0-ce (darwin)" + }, + "credHelpers": { + "registrytoken.example.com": "fake" + } +} diff --git a/core/src/test/resources/auth-config/docker-credential-fake b/core/src/test/resources/auth-config/docker-credential-fake index 0fc0d44621e..880009f2c2a 100755 --- a/core/src/test/resources/auth-config/docker-credential-fake +++ b/core/src/test/resources/auth-config/docker-credential-fake @@ -15,8 +15,21 @@ if [[ $inputLine == "https://not.a.real.registry/url" ]]; then exit 1 fi -echo '{' \ - ' "ServerURL": "url",' \ - ' "Username": "username",' \ - ' "Secret": "secret"' \ - '}' +if [[ $inputLine == "registry.example.com" ]]; then + echo '{' \ + ' "ServerURL": "url",' \ + ' "Username": "username",' \ + ' "Secret": "secret"' \ + '}' + exit 0 +fi +if [[ $inputLine == "registrytoken.example.com" ]]; then + echo '{' \ + ' "ServerURL": "url",' \ + ' "Username": "",' \ + ' "Secret": "secret"' \ + '}' + exit 0 +fi + +exit 1 diff --git a/core/src/test/resources/auth-config/win/docker-credential-fake.bat b/core/src/test/resources/auth-config/win/docker-credential-fake.bat index 7b6b27df5a6..4b248973b48 100644 --- a/core/src/test/resources/auth-config/win/docker-credential-fake.bat +++ b/core/src/test/resources/auth-config/win/docker-credential-fake.bat @@ -14,8 +14,21 @@ if "%inputLine%" == "https://not.a.real.registry/url" ( exit 1 ) -echo { -echo "ServerURL": "url", -echo "Username": "username", -echo "Secret": "secret" -echo } +if "%inputLine%" == "registry.example.com" ( + echo { + echo "ServerURL": "url", + echo "Username": "username", + echo "Secret": "secret" + echo } + exit 0 +) +if "%inputLine%" == "registrytoken.example.com" ( + echo { + echo "ServerURL": "url", + echo "Username": "", + echo "Secret": "secret" + echo } + exit 0 +) + +exit 1 From da97377ff459247156cc39814f6a4a6e9009ce65 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2019 18:41:56 +0200 Subject: [PATCH 0227/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#1779) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 6.7.1 to 7.3.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v6.7.1...v7.3.1) Signed-off-by: dependabot-preview[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 699bc54bd9e..6ae9ab00dab 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.7.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.3.1" testCompile "org.elasticsearch.client:transport:6.7.1" } From aab9aa06a8cfa2f04d87f08c2098d7bd5b6f0435 Mon Sep 17 00:00:00 2001 From: Andrew Guibert Date: Sun, 25 Aug 2019 14:14:57 -0500 Subject: [PATCH 0228/4969] Coordinate image removals after stopping containers (#1745) --- .../images/builder/ImageFromDockerfile.java | 23 ++----------------- .../utility/ResourceReaper.java | 20 +++++++++++++++- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 8c653718a69..98d0dda5e5c 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -22,6 +22,7 @@ import org.testcontainers.utility.Base58; import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.LazyFuture; +import org.testcontainers.utility.ResourceReaper; import java.io.IOException; import java.io.PipedInputStream; @@ -42,26 +43,6 @@ public class ImageFromDockerfile extends LazyFuture implements StringsTrait, DockerfileTrait { - private static final Set imagesToDelete = Sets.newConcurrentHashSet(); - - static { - Runtime.getRuntime().addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { - DockerClient dockerClientForCleaning = DockerClientFactory.instance().client(); - try { - for (String dockerImageName : imagesToDelete) { - log.info("Removing image tagged {}", dockerImageName); - try { - dockerClientForCleaning.removeImageCmd(dockerImageName).withForce(true).exec(); - } catch (Throwable e) { - log.warn("Unable to delete image " + dockerImageName, e); - } - } - } catch (DockerClientException e) { - throw new RuntimeException(e); - } - })); - } - private final String dockerImageName; private boolean deleteOnExit = true; @@ -102,7 +83,7 @@ protected final String resolve() { DockerClient dockerClient = DockerClientFactory.instance().client(); try { if (deleteOnExit) { - imagesToDelete.add(dockerImageName); + ResourceReaper.instance().registerImageForCleanup(dockerImageName); } BuildImageResultCallback resultCallback = new BuildImageResultCallback() { diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 53f7693149b..f46db952c37 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -11,6 +11,8 @@ import com.github.dockerjava.api.model.Volume; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; +import com.google.common.collect.Sets; + import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; @@ -51,7 +53,8 @@ public final class ResourceReaper { private static ResourceReaper instance; private final DockerClient dockerClient; private Map registeredContainers = new ConcurrentHashMap<>(); - private Set registeredNetworks = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private Set registeredNetworks = Sets.newConcurrentHashSet(); + private Set registeredImages = Sets.newConcurrentHashSet(); private AtomicBoolean hookIsSet = new AtomicBoolean(false); private ResourceReaper() { @@ -164,6 +167,7 @@ public synchronized static ResourceReaper instance() { public synchronized void performCleanup() { registeredContainers.forEach(this::stopContainer); registeredNetworks.forEach(this::removeNetwork); + registeredImages.forEach(this::removeImage); } /** @@ -337,6 +341,20 @@ public void unregisterNetwork(String identifier) { public void unregisterContainer(String identifier) { registeredContainers.remove(identifier); } + + public void registerImageForCleanup(String dockerImageName) { + setHook(); + registeredImages.add(dockerImageName); + } + + private void removeImage(String dockerImageName) { + LOGGER.trace("Removing image tagged {}", dockerImageName); + try { + dockerClient.removeImageCmd(dockerImageName).withForce(true).exec(); + } catch (Throwable e) { + LOGGER.warn("Unable to delete image " + dockerImageName, e); + } + } private void setHook() { if (hookIsSet.compareAndSet(false, true)) { From a4b70413e71b7ea65675de0475e296a2ce102184 Mon Sep 17 00:00:00 2001 From: glebsts Date: Sun, 25 Aug 2019 22:16:28 +0300 Subject: [PATCH 0229/4969] Fix fixed host port test (#1355) * 'fix fixed host port test' - rewrote test using simple echo http container, followed path of original test; * 'fix fixed host port test' - rewrote assertions to hamcrest, failure in response getting now fails test directly with io exc * 'fix fixed host port test' - as suggested by reviewer, rewrote tests to alpine, also copied some routines from generic container tests * 'fix fixed host port test' - no assertions on basic container start, code style updates based on PR --- .../junit/FixedHostPortContainerTest.java | 93 +++++++++++++++---- 1 file changed, 74 insertions(+), 19 deletions(-) diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index 516fcb8516a..dba48da4db1 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -1,10 +1,19 @@ package org.testcontainers.junit; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.google.common.util.concurrent.Uninterruptibles; import org.junit.Test; +import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.FixedHostPortGenericContainer; import org.testcontainers.containers.GenericContainer; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; +import java.util.concurrent.TimeUnit; /** * Test of {@link FixedHostPortGenericContainer}. Note that this is not an example of typical use (usually, a container @@ -14,28 +23,74 @@ */ public class FixedHostPortContainerTest { - private static final int REDIS_PORT = 6379; + private static final String TEST_IMAGE = "alpine:3.2"; + + /** + * Default http server port (just something different from default) + */ + private static final int TEST_PORT = 5678; + + /** + * test response + */ + private static final String TEST_RESPONSE = "test-response"; + + /** + * *nix pipe to fire test response on test port + */ + private static final String HTTP_ECHO_CMD = + String.format("while true; do echo \"%s\" | nc -l -p %d; done", TEST_RESPONSE, TEST_PORT); @Test public void testFixedHostPortMapping() throws IOException { // first find a free port on the docker host that will work for testing - GenericContainer portDiscoveryRedis = new GenericContainer("redis:3.0.2").withExposedPorts(REDIS_PORT); - portDiscoveryRedis.start(); - Integer freePort = portDiscoveryRedis.getMappedPort(REDIS_PORT); - portDiscoveryRedis.stop(); - - - // Set up a FixedHostPortGenericContainer as if this were a @Rule - FixedHostPortGenericContainer redis = new FixedHostPortGenericContainer("redis:3.0.2").withFixedExposedPort(freePort, REDIS_PORT); - redis.start(); - -// Config redisConfig = new Config(); -// redisConfig.useSingleServer().setAddress(redis.getContainerIpAddress() + ":" + freePort); -// Redisson redisson = Redisson.create(redisConfig); -// -// redisson.getBucket("test").set("foo"); -// -// assertEquals("The bucket content was successfully set", "foo", redisson.getBucket("test").get()); -// assertEquals("The container returns the fixed port from getMappedPort(...)", freePort, redis.getMappedPort(REDIS_PORT)); + final Integer unusedHostPort; + try ( + final GenericContainer echoServer = new GenericContainer<>(TEST_IMAGE) + .withExposedPorts(TEST_PORT) + .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) + ) { + echoServer.start(); + unusedHostPort = echoServer.getMappedPort(TEST_PORT); + } + + // now starting echo server container mapped to known-as-free host port + try ( + final GenericContainer echoServer = new FixedHostPortGenericContainer(TEST_IMAGE) + // using workaround for port bind+expose + .withFixedExposedPort(unusedHostPort, TEST_PORT) + .withExposedPorts(TEST_PORT) + .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) + ) { + echoServer.start(); + + assertThat("Port mapping does not seem to match given fixed port", + echoServer.getMappedPort(TEST_PORT), equalTo(unusedHostPort)); + + final String content = this.readResponse(echoServer, unusedHostPort); + assertThat("Returned echo from fixed port does not match expected", content, equalTo(TEST_RESPONSE)); + } + } + + /** + * Simple socket content reader from given container:port + * + * @param container to query + * @param port to send request to + * @return socket reader content + * @throws IOException if any + */ + private String readResponse(GenericContainer container, Integer port) throws IOException { + try ( + final BufferedReader reader = Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, + () -> { + Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); + final Socket socket = new Socket(container.getContainerIpAddress(), port); + return new BufferedReader(new InputStreamReader(socket.getInputStream())); + } + ) + ) { + return reader.readLine(); + } } } From 79adf4e5f7f2c511a7ce3f0583326ace4448cd1e Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 25 Aug 2019 20:17:01 +0100 Subject: [PATCH 0230/4969] Disable Travis for all but master branch builds (#1720) --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0c03c4931bb..f07d50123e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +if: branch = master + language: java jdk: - oraclejdk8 From 8894daec097aa1e91e434475d4d7edb2f81fdfcd Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Sun, 25 Aug 2019 21:34:14 +0200 Subject: [PATCH 0231/4969] add check for compatible Docker OS type (#1780) * add container OSType check for Windows strategies as Windows containers are not supported at the moment * fix typo * generic check for OS Type, as we currently only support Linux containers * use debug logging when checking OS type * words --- .../dockerclient/DockerClientProviderStrategy.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index a9321276fd6..57cccc8b540 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -5,6 +5,7 @@ import com.github.dockerjava.core.DockerClientConfig; import com.google.common.base.Throwables; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; import org.rnorth.ducttape.TimeoutException; import org.rnorth.ducttape.ratelimits.RateLimiter; @@ -111,6 +112,7 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List Date: Sun, 25 Aug 2019 22:51:24 +0300 Subject: [PATCH 0232/4969] Fix Deprecated MySQL Class Name (#1760) * Fix #1655 * MySQL driver discovery in MySQLContainer instead of JdbcDatabaseContainer --- .../java/org/testcontainers/containers/MySQLContainer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 172ead4856a..fa2e8626b0d 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -56,7 +56,12 @@ protected void configure() { @Override public String getDriverClassName() { - return "com.mysql.jdbc.Driver"; + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + return "com.mysql.cj.jdbc.Driver"; + } catch (ClassNotFoundException e) { + return "com.mysql.jdbc.Driver"; + } } @Override From 764ab17217b2fdb67898f9ea00bdfdc7e6b4798b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2019 22:40:53 +0200 Subject: [PATCH 0233/4969] Bump mockito-core from 2.28.2 to 3.0.0 in /core (#1635) Bumps [mockito-core](https://github.com/mockito/mockito) from 2.28.2 to 3.0.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v2.28.2...v3.0.0) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index c39bb183e82..9698160c033 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -109,7 +109,7 @@ dependencies { testCompile 'redis.clients:jedis:3.0.1' testCompile 'com.rabbitmq:amqp-client:5.7.2' testCompile 'org.mongodb:mongo-java-driver:3.10.2' - testCompile ('org.mockito:mockito-core:2.28.2') { + testCompile ('org.mockito:mockito-core:3.0.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 7228a2df3cd7a02ad644c072525d3276fd8a25fb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2019 22:34:24 +0000 Subject: [PATCH 0234/4969] Bump aws-java-sdk-sqs from 1.11.616 to 1.11.618 in /modules/localstack (#1785) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d950467e502..897e337ddb5 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.616' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.618' } From e6cd4f51523a1b4e4c5f5821a6fe9bd1081702c3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2019 23:53:33 +0000 Subject: [PATCH 0235/4969] Bump selenium-firefox-driver from 3.14.0 to 3.141.59 in /examples (#1748) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 069e0a8881a..5467783ef92 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' - implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.14.0' + implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.7.1' testImplementation 'io.cucumber:cucumber-junit:4.7.1' From 6fda0556732087659b24ffa81710bcef3726867f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2019 06:33:51 +0000 Subject: [PATCH 0236/4969] Bump assertj-core from 3.12.2 to 3.13.2 in /core (#1789) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9698160c033..2b4c76ee4b1 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -115,7 +115,7 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.12.2' + testCompile 'org.assertj:assertj-core:3.13.2' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" From f9fc67147ea68cbaab4c9fcd128c6b2c57588626 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2019 08:36:43 +0100 Subject: [PATCH 0237/4969] Bump snakeyaml from 1.21 to 1.25 in /core (#1742) Bumps [snakeyaml](https://bitbucket.org/asomov/snakeyaml) from 1.21 to 1.25. - [Commits](https://bitbucket.org/asomov/snakeyaml/commits) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 2b4c76ee4b1..78b60a41de0 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -95,7 +95,7 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded "org.yaml:snakeyaml:1.21" + shaded "org.yaml:snakeyaml:1.25" shaded 'com.squareup.okhttp3:okhttp:3.14.2' From 7d93069b1f427ed530a2cd465fca58554af81051 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2019 08:37:03 +0100 Subject: [PATCH 0238/4969] Bump jedis from 3.0.1 to 3.1.0 in /core (#1656) Bumps [jedis](https://github.com/xetorthio/jedis) from 3.0.1 to 3.1.0. - [Release notes](https://github.com/xetorthio/jedis/releases) - [Commits](https://github.com/xetorthio/jedis/compare/jedis-3.0.1...jedis-3.1.0) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 78b60a41de0..2235b53742e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -106,7 +106,7 @@ dependencies { } testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testCompile 'redis.clients:jedis:3.0.1' + testCompile 'redis.clients:jedis:3.1.0' testCompile 'com.rabbitmq:amqp-client:5.7.2' testCompile 'org.mongodb:mongo-java-driver:3.10.2' testCompile ('org.mockito:mockito-core:3.0.0') { From 827c4c567a30a1c43483a85c326883d051ea539d Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 26 Aug 2019 10:45:12 +0200 Subject: [PATCH 0239/4969] Separate "environment" and "classpath" properties (for global things) (#1784) * Separate "environment" and "classpath" properties (for global things) * Update TestcontainersConfiguration.java --- .../DockerClientProviderStrategy.java | 18 +--- .../utility/TestcontainersConfiguration.java | 97 ++++++++++--------- .../TestcontainersConfigurationTest.java | 43 ++++++++ 3 files changed, 99 insertions(+), 59 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 57cccc8b540..7101b23b21a 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -167,20 +167,10 @@ public DockerClient getClient() { } protected DockerClient getClientForConfig(DockerClientConfig config) { - DockerClientBuilder clientBuilder = DockerClientBuilder - .getInstance(new AuthDelegatingDockerClientConfig(config)); - - String transportType = TestcontainersConfiguration.getInstance().getTransportType(); - if ("okhttp".equals(transportType)) { - clientBuilder - .withDockerCmdExecFactory(new OkHttpDockerCmdExecFactory()); - } else { - throw new IllegalArgumentException("Unknown transport type: " + transportType); - } - - LOGGER.info("Will use '{}' transport", transportType); - - return clientBuilder.build(); + return DockerClientBuilder + .getInstance(new AuthDelegatingDockerClientConfig(config)) + .withDockerCmdExecFactory(new OkHttpDockerCmdExecFactory()) + .build(); } protected void ping(DockerClient client, int timeoutInSeconds) { diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 608d02716d0..b7ef772fcf5 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -5,6 +5,7 @@ import java.io.*; import java.net.MalformedURLException; +import java.net.URL; import java.util.Objects; import java.util.Properties; import java.util.stream.Stream; @@ -19,12 +20,22 @@ public class TestcontainersConfiguration { private static String PROPERTIES_FILE_NAME = "testcontainers.properties"; - private static File GLOBAL_CONFIG_FILE = new File(System.getProperty("user.home"), "." + PROPERTIES_FILE_NAME); + private static File ENVIRONMENT_CONFIG_FILE = new File(System.getProperty("user.home"), "." + PROPERTIES_FILE_NAME); @Getter(lazy = true) private static final TestcontainersConfiguration instance = loadConfiguration(); - private final Properties properties; + @Getter(AccessLevel.NONE) + private final Properties environmentProperties; + + private final Properties properties = new Properties(); + + TestcontainersConfiguration(Properties environmentProperties, Properties classpathProperties) { + this.environmentProperties = environmentProperties; + + this.properties.putAll(classpathProperties); + this.properties.putAll(environmentProperties); + } public String getAmbassadorContainerImage() { return (String) properties.getOrDefault("ambassador.container.image", "richnorth/ambassador:latest"); @@ -71,13 +82,18 @@ public String getPulsarImage() { } public boolean isDisableChecks() { - return Boolean.parseBoolean((String) properties.getOrDefault("checks.disable", "false")); + return Boolean.parseBoolean((String) environmentProperties.getOrDefault("checks.disable", "false")); } public String getDockerClientStrategyClassName() { - return (String) properties.get("docker.client.strategy"); + return (String) environmentProperties.get("docker.client.strategy"); } + /** + * + * @deprecated we no longer have different transport types + */ + @Deprecated public String getTransportType() { return properties.getProperty("transport.type", "okhttp"); } @@ -89,64 +105,55 @@ public Integer getImagePullPauseTimeout() { @Synchronized public boolean updateGlobalConfig(@NonNull String prop, @NonNull String value) { try { - Properties globalProperties = new Properties(); - GLOBAL_CONFIG_FILE.createNewFile(); - try (InputStream inputStream = new FileInputStream(GLOBAL_CONFIG_FILE)) { - globalProperties.load(inputStream); - } - - if (value.equals(globalProperties.get(prop))) { + if (value.equals(environmentProperties.get(prop))) { return false; } - globalProperties.setProperty(prop, value); + environmentProperties.setProperty(prop, value); - try (OutputStream outputStream = new FileOutputStream(GLOBAL_CONFIG_FILE)) { - globalProperties.store(outputStream, "Modified by Testcontainers"); + ENVIRONMENT_CONFIG_FILE.createNewFile(); + try (OutputStream outputStream = new FileOutputStream(ENVIRONMENT_CONFIG_FILE)) { + environmentProperties.store(outputStream, "Modified by Testcontainers"); } - // Update internal state only if global config was successfully updated + // Update internal state only if environment config was successfully updated properties.setProperty(prop, value); return true; } catch (Exception e) { - log.debug("Can't store global property {} in {}", prop, GLOBAL_CONFIG_FILE); + log.debug("Can't store environment property {} in {}", prop, ENVIRONMENT_CONFIG_FILE); return false; } } @SneakyThrows(MalformedURLException.class) private static TestcontainersConfiguration loadConfiguration() { - final TestcontainersConfiguration config = new TestcontainersConfiguration( - Stream - .of( - TestcontainersConfiguration.class.getClassLoader().getResource(PROPERTIES_FILE_NAME), - Thread.currentThread().getContextClassLoader().getResource(PROPERTIES_FILE_NAME), - GLOBAL_CONFIG_FILE.toURI().toURL() - ) - .filter(Objects::nonNull) - .map(it -> { - log.debug("Testcontainers configuration overrides will be loaded from {}", it); - - final Properties subProperties = new Properties(); - try (final InputStream inputStream = it.openStream()) { - subProperties.load(inputStream); - } catch (FileNotFoundException e) { - log.trace("Testcontainers config override was found on " + it + " but the file was not found", e); - } catch (IOException e) { - log.warn("Testcontainers config override was found on " + it + " but could not be loaded", e); - } - return subProperties; - }) - .reduce(new Properties(), (a, b) -> { - a.putAll(b); - return a; - }) + return new TestcontainersConfiguration( + readProperties(ENVIRONMENT_CONFIG_FILE.toURI().toURL()), + Stream + .of( + TestcontainersConfiguration.class.getClassLoader(), + Thread.currentThread().getContextClassLoader() + ) + .map(it -> it.getResource(PROPERTIES_FILE_NAME)) + .filter(Objects::nonNull) + .map(TestcontainersConfiguration::readProperties) + .reduce(new Properties(), (a, b) -> { + a.putAll(b); + return a; + }) ); + } - if (!config.getProperties().isEmpty()) { - log.debug("Testcontainers configuration overrides loaded from {}", config); + private static Properties readProperties(URL url) { + log.debug("Testcontainers configuration overrides will be loaded from {}", url); + Properties properties = new Properties(); + try (InputStream inputStream = url.openStream()) { + properties.load(inputStream); + } catch (FileNotFoundException e) { + log.trace("Testcontainers config override was found on {} but the file was not found", url, e); + } catch (IOException e) { + log.warn("Testcontainers config override was found on {} but could not be loaded", url, e); } - - return config; + return properties; } } diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java new file mode 100644 index 00000000000..ad2a0be6cd3 --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -0,0 +1,43 @@ +package org.testcontainers.utility; + +import org.junit.Test; + +import java.util.Properties; +import java.util.UUID; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; + +public class TestcontainersConfigurationTest { + + final Properties environmentProperties = new Properties(); + + final Properties classpathProperties = new Properties(); + + @Test + public void shouldReadChecksFromEnvironmentOnly() { + assertFalse("checks enabled by default", newConfig().isDisableChecks()); + + classpathProperties.setProperty("checks.disable", "true"); + assertFalse("checks are not affected by classpath properties", newConfig().isDisableChecks()); + + environmentProperties.setProperty("checks.disable", "true"); + assertTrue("checks disabled", newConfig().isDisableChecks()); + } + + @Test + public void shouldReadDockerClientStrategyFromEnvironmentOnly() { + String currentValue = newConfig().getDockerClientStrategyClassName(); + + classpathProperties.setProperty("docker.client.strategy", UUID.randomUUID().toString()); + assertEquals("Docker client strategy is not affected by classpath properties", currentValue, newConfig().getDockerClientStrategyClassName()); + + environmentProperties.setProperty("docker.client.strategy", "foo"); + assertEquals("Docker client strategy is changed", "foo", newConfig().getDockerClientStrategyClassName()); + } + + private TestcontainersConfiguration newConfig() { + return new TestcontainersConfiguration(environmentProperties, classpathProperties); + } +} From 137c510f96e89fdf359c5a7e36af3f82e06e6430 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 26 Aug 2019 10:47:13 +0200 Subject: [PATCH 0240/4969] speed up port detection by running the checks as a single command (#1782) --- .../internal/ExternalPortListeningCheck.java | 4 +- .../InternalCommandPortListeningCheck.java | 45 ++++++++++--------- .../wait/strategy/HostPortWaitStrategy.java | 4 +- ...InternalCommandPortListeningCheckTest.java | 10 ++--- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java index 3283880b569..2aae12bab8d 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java @@ -20,13 +20,13 @@ public class ExternalPortListeningCheck implements Callable { public Boolean call() { String address = containerState.getContainerIpAddress(); - for (Integer externalPort : externalLivenessCheckPorts) { + externalLivenessCheckPorts.parallelStream().forEach(externalPort -> { try { new Socket(address, externalPort).close(); } catch (IOException e) { throw new IllegalStateException("Socket not listening yet: " + externalPort); } - } + }); return true; } } diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index bad30fef653..43ed94bc84d 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -1,9 +1,13 @@ package org.testcontainers.containers.wait.internal; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.containers.Container.ExecResult; import org.testcontainers.containers.ExecInContainerPattern; import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; +import java.time.Duration; +import java.time.Instant; import java.util.Set; import static java.lang.String.format; @@ -12,6 +16,7 @@ * Mechanism for testing that a socket is listening when run from the container being checked. */ @RequiredArgsConstructor +@Slf4j public class InternalCommandPortListeningCheck implements java.util.concurrent.Callable { private final WaitStrategyTarget waitStrategyTarget; @@ -19,30 +24,26 @@ public class InternalCommandPortListeningCheck implements java.util.concurrent.C @Override public Boolean call() { - for (Integer internalPort : internalPorts) { - tryPort(internalPort); + String command = "true"; + + for (int internalPort : internalPorts) { + command += " && "; + command += " ("; + command += format("cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%x", internalPort); + command += " || "; + command += format("nc -vz -w 1 localhost %d", internalPort); + command += " || "; + command += format("/bin/bash -c ' externalLivenessCheckPorts = getLivenessCheckPorts(); if (externalLivenessCheckPorts.isEmpty()) { - log.debug("Liveness check ports of {} is empty. Not waiting.", waitStrategyTarget.getContainerInfo().getName()); + if (log.isDebugEnabled()) { + log.debug("Liveness check ports of {} is empty. Not waiting.", waitStrategyTarget.getContainerInfo().getName()); + } return; } diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java index c1cd341943e..71a14c3c79e 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java @@ -6,7 +6,7 @@ import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class InternalCommandPortListeningCheckTest { @@ -30,8 +30,8 @@ public void singleListening() { public void nonListening() { final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(nginx, ImmutableSet.of(8080, 1234)); - assertThrows("InternalCommandPortListeningCheck detects a non-listening port among many", - IllegalStateException.class, - (Runnable) check::call); + final Boolean result = check.call(); + + assertFalse("InternalCommandPortListeningCheck detects a non-listening port among many", result); } -} \ No newline at end of file +} From a0f5d0008f5a89929dba388557a49718a3e0af20 Mon Sep 17 00:00:00 2001 From: William Delanoue Date: Mon, 26 Aug 2019 20:58:50 +0200 Subject: [PATCH 0241/4969] Support legacy RabbitMQ configuration format (#1692) see https://github.com/testcontainers/testcontainers-java/issues/1690 --- .../containers/RabbitMQContainer.java | 32 ++- .../containers/RabbitMQContainerTest.java | 195 +++++++++++------- .../src/test/resources/rabbitmq-custom.conf | 2 +- .../src/test/resources/rabbitmq-custom.config | 13 ++ 4 files changed, 161 insertions(+), 81 deletions(-) create mode 100644 modules/rabbitmq/src/test/resources/rabbitmq-custom.config diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index f16f005df5e..4faaf3a5dea 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -346,16 +346,42 @@ public RabbitMQContainer withExchange(String name, String type, boolean autoDele } /** - * Overwrites the default RabbitMQ configuration file with the supplied one + * Overwrites the default RabbitMQ configuration file with the supplied one. * - * @param rabbitMQConf The rabbitmq.conf file to use + * @param rabbitMQConf The rabbitmq.conf file to use (in sysctl format, don't forget empty line in the end of file) * @return This container. */ public RabbitMQContainer withRabbitMQConfig(MountableFile rabbitMQConf) { - withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom.conf"); + + return withRabbitMQConfigSysctl(rabbitMQConf); + } + + /** + * Overwrites the default RabbitMQ configuration file with the supplied one. + * + * This function doesn't work with RabbitMQ < 3.7. + * + * This function and the Sysctl format is recommended for RabbitMQ >= 3.7 + * + * @param rabbitMQConf The rabbitmq.config file to use (in sysctl format, don't forget empty line in the end of file) + * @return This container. + */ + public RabbitMQContainer withRabbitMQConfigSysctl(MountableFile rabbitMQConf) { + withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom"); return withCopyFileToContainer(rabbitMQConf, "/etc/rabbitmq/rabbitmq-custom.conf"); } + /** + * Overwrites the default RabbitMQ configuration file with the supplied one. + * + * @param rabbitMQConf The rabbitmq.config file to use (in erlang format) + * @return This container. + */ + public RabbitMQContainer withRabbitMQConfigErlang(MountableFile rabbitMQConf) { + withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom.config"); + return withCopyFileToContainer(rabbitMQConf, "/etc/rabbitmq/rabbitmq-custom.config"); + } + @NotNull private String toJson(Map arguments) { try { diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index 4f549a6f5ed..bdda594818f 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -1,26 +1,29 @@ package org.testcontainers.containers; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER; +import static org.testcontainers.utility.MountableFile.forClasspathResource; + import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; -import org.junit.Test; -import org.testcontainers.utility.MountableFile; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.security.*; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER; -import static org.testcontainers.utility.MountableFile.forClasspathResource; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import org.junit.Test; +import org.testcontainers.utility.MountableFile; /** * @author Martin Greber @@ -34,7 +37,8 @@ public class RabbitMQContainerTest { public static final int DEFAULT_HTTP_PORT = 15672; @Test - public void shouldCreateRabbitMQContainer() { + public void shouldCreateRabbitMQContainer() + { try (RabbitMQContainer container = new RabbitMQContainer()) { assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE); @@ -44,13 +48,13 @@ public void shouldCreateRabbitMQContainer() { container.start(); assertThat(container.getAmqpsUrl()).isEqualTo( - String.format("amqps://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQPS_PORT))); + String.format("amqps://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQPS_PORT))); assertThat(container.getAmqpUrl()).isEqualTo( - String.format("amqp://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQP_PORT))); + String.format("amqp://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQP_PORT))); assertThat(container.getHttpsUrl()).isEqualTo( - String.format("https://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTPS_PORT))); + String.format("https://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTPS_PORT))); assertThat(container.getHttpUrl()).isEqualTo( - String.format("http://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTP_PORT))); + String.format("http://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTP_PORT))); assertThat(container.getHttpsPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTPS_PORT)); assertThat(container.getHttpPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTP_PORT)); @@ -58,140 +62,176 @@ public void shouldCreateRabbitMQContainer() { assertThat(container.getAmqpPort()).isEqualTo(container.getMappedPort(DEFAULT_AMQP_PORT)); assertThat(container.getLivenessCheckPortNumbers()).containsExactlyInAnyOrder( - container.getMappedPort(DEFAULT_AMQP_PORT), - container.getMappedPort(DEFAULT_AMQPS_PORT), - container.getMappedPort(DEFAULT_HTTP_PORT), - container.getMappedPort(DEFAULT_HTTPS_PORT) + container.getMappedPort(DEFAULT_AMQP_PORT), + container.getMappedPort(DEFAULT_AMQPS_PORT), + container.getMappedPort(DEFAULT_HTTP_PORT), + container.getMappedPort(DEFAULT_HTTPS_PORT) ); } } @Test - public void shouldCreateRabbitMQContainerWithTag() { + public void shouldCreateRabbitMQContainerWithTag() + { try (RabbitMQContainer container = new RabbitMQContainer(DEFAULT_IMAGE)) { assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE); } } @Test - public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException { + public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException + { try (RabbitMQContainer container = new RabbitMQContainer()) { container.withExchange("test-exchange", "direct"); container.start(); assertThat(container.execInContainer("rabbitmqctl", "list_exchanges").getStdout()) - .containsPattern("test-exchange\\s+direct"); + .containsPattern("test-exchange\\s+direct"); } } @Test - public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException { + public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException + { try (RabbitMQContainer container = new RabbitMQContainer()) { container.withQueue("queue-one") - .withQueue("queue-two", false, true, ImmutableMap.of("x-message-ttl", 1000)); + .withQueue("queue-two", false, true, ImmutableMap.of("x-message-ttl", 1000)); container.start(); assertThat(container.execInContainer("rabbitmqctl", "list_queues", "name", "arguments").getStdout()) - .containsPattern("queue-one"); + .containsPattern("queue-one"); assertThat(container.execInContainer("rabbitmqctl", "list_queues", "name", "arguments").getStdout()) - .containsPattern("queue-two\\s.*x-message-ttl"); + .containsPattern("queue-two\\s.*x-message-ttl"); + } + } + + @Test + public void shouldMountConfigurationFile() + { + try (RabbitMQContainer container = new RabbitMQContainer()) { + + container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); + container.start(); + + assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.conf"); + assertThat(container.getLogs()).doesNotContain(" (not found)"); } } + + @Test + public void shouldMountConfigurationFileErlang() + { + try (RabbitMQContainer container = new RabbitMQContainer()) { + + container.withRabbitMQConfigErlang(MountableFile.forClasspathResource("/rabbitmq-custom.config")); + container.start(); + + assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.config"); + assertThat(container.getLogs()).doesNotContain(" (not found)"); + } + } + + @Test - public void shouldMountConfigurationFile() { + public void shouldMountConfigurationFileSysctl() + { try (RabbitMQContainer container = new RabbitMQContainer()) { container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); container.start(); - assertThat(container.getLogs().contains("/etc/rabbitmq/rabbitmq-custom.conf")).isTrue(); + assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.conf"); + assertThat(container.getLogs()).doesNotContain(" (not found)"); } } @Test - public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException { + public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException + { try (RabbitMQContainer container = new RabbitMQContainer()) { container - .withVhost("vhost1") - .withVhostLimit("vhost1", "max-connections", 1) - .withVhost("vhost2", true) - .withExchange("direct-exchange", "direct") - .withExchange("topic-exchange", "topic") - .withQueue("queue1") - .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) - .withBinding("direct-exchange", "queue1") - .withUser("user1", "password1") - .withUser("user2", "password2", ImmutableSet.of("administrator")) - .withPermission("vhost1", "user1", ".*", ".*", ".*") - .withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues") - .withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct")) - .withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues") - .withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange"); + .withVhost("vhost1") + .withVhostLimit("vhost1", "max-connections", 1) + .withVhost("vhost2", true) + .withExchange("direct-exchange", "direct") + .withExchange("topic-exchange", "topic") + .withQueue("queue1") + .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) + .withBinding("direct-exchange", "queue1") + .withUser("user1", "password1") + .withUser("user2", "password2", ImmutableSet.of("administrator")) + .withPermission("vhost1", "user1", ".*", ".*", ".*") + .withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues") + .withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct")) + .withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues") + .withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange"); container.start(); assertThat(container.execInContainer("rabbitmqadmin", "list", "queues") - .getStdout()) - .contains("queue1", "queue2"); + .getStdout()) + .contains("queue1", "queue2"); assertThat(container.execInContainer("rabbitmqadmin", "list", "exchanges") - .getStdout()) - .contains("direct-exchange", "topic-exchange"); + .getStdout()) + .contains("direct-exchange", "topic-exchange"); assertThat(container.execInContainer("rabbitmqadmin", "list", "bindings") - .getStdout()) - .contains("direct-exchange"); + .getStdout()) + .contains("direct-exchange"); assertThat(container.execInContainer("rabbitmqadmin", "list", "users") - .getStdout()) - .contains("user1", "user2"); + .getStdout()) + .contains("user1", "user2"); assertThat(container.execInContainer("rabbitmqadmin", "list", "policies") - .getStdout()) - .contains("max length policy", "alternate exchange policy"); + .getStdout()) + .contains("max length policy", "alternate exchange policy"); assertThat(container.execInContainer("rabbitmqadmin", "list", "operator_policies") - .getStdout()) - .contains("operator policy 1"); + .getStdout()) + .contains("operator policy 1"); assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_shovel", "--quiet") - .getStdout()) - .contains("rabbitmq_shovel is enabled"); + .getStdout()) + .contains("rabbitmq_shovel is enabled"); assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_random_exchange", "--quiet") - .getStdout()) - .contains("rabbitmq_random_exchange is enabled"); + .getStdout()) + .contains("rabbitmq_random_exchange is enabled"); } } @Test - public void shouldThrowExceptionForDodgyJson() { + public void shouldThrowExceptionForDodgyJson() + { try (RabbitMQContainer container = new RabbitMQContainer()) { assertThatCode(() -> - container.withQueue( - "queue2", - true, - false, - ImmutableMap.of("x-message-ttl", container)) + container.withQueue( + "queue2", + true, + false, + ImmutableMap.of("x-message-ttl", container)) ).hasMessageStartingWith("Failed to convert arguments into json"); } } @Test - public void shouldWorkWithSSL() { + public void shouldWorkWithSSL() + { try (RabbitMQContainer container = new RabbitMQContainer()) { container.withSSL( - forClasspathResource("/certs/server_key.pem", 0644), - forClasspathResource("/certs/server_certificate.pem", 0644), - forClasspathResource("/certs/ca_certificate.pem", 0644), - VERIFY_PEER, - true + forClasspathResource("/certs/server_key.pem", 0644), + forClasspathResource("/certs/server_certificate.pem", 0644), + forClasspathResource("/certs/ca_certificate.pem", 0644), + VERIFY_PEER, + true ); container.start(); @@ -199,8 +239,8 @@ public void shouldWorkWithSSL() { assertThatCode(() -> { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.useSslProtocol(createSslContext( - "certs/client_key.p12", "password", - "certs/truststore.jks", "password")); + "certs/client_key.p12", "password", + "certs/truststore.jks", "password")); connectionFactory.enableHostnameVerification(); connectionFactory.setUri(container.getAmqpsUrl()); connectionFactory.setPassword(container.getAdminPassword()); @@ -213,7 +253,8 @@ public void shouldWorkWithSSL() { } private SSLContext createSslContext(String keystoreFile, String keystorePassword, String truststoreFile, String truststorePassword) - throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException + { ClassLoader classLoader = getClass().getClassLoader(); KeyStore ks = KeyStore.getInstance("PKCS12"); diff --git a/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf b/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf index 2e93b89bb13..293829a353b 100644 --- a/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf +++ b/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf @@ -1,2 +1,2 @@ loopback_users.guest = false -listeners.tcp.default = 5555 \ No newline at end of file +listeners.tcp.default = 5555 diff --git a/modules/rabbitmq/src/test/resources/rabbitmq-custom.config b/modules/rabbitmq/src/test/resources/rabbitmq-custom.config new file mode 100644 index 00000000000..a1c581542ce --- /dev/null +++ b/modules/rabbitmq/src/test/resources/rabbitmq-custom.config @@ -0,0 +1,13 @@ +[ +{ rabbit, [ +{ loopback_users, [ ] }, + { tcp_listeners, [ 5555 ] }, + { ssl_listeners, [ ] }, + { default_vhost, <<"vhost">> }, + { hipe_compile, false } + ] }, + { rabbitmq_management, [ { listener, [ + { port, 15672 }, + { ssl, false } + ] } ] } +]. From b5fda2acf41d67f800b92a86285ee9e60ebd3078 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2019 19:59:34 +0100 Subject: [PATCH 0242/4969] Bump mockito-core from 2.28.2 to 3.0.0 in /modules/junit-jupiter (#1636) Bumps [mockito-core](https://github.com/mockito/mockito) from 2.28.2 to 3.0.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v2.28.2...v3.0.0) Signed-off-by: dependabot-preview[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5710b48fd15..2a0937a85d7 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'redis.clients:jedis:3.1.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testCompile ('org.mockito:mockito-core:2.28.2') { + testCompile ('org.mockito:mockito-core:3.0.0') { exclude(module: 'hamcrest-core') } From 2c21181520086a966714de4bd57bde360d6133f7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2019 05:57:08 +0000 Subject: [PATCH 0243/4969] Bump aws-java-sdk-sqs from 1.11.618 to 1.11.619 in /modules/localstack (#1793) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 897e337ddb5..24474e5b697 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.618' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.619' } From 91acbb4f4934eae5b2b3c8a0c2f9355c8f489675 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2019 16:12:00 +0100 Subject: [PATCH 0244/4969] Bump mongo-java-driver from 3.10.2 to 3.11.0 in /core (#1795) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.10.2 to 3.11.0. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.10.2...r3.11.0) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 2235b53742e..dee1acb4d69 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,7 +108,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.1.0' testCompile 'com.rabbitmq:amqp-client:5.7.2' - testCompile 'org.mongodb:mongo-java-driver:3.10.2' + testCompile 'org.mongodb:mongo-java-driver:3.11.0' testCompile ('org.mockito:mockito-core:3.0.0') { exclude(module: 'hamcrest-core') } From 0044218c722c174d1968c5a5e933edb5efb5ceca Mon Sep 17 00:00:00 2001 From: Yoonyoul Yoo Date: Wed, 28 Aug 2019 00:14:20 +0900 Subject: [PATCH 0245/4969] update latest version with 1.12.0 (#1800) --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 044489d1e50..f0d953ecd8a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,4 +82,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.11.3 + latest_version: 1.12.0 From 8405607b9da8fc324adf1b5b3162f8fb3c2e257d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2019 09:31:09 +0000 Subject: [PATCH 0246/4969] Bump aws-java-sdk-sqs from 1.11.619 to 1.11.620 in /modules/localstack (#1803) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 24474e5b697..d808e44d594 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.619' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.620' } From 2c72803f3dc4acea93ab31988d2ad3d4890a269a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2019 06:03:39 +0000 Subject: [PATCH 0247/4969] Bump aws-java-sdk-sqs from 1.11.620 to 1.11.621 in /modules/localstack (#1808) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d808e44d594..bfb94e0a16b 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.620' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.621' } From 040b35dd2b7163b1687ca9f5d39f7de7e67f1df9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2019 07:37:08 +0000 Subject: [PATCH 0248/4969] Bump cucumber-junit from 4.7.1 to 4.7.2 in /examples (#1809) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 5467783ef92..062fbf84612 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.7.1' - testImplementation 'io.cucumber:cucumber-junit:4.7.1' + testImplementation 'io.cucumber:cucumber-junit:4.7.2' testImplementation 'org.testcontainers:selenium' } From 6e7546ac3bf923f1f00fe4178be5ff2655403400 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2019 05:55:27 +0000 Subject: [PATCH 0249/4969] Bump aws-java-sdk-sqs from 1.11.621 to 1.11.622 in /modules/localstack (#1811) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index bfb94e0a16b..371891ce27a 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.621' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.622' } From a3190044dd940c8ec61bfc5b5441fb07d5f161bf Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2019 06:44:56 +0000 Subject: [PATCH 0250/4969] Bump cucumber-java from 4.7.1 to 4.7.2 in /examples (#1812) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 062fbf84612..7e73852ca1d 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.7.1' + implementation 'io.cucumber:cucumber-java:4.7.2' testImplementation 'io.cucumber:cucumber-junit:4.7.2' testImplementation 'org.testcontainers:selenium' } From d9f0d73307c27de6883602ca13257bb914da03b5 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 30 Aug 2019 09:57:08 +0200 Subject: [PATCH 0251/4969] Add more labels to the Stale bot's config (#1810) --- .github/stale.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/stale.yml b/.github/stale.yml index a071ce18a5f..5f903fb0189 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -7,6 +7,8 @@ exemptLabels: - pinned - security - "resolution/acknowledged" + - "help wanted" + - "good first issue" # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable From b97254c3bfa208011d484ac3073674aa6dd11954 Mon Sep 17 00:00:00 2001 From: Guillaume Le Floch Date: Sun, 1 Sep 2019 22:52:08 +0200 Subject: [PATCH 0252/4969] RabbitMQ: fix typo in binding command (#1792) --- .../java/org/testcontainers/containers/RabbitMQContainer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index 4faaf3a5dea..8f0ef0ebcc1 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -215,8 +215,8 @@ public RabbitMQContainer withBinding(String source, String destination, Map Date: Sun, 1 Sep 2019 21:59:59 +0100 Subject: [PATCH 0253/4969] Bump commons-compress from 1.18 to 1.19 in /core (#1804) Bumps commons-compress from 1.18 to 1.19. Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index dee1acb4d69..51f61fcb976 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -60,7 +60,7 @@ dependencies { compile 'org.slf4j:slf4j-api:1.7.26' compile 'org.jetbrains:annotations:17.0.0' compile 'javax.annotation:javax.annotation-api:1.3.2' - compile 'org.apache.commons:commons-compress:1.18' + compile 'org.apache.commons:commons-compress:1.19' // Added for JDK9 compatibility since it's missing this package compile 'javax.xml.bind:jaxb-api:2.3.1' compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { From 3509316dda8b1cefbc5201ea3248dab611bc2f08 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2019 06:06:14 +0000 Subject: [PATCH 0254/4969] Bump rest-assured from 4.0.0 to 4.1.0 in /modules/vault (#1820) --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 3dd346ab559..a05c77f8158 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Vault" dependencies { compile project(':testcontainers') - testCompile 'io.rest-assured:rest-assured:4.0.0' + testCompile 'io.rest-assured:rest-assured:4.1.0' } From 2c6315270bd388138181d529719230e2261ea34e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2019 08:35:09 +0100 Subject: [PATCH 0255/4969] Bump slf4j-api from 1.7.26 to 1.7.28 in /core (#1805) Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.26 to 1.7.28. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.26...v_1.7.28) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 51f61fcb976..6b6ad2a6c28 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -57,7 +57,7 @@ project.tasks.check.dependsOn(jarFileTest) dependencies { compile 'junit:junit:4.12' - compile 'org.slf4j:slf4j-api:1.7.26' + compile 'org.slf4j:slf4j-api:1.7.28' compile 'org.jetbrains:annotations:17.0.0' compile 'javax.annotation:javax.annotation-api:1.3.2' compile 'org.apache.commons:commons-compress:1.19' From 7122b33750ebce829959622a58b5f760b6e8cfb2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2019 08:36:52 +0000 Subject: [PATCH 0256/4969] Bump aws-java-sdk-sqs from 1.11.622 to 1.11.623 in /modules/localstack (#1819) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 371891ce27a..15eac5ebb44 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.622' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.623' } From 88a4eaf6f0353af172b2b952fc8d02c2bbea026e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2019 11:27:06 +0100 Subject: [PATCH 0257/4969] Bump amqp-client from 5.7.2 to 5.7.3 in /core (#1818) Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.7.2 to 5.7.3. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.7.2...v5.7.3) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 6b6ad2a6c28..f08e7763b18 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -107,7 +107,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.1.0' - testCompile 'com.rabbitmq:amqp-client:5.7.2' + testCompile 'com.rabbitmq:amqp-client:5.7.3' testCompile 'org.mongodb:mongo-java-driver:3.11.0' testCompile ('org.mockito:mockito-core:3.0.0') { exclude(module: 'hamcrest-core') From c9b66eb3e610bfb76024000ae062bec889cdab34 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 3 Sep 2019 06:56:39 +0200 Subject: [PATCH 0258/4969] Use "copy" strategy in `withClasspathResourceMapping` where appropriate (#1814) --- .../containers/GenericContainer.java | 6 ++- .../junit/CopyFileToContainerTest.java | 49 ++++++++++++++++--- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 14ce129c9a5..baf79474aaa 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -967,7 +967,11 @@ public SELF withClasspathResourceMapping(final String resourcePath, final String public SELF withClasspathResourceMapping(final String resourcePath, final String containerPath, final BindMode mode, final SelinuxContext selinuxContext) { final MountableFile mountableFile = MountableFile.forClasspathResource(resourcePath); - this.addFileSystemBind(mountableFile.getResolvedPath(), containerPath, mode, selinuxContext); + if (mode == BindMode.READ_ONLY && selinuxContext == SelinuxContext.NONE) { + withCopyFileToContainer(mountableFile, containerPath); + } else { + addFileSystemBind(mountableFile.getResolvedPath(), containerPath, mode, selinuxContext); + } return self(); } diff --git a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java index 5164ea6c6e1..0641bc7d50d 100644 --- a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java @@ -1,10 +1,16 @@ package org.testcontainers.junit; -import org.junit.Assert; import org.junit.Test; +import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.SelinuxContext; import org.testcontainers.utility.MountableFile; + import java.io.IOException; +import java.util.Map; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class CopyFileToContainerTest { private static String containerPath = "/tmp/mappable-resource/"; @@ -12,14 +18,45 @@ public class CopyFileToContainerTest { @Test public void checkFileCopied() throws IOException, InterruptedException { - try( - GenericContainer container = new GenericContainer("alpine:latest") - .withCommand("sleep","3000") + try ( + GenericContainer container = new GenericContainer() + .withCommand("sleep", "3000") .withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), containerPath) ) { container.start(); - String filesList = container.execInContainer("ls","/tmp/mappable-resource").getStdout(); - Assert.assertTrue(filesList.contains(fileName)); + String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); + assertTrue("file list contains the file", filesList.contains(fileName)); + } + } + + @Test + public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { + try ( + GenericContainer container = new GenericContainer() + .withCommand("sleep", "3000") + .withClasspathResourceMapping("/mappable-resource/", containerPath, BindMode.READ_ONLY) + ) { + container.start(); + String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); + assertTrue("file list contains the file", filesList.contains(fileName)); } } + + @Test + public void shouldUseCopyOnlyWithReadOnlyClasspathResources() { + String resource = "/test_copy_to_container.txt"; + GenericContainer container = new GenericContainer<>() + .withClasspathResourceMapping(resource, "/readOnly", BindMode.READ_ONLY) + .withClasspathResourceMapping(resource, "/readOnlyNoSelinux", BindMode.READ_ONLY) + + .withClasspathResourceMapping(resource, "/readOnlyShared", BindMode.READ_ONLY, SelinuxContext.SHARED) + .withClasspathResourceMapping(resource, "/readWrite", BindMode.READ_WRITE); + + Map copyMap = container.getCopyToFileContainerPathMap(); + assertTrue("uses copy for read-only", copyMap.containsValue("/readOnly")); + assertTrue("uses copy for read-only and no Selinux", copyMap.containsValue("/readOnlyNoSelinux")); + + assertFalse("uses mount for read-only with Selinux", copyMap.containsValue("/readOnlyShared")); + assertFalse("uses mount for read-write", copyMap.containsValue("/readWrite")); + } } From 0ce63054628fa1ed1a1a3fa5f58d3931f6e23df3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2019 05:55:49 +0000 Subject: [PATCH 0259/4969] Bump neo4j from 3.5.8 to 3.5.9 in /modules/neo4j (#1823) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index c7227a2d9ac..4889196ccef 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -25,7 +25,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.8" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.9" compile project(":testcontainers") From 33beb8d4bd97dd1f106d77124ddd2a1eb95ecf97 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2019 05:55:25 +0000 Subject: [PATCH 0260/4969] Bump aws-java-sdk-sqs from 1.11.623 to 1.11.624 in /modules/localstack (#1826) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 15eac5ebb44..ce2982204b7 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.623' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.624' } From 0d8b42b47fcfd5f7cf41c9c7324dca32f73f1d8d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2019 06:44:24 +0000 Subject: [PATCH 0261/4969] Bump pulsar-client from 2.4.0 to 2.4.1 in /modules/pulsar (#1825) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 34cde96a33e..05d9a711420 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.4.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.4.1' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.13.2' } From acd8bdc782dfd2e8456427bb0677e94d0d5a0c8b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2019 05:56:26 +0000 Subject: [PATCH 0262/4969] Bump aws-java-sdk-sqs from 1.11.624 to 1.11.625 in /modules/localstack (#1829) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ce2982204b7..9bc7d4fe545 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.624' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.625' } From 1e6ac9b9510f2227c6e54694ae048e47de469d12 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Sep 2019 08:47:16 +0100 Subject: [PATCH 0263/4969] Fix error in Javadocs and run javadoc generation during 'check' (#1813) * Fix Javadoc error * Ensure that Javadoc generation is tested for all `check` builds * Generate Javadocs from delomboked sources --- build.gradle | 8 ++++++++ .../org/testcontainers/containers/RabbitMQContainer.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index b3e96b265b5..c1c031f2757 100644 --- a/build.gradle +++ b/build.gradle @@ -67,6 +67,14 @@ subprojects { } } + // Ensure that Javadoc generation is always tested + check.dependsOn(javadoc) + + javadoc { + dependsOn delombok + source = delombok.outputs + } + shadowJar { configurations = [] classifier = null diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index 8f0ef0ebcc1..ea25bf629e6 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -359,9 +359,9 @@ public RabbitMQContainer withRabbitMQConfig(MountableFile rabbitMQConf) { /** * Overwrites the default RabbitMQ configuration file with the supplied one. * - * This function doesn't work with RabbitMQ < 3.7. + * This function doesn't work with RabbitMQ < 3.7. * - * This function and the Sysctl format is recommended for RabbitMQ >= 3.7 + * This function and the Sysctl format is recommended for RabbitMQ >= 3.7 * * @param rabbitMQConf The rabbitmq.config file to use (in sysctl format, don't forget empty line in the end of file) * @return This container. From 1161b1b843928706dcb4223d0ff87497249306c7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2019 05:58:27 +0000 Subject: [PATCH 0264/4969] Bump aws-java-sdk-sqs from 1.11.625 to 1.11.626 in /modules/localstack (#1830) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9bc7d4fe545..4bc50a6a1f1 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.625' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.626' } From 386c545b01751447890139aaf6475e9fb73e0529 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2019 07:00:32 +0000 Subject: [PATCH 0265/4969] Bump org.springframework.boot in /examples (#1831) --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 22198984e33..cf3b6567982 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.7.RELEASE' + id 'org.springframework.boot' version '2.1.8.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 7af6b9d26da..46e587bc39a 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.7.RELEASE' + id 'org.springframework.boot' version '2.1.8.RELEASE' } apply plugin: 'io.spring.dependency-management' From 4fbef4b66b2af7658792402db4523c4eba398fd9 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 7 Sep 2019 19:36:24 +0100 Subject: [PATCH 0266/4969] Fix javadoc error (#1832) * Update Lombok for fix to [JDK12 delombok issue](https://github.com/rzwitserloot/lombok/issues/2082) Also upgrade Gradle Lombok plugin --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c1c031f2757..ecdf48cd3f7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'com.gradle.build-scan' version '1.16' - id 'io.franzbecker.gradle-lombok' version '1.14' + id 'io.franzbecker.gradle-lombok' version '3.1.0' id 'nebula.provided-base' version '3.0.3' id 'com.github.johnrengelman.shadow' version '2.0.2' id "com.jfrog.bintray" version "1.8.4" apply false @@ -21,7 +21,7 @@ subprojects { compileTestJava.options.encoding = 'UTF-8' lombok { - version = '1.18.6' + version = '1.18.8' } task delombok(type: io.franzbecker.gradle.lombok.task.DelombokTask) { From b1cb06d7524ce44c56c7050f06e4aafb222c17fd Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 7 Sep 2019 19:36:50 +0100 Subject: [PATCH 0267/4969] =?UTF-8?q?Add=20test=20to=20demonstrate=20fix?= =?UTF-8?q?=20for=20#1452=20(loss=20of=20whitespace=20in=20sp=E2=80=A6=20(?= =?UTF-8?q?#1702)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (probably fixed by #1627) --- .../testcontainers/ext/ScriptSplittingTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java index 0836592b91e..202a3b995db 100644 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java @@ -281,6 +281,21 @@ public void testUnclosedBlockComment() { } } + @Test + public void testIssue1452Case() { + String script = "create table test (text VARCHAR(255));\n" + + "\n" + + "/* some comment */\n" + + "insert into `test` (`text`) values ('a b');"; + + List expected = asList( + "create table test (text VARCHAR(255))", + "insert into `test` (`text`) values ('a b')" + ); + + splitAndCompare(script, expected); + } + private void splitAndCompare(String script, List expected) { final List statements = doSplit(script); Assertions.assertThat(statements).isEqualTo(expected); From b35f2ca12ce1a30c4dd932b9f5f6299ac8917c50 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 8 Sep 2019 09:00:20 +0100 Subject: [PATCH 0268/4969] Update .travis.yml to ensure that tag builds are performed --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f07d50123e2..d7d5f94270d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -if: branch = master +if: branch = master OR tag is present language: java jdk: From 271cb1a37356f322bd4f34b73e91d29d02e71283 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 8 Sep 2019 13:29:50 +0100 Subject: [PATCH 0269/4969] Update latest version in docs --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index f0d953ecd8a..39d2c8d8164 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,4 +82,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.12.0 + latest_version: 1.12.1 From 5a2257454d46adc9404886f48fb4bac45c708457 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 8 Sep 2019 17:33:55 +0200 Subject: [PATCH 0270/4969] Bump testng from 6.14.3 to 7.0.0 in /examples (#1756) Bumps testng from 6.14.3 to 7.0.0. Signed-off-by: dependabot-preview[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 777ca2d9511..e68ccfea24f 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' - testImplementation 'org.testng:testng:6.14.3' + testImplementation 'org.testng:testng:7.0.0' } test { From 097d1572851334dea84c54c053d6065c7f8f1db4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2019 06:07:07 +0000 Subject: [PATCH 0271/4969] Bump rest-assured from 4.1.0 to 4.1.1 in /modules/vault (#1839) --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index a05c77f8158..41807d2573b 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Vault" dependencies { compile project(':testcontainers') - testCompile 'io.rest-assured:rest-assured:4.1.0' + testCompile 'io.rest-assured:rest-assured:4.1.1' } From fc5f971711ef74f14434c0115664d26bd0299c1c Mon Sep 17 00:00:00 2001 From: Frederik Hahne Date: Mon, 9 Sep 2019 08:36:02 +0200 Subject: [PATCH 0272/4969] add jhipster as user (#1838) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 657c2446a55..f62cba3af45 100644 --- a/docs/index.md +++ b/docs/index.md @@ -74,6 +74,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Zalando SE](https://corporate.zalando.com/en) - Testing core business services * [Europace AG](https://tech.europace.de/) - Integration testing for databases and micro services * [Micronaut Data](https://github.com/micronaut-projects/micronaut-data/) - Testing of Micronaut Data JDBC, a database access toolkit +* [JHipster](https://www.jhipster.tech/) - Couchbase and Cassandra integration testing ## License From 21e397be4e9e3a7c36863c352785e86a6ea0e2e2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2019 05:59:32 +0000 Subject: [PATCH 0273/4969] Bump httpclient from 4.5.9 to 4.5.10 in /modules/spock (#1850) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index f9353314c1b..69058b53a92 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' - testCompile 'org.apache.httpcomponents:httpclient:4.5.9' + testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testRuntime 'org.postgresql:postgresql:42.2.6' testRuntime 'mysql:mysql-connector-java:8.0.17' From 896e30634df1dc1b27ec8e80c8612f2f87c3b96c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2019 06:41:00 +0000 Subject: [PATCH 0274/4969] Bump junit-jupiter-api from 5.5.1 to 5.5.2 in /modules/junit-jupiter (#1842) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 2a0937a85d7..3aa2abd08ba 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.5.1' + compile 'org.junit.jupiter:junit-jupiter-api:5.5.2' testCompile project(':mysql') testCompile project(':postgresql') From d1a41d44a9a90438775c39d4d937ba86467a3897 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2019 07:32:17 +0000 Subject: [PATCH 0275/4969] Bump httpclient from 4.5.9 to 4.5.10 in /modules/junit-jupiter (#1851) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 3aa2abd08ba..6997c270052 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,7 +8,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'redis.clients:jedis:3.1.0' - testCompile 'org.apache.httpcomponents:httpclient:4.5.9' + testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testCompile ('org.mockito:mockito-core:3.0.0') { exclude(module: 'hamcrest-core') } From 09d70c4b9d942c1c71b8bc01d406245966ed8649 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2019 08:11:30 +0000 Subject: [PATCH 0276/4969] Bump aws-java-sdk-sqs from 1.11.626 to 1.11.628 in /modules/localstack (#1852) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 4bc50a6a1f1..3e065497bf2 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.626' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.628' } From aa4a99f795fb21cb9b790dc088be95fdcca3ae96 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2019 08:50:54 +0000 Subject: [PATCH 0277/4969] Bump junit-jupiter-engine from 5.5.1 to 5.5.2 in /modules/junit-jupiter (#1840) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 6997c270052..74cb75cec0c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.6' testRuntime 'mysql:mysql-connector-java:8.0.17' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.1' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.2' } test { From c370fe19546671bb349222b95213315353d6ee6c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 05:57:00 +0000 Subject: [PATCH 0278/4969] Bump postgresql from 42.2.6 to 42.2.7 in /modules/junit-jupiter (#1856) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 74cb75cec0c..83559949614 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } - testRuntime 'org.postgresql:postgresql:42.2.6' + testRuntime 'org.postgresql:postgresql:42.2.7' testRuntime 'mysql:mysql-connector-java:8.0.17' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.2' } From 33ace195c63bc52baec050f1cf3a31de1f215d10 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 06:34:54 +0000 Subject: [PATCH 0279/4969] Bump aws-java-sdk-sqs from 1.11.628 to 1.11.629 in /modules/localstack (#1858) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3e065497bf2..0b4faf4aabe 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.628' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.629' } From 185498dfa209b05ba02c01227dfd66d5970d8658 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 07:40:29 +0000 Subject: [PATCH 0280/4969] Bump postgresql from 42.2.6 to 42.2.7 in /modules/spock (#1860) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 69058b53a92..a51b7edaf32 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -13,6 +13,6 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' - testRuntime 'org.postgresql:postgresql:42.2.6' + testRuntime 'org.postgresql:postgresql:42.2.7' testRuntime 'mysql:mysql-connector-java:8.0.17' } From 4bb2cc231f23b62a67471e5c8408a30aa89325fd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 08:56:07 +0000 Subject: [PATCH 0281/4969] Bump postgresql from 42.2.6 to 42.2.7 in /examples (#1862) --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 6bf099030ec..bc531b1b2c5 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.28' implementation 'com.squareup.okhttp3:okhttp:3.14.2' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.6' + testImplementation 'org.postgresql:postgresql:42.2.7' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From 5705b0db5a61ad4150a60880036827830f8bda8f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 10:03:53 +0000 Subject: [PATCH 0282/4969] Bump okhttp from 3.14.2 to 3.14.3 in /examples (#1861) --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index bc531b1b2c5..b0247f837cf 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.28' - implementation 'com.squareup.okhttp3:okhttp:3.14.2' + implementation 'com.squareup.okhttp3:okhttp:3.14.3' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.7' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From ea54415727bf819f01fff3ce539b0d21771f4be9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 10:55:43 +0000 Subject: [PATCH 0283/4969] Bump postgresql from 42.2.6 to 42.2.7 in /modules/postgresql (#1857) --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 1a5980dee55..df75d333ca1 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { compile project(':jdbc') - testCompile 'org.postgresql:postgresql:42.2.6' + testCompile 'org.postgresql:postgresql:42.2.7' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' } From ee51a486f643feba25932f7158376de46af97f24 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2019 05:57:35 +0000 Subject: [PATCH 0284/4969] Bump aws-java-sdk-sqs from 1.11.629 to 1.11.630 in /modules/localstack (#1866) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 0b4faf4aabe..d19da1299da 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.629' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.630' } From 520f86cf767b5f4ebd3aac7e510aa61a85aa30d7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2019 07:01:45 +0000 Subject: [PATCH 0285/4969] Bump lombok from 1.18.8 to 1.18.10 in /examples (#1867) --- examples/disque-job-queue/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 78a38d2ba08..bb4aa6edaaa 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.projectlombok:lombok:1.18.8' + compileOnly 'org.projectlombok:lombok:1.18.10' implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 46e587bc39a..487c60e51dd 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -9,7 +9,7 @@ repositories { } dependencies { - compileOnly 'org.projectlombok:lombok:1.18.8' + compileOnly 'org.projectlombok:lombok:1.18.10' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' From 5ecf798b5dbf8d95f48be1b5633f53f8db18676f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2019 05:59:07 +0000 Subject: [PATCH 0286/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#1870) --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 6ae9ab00dab..e8431190e8b 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.3.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.3.2" testCompile "org.elasticsearch.client:transport:6.7.1" } From 34ba4f763cfb4f6a70fcd4de6ed191e9d9fac07d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2019 06:37:45 +0000 Subject: [PATCH 0287/4969] Bump aws-java-sdk-sqs from 1.11.630 to 1.11.631 in /modules/localstack (#1869) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d19da1299da..f8ff744ed47 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.630' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.631' } From e5ab9ecfa047efdfd1db5805ea4e488956c1154c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2019 05:59:14 +0000 Subject: [PATCH 0288/4969] Bump postgresql from 42.2.7 to 42.2.8 in /modules/junit-jupiter (#1877) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 83559949614..41e011c07b9 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } - testRuntime 'org.postgresql:postgresql:42.2.7' + testRuntime 'org.postgresql:postgresql:42.2.8' testRuntime 'mysql:mysql-connector-java:8.0.17' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.2' } From 901724719be11d52e3777a5e21eddf5d7d993429 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2019 06:36:59 +0000 Subject: [PATCH 0289/4969] Bump mariadb-java-client from 2.4.3 to 2.4.4 in /modules/mariadb (#1875) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index eb778c6c827..692a1636e15 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.3' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.4' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.24' From 2b3a49f7c38b729ea594551d20455d8d047f58a5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2019 07:16:44 +0000 Subject: [PATCH 0290/4969] Bump postgresql from 42.2.7 to 42.2.8 in /examples (#1879) --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index b0247f837cf..3a721e4702b 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.28' implementation 'com.squareup.okhttp3:okhttp:3.14.3' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.7' + testImplementation 'org.postgresql:postgresql:42.2.8' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From d62a9a10377d9a7a81525657b774e7208bd40b5a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2019 08:21:06 +0000 Subject: [PATCH 0291/4969] Bump postgresql from 42.2.7 to 42.2.8 in /modules/spock (#1878) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index a51b7edaf32..df61a9fefa2 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -13,6 +13,6 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.3.1' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' - testRuntime 'org.postgresql:postgresql:42.2.7' + testRuntime 'org.postgresql:postgresql:42.2.8' testRuntime 'mysql:mysql-connector-java:8.0.17' } From 3ad6adefefe025e267ec5ec15318f87ebe5d5bad Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2019 09:23:29 +0000 Subject: [PATCH 0292/4969] Bump postgresql from 42.2.7 to 42.2.8 in /modules/postgresql (#1876) --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index df75d333ca1..c070ce9ba13 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { compile project(':jdbc') - testCompile 'org.postgresql:postgresql:42.2.7' + testCompile 'org.postgresql:postgresql:42.2.8' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' } From 158e42f3d4d493fd7ab16c268e88fc6002e12c28 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2019 06:00:45 +0000 Subject: [PATCH 0293/4969] Bump HikariCP from 3.3.1 to 3.4.0 in /modules/spock (#1882) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index df61a9fefa2..285618ab116 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.3.1' + testCompile 'com.zaxxer:HikariCP:3.4.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testRuntime 'org.postgresql:postgresql:42.2.8' From 7bd756d2a279eabecf55e54ca0454a9b975ff184 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2019 07:07:43 +0000 Subject: [PATCH 0294/4969] Bump aws-java-sdk-sqs from 1.11.631 to 1.11.632 in /modules/localstack (#1884) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index f8ff744ed47..b96f4ad0048 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.631' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.632' } From 8ce740d2b7b73e56e5855c8ff6208c9c10687fe1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2019 08:12:14 +0000 Subject: [PATCH 0295/4969] Bump HikariCP from 3.3.1 to 3.4.0 in /modules/junit-jupiter (#1883) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 41e011c07b9..291bc27152c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.3.1' + testCompile 'com.zaxxer:HikariCP:3.4.0' testCompile 'redis.clients:jedis:3.1.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testCompile ('org.mockito:mockito-core:3.0.0') { From b84b1b04d27ffd379452740d655381040622c88c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2019 05:57:56 +0000 Subject: [PATCH 0296/4969] Bump aws-java-sdk-sqs from 1.11.632 to 1.11.633 in /modules/localstack (#1885) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index b96f4ad0048..c5f09772048 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.632' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.633' } From 0fcaca7cd3ebc8b3e168617257c26b4e1c842cb7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2019 05:58:22 +0000 Subject: [PATCH 0297/4969] Bump HikariCP from 3.4.0 to 3.4.1 in /modules/junit-jupiter (#1889) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 291bc27152c..75367d57720 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.0' + testCompile 'com.zaxxer:HikariCP:3.4.1' testCompile 'redis.clients:jedis:3.1.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testCompile ('org.mockito:mockito-core:3.0.0') { From 78e78fcd08b873e2ffbd0b9fa46bba364335c298 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 19 Sep 2019 21:46:54 +0100 Subject: [PATCH 0298/4969] Create _headers for docs, to allow cross-origin search --- docs/_headers | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/_headers diff --git a/docs/_headers b/docs/_headers new file mode 100644 index 00000000000..e59f34a29e2 --- /dev/null +++ b/docs/_headers @@ -0,0 +1,2 @@ +/search/search_index.json + Access-Control-Allow-Origin: * From 826b9583cf26fc1ef06fc6003cda554b463b1374 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2019 05:57:39 +0000 Subject: [PATCH 0299/4969] Bump tomcat-jdbc from 9.0.24 to 9.0.26 in /modules/mariadb (#1895) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 692a1636e15..9393f6c65c7 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.4' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.24' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.26' testCompile 'org.vibur:vibur-dbcp:22.2' } From 7c07bf989f7f2b3d18c0632b1be63f152807d42a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2019 06:39:51 +0000 Subject: [PATCH 0300/4969] Bump HikariCP from 3.4.0 to 3.4.1 in /modules/spock (#1888) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 285618ab116..552fd3883cd 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.0' + testCompile 'com.zaxxer:HikariCP:3.4.1' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testRuntime 'org.postgresql:postgresql:42.2.8' From 1b9ab1a0975f8b88360e6177f913dccfd6e66389 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2019 07:45:10 +0000 Subject: [PATCH 0301/4969] Bump tomcat-jdbc from 9.0.24 to 9.0.26 in /modules/mysql (#1894) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index d5a366825b9..dbb6747e80f 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.17' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.24' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.26' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From 2e0cdb0381c1d348c3edae9ca120a2ac2563806a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2019 08:47:31 +0000 Subject: [PATCH 0302/4969] Bump aws-java-sdk-sqs from 1.11.633 to 1.11.635 in /modules/localstack (#1896) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c5f09772048..662e754976e 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.633' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.635' } From 8e871d03c0082474b3a7e304362e97aca4de0740 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2019 06:12:17 +0000 Subject: [PATCH 0303/4969] Bump aws-java-sdk-sqs from 1.11.635 to 1.11.636 in /modules/localstack (#1901) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 662e754976e..eacbc7bb5ae 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,5 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.635' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' } From b063082db75918b81158b26a70b34f09c9591182 Mon Sep 17 00:00:00 2001 From: Kai Winter Date: Mon, 23 Sep 2019 22:18:23 +0200 Subject: [PATCH 0304/4969] Obtain official Oracle JDBC driver (#73) (#1899) Also removed two unnecessary dependencies. --- modules/oracle-xe/build.gradle | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index 6b4ab1af763..de1160fa84d 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -1,17 +1,9 @@ description = "Testcontainers :: JDBC :: Oracle XE" -repositories { - maven { - url "https://maven.atlassian.com/3rdparty/" - } -} - dependencies { compile project(':jdbc') - testCompile 'com.oracle:ojdbc6:12.1.0.1-atlassian-hosted' + testCompile 'com.oracle.ojdbc:ojdbc8:19.3.0.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.8' testCompile 'commons-dbutils:commons-dbutils:1.6' - testCompile 'org.apache.tomcat:tomcat-jdbc:8.5.4' - testCompile 'org.vibur:vibur-dbcp:9.0' } From 41a009dde90941c587920f3fec685660e948649b Mon Sep 17 00:00:00 2001 From: aosagie Date: Mon, 23 Sep 2019 16:24:19 -0400 Subject: [PATCH 0305/4969] Make LocalStack image configurable (#1873) --- .../testcontainers/utility/TestcontainersConfiguration.java | 4 ++++ docs/features/configuration.md | 3 +++ .../containers/localstack/LocalStackContainer.java | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index b7ef772fcf5..21f9bdfb333 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -81,6 +81,10 @@ public String getPulsarImage() { return (String) properties.getOrDefault("pulsar.container.image", "apachepulsar/pulsar"); } + public String getLocalStackImage() { + return (String) properties.getOrDefault("localstack.container.image", "localstack/localstack"); + } + public boolean isDisableChecks() { return Boolean.parseBoolean((String) environmentProperties.getOrDefault("checks.disable", "false")); } diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 2ef7e4997a3..61500cb9cb5 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -42,6 +42,9 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **kafka.container.image = confluentinc/cp-kafka** > Used by KafkaContainer +> **localstack.container.image = localstack/localstack** +> Used by LocalStack + ## Customizing Ryuk resource reaper > **ryuk.container.image = quay.io/testcontainers/ryuk:0.2.3** diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 1bf0e18627d..d16babb51e8 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -10,6 +10,7 @@ import org.rnorth.ducttape.Preconditions; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.TestcontainersConfiguration; import java.net.InetAddress; import java.net.UnknownHostException; @@ -37,7 +38,7 @@ public LocalStackContainer() { } public LocalStackContainer(String version) { - super("localstack/localstack:" + version); + super(TestcontainersConfiguration.getInstance().getLocalStackImage() + ":" + version); withFileSystemBind("//var/run/docker.sock", "/var/run/docker.sock"); waitingFor(Wait.forLogMessage(".*Ready\\.\n", 1)); From b6a5248365acb240cd6f6c7d3c1ae38c6c5b3ed7 Mon Sep 17 00:00:00 2001 From: Frederik Hahne Date: Mon, 23 Sep 2019 22:26:43 +0200 Subject: [PATCH 0306/4969] add wescale as happy user (#1887) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index f62cba3af45..ba99eb6e555 100644 --- a/docs/index.md +++ b/docs/index.md @@ -75,6 +75,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Europace AG](https://tech.europace.de/) - Integration testing for databases and micro services * [Micronaut Data](https://github.com/micronaut-projects/micronaut-data/) - Testing of Micronaut Data JDBC, a database access toolkit * [JHipster](https://www.jhipster.tech/) - Couchbase and Cassandra integration testing +* [wescale](https://www.wescale.com) - Integration testing against HTTP service mocks and various data stores ## License From ec0ab6f1e0c2a826ee21bb06a88508081484892d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2019 06:04:35 +0000 Subject: [PATCH 0307/4969] Bump commons-dbutils from 1.6 to 1.7 in /modules/oracle-xe (#1905) --- modules/oracle-xe/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index de1160fa84d..1ab61e997af 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -5,5 +5,5 @@ dependencies { testCompile 'com.oracle.ojdbc:ojdbc8:19.3.0.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.8' - testCompile 'commons-dbutils:commons-dbutils:1.6' + testCompile 'commons-dbutils:commons-dbutils:1.7' } From d3ba8428d7494a522b49792bc04d528fb70fea4f Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 26 Sep 2019 08:06:31 +0100 Subject: [PATCH 0308/4969] =?UTF-8?q?Reduce=20logs=20in=20EnvironmentAndSy?= =?UTF-8?q?stemPropertyClientProviderStrate=E2=80=A6=20(#1913)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1912 --- ...dSystemPropertyClientProviderStrategy.java | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java index 195a07a4024..4b02eded72b 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java @@ -1,7 +1,6 @@ package org.testcontainers.dockerclient; import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.DockerClientConfig; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.SystemUtils; @@ -50,21 +49,7 @@ public void test() throws InvalidConfigurationException { @Override public String getDescription() { - return "Environment variables, system properties and defaults. Resolved: \n" + stringRepresentation(config); - } - - private String stringRepresentation(DockerClientConfig config) { - - if (config == null) { - return ""; - } - - return " dockerHost=" + config.getDockerHost() + "\n" + - " apiVersion='" + config.getApiVersion() + "'\n" + - " registryUrl='" + config.getRegistryUrl() + "'\n" + - " registryUsername='" + config.getRegistryUsername() + "'\n" + - " registryPassword='" + config.getRegistryPassword() + "'\n" + - " registryEmail='" + config.getRegistryEmail() + "'\n" + - " dockerConfig='" + config.toString() + "'\n"; + return "Environment variables, system properties and defaults. Resolved dockerHost=" + + (config != null ? config.getDockerHost() : ""); } } From e717e8375c13fe416fa5860fe06a0caef48d8590 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2019 05:58:17 +0000 Subject: [PATCH 0309/4969] Bump lettuce-core from 5.1.8.RELEASE to 5.2.0.RELEASE in /examples (#1919) --- examples/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spock/build.gradle b/examples/spock/build.gradle index 147e1eaf079..486107f9b21 100644 --- a/examples/spock/build.gradle +++ b/examples/spock/build.gradle @@ -8,7 +8,7 @@ repositories { } dependencies { - compile "io.lettuce:lettuce-core:5.1.8.RELEASE" + compile "io.lettuce:lettuce-core:5.2.0.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' testImplementation 'org.testcontainers:spock' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From a90b120bdd8e4133e10aea862e30f02a22dfca40 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2019 06:25:16 +0000 Subject: [PATCH 0310/4969] Bump okhttp from 3.14.3 to 3.14.4 in /examples (#1925) --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 3a721e4702b..1680aa3b963 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.28' - implementation 'com.squareup.okhttp3:okhttp:3.14.3' + implementation 'com.squareup.okhttp3:okhttp:3.14.4' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.8' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 9ab6909eda47ad65f6155737b1b869d88ad15850 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 1 Oct 2019 21:57:58 +0200 Subject: [PATCH 0311/4969] =?UTF-8?q?Remove=20`hostname`=20and=20`port`=20?= =?UTF-8?q?from=20JDBC=20examples=20to=20avoid=20confus=E2=80=A6=20(#1786)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove `hostname` and `port` from JDBC examples to avoid confusion * restore original URL * Explain the host-less URIs --- docs/modules/databases/index.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index 22292875307..b0e5335b7e8 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -47,29 +47,33 @@ _N.B:_ * _TC needs to be on your application's classpath at runtime for this to work_ * _For Spring Boot you need to specify the driver manually `spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver`_ -**Original URL**: `jdbc:mysql:5.7.22://somehostname:someport/databasename` +**Original URL**: `jdbc:mysql:5.7.22://localhost:3306/databasename` -Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value. +Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value. + +!!! note + We will use `///` (host-less URIs) from now on to emphasis the unimportance of the `host:port` pair. + From Testcontainers' perspective, `jdbc:mysql:5.7.22://localhost:3306/databasename` and `jdbc:mysql:5.7.22:///databasename` is the same URI. ### JDBC URL examples #### Using Testcontainers with a fixed version -`jdbc:tc:mysql:5.6.23://somehostname:someport/databasename` +`jdbc:tc:mysql:5.6.23:///databasename` #### Using PostgreSQL -`jdbc:tc:postgresql:9.6.8://hostname/databasename` +`jdbc:tc:postgresql:9.6.8:///databasename` ### Using PostGIS -`jdbc:tc:postgis:9.6://hostname/databasename` +`jdbc:tc:postgis:9.6:///databasename` ## Using a classpath init script Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: -`jdbc:tc:mysql:5.7.22://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql` +`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=somepath/init_mysql.sql` This is useful if you have a fixed script for setting up database schema, etc. @@ -77,13 +81,13 @@ This is useful if you have a fixed script for setting up database schema, etc. If the init script path is prefixed `file:`, it will be loaded from a file (relative to the working directory, which will usually be the project root). -`jdbc:tc:mysql:5.7.22://hostname/databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql` +`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql` #### Using an init function Instead of running a fixed script for DB setup, it may be useful to call a Java function that you define. This is intended to allow you to trigger database schema migration tools. To do this, add TC_INITFUNCTION to the URL as follows, passing a full path to the class name and method: - `jdbc:tc:mysql:5.7.22://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction` + `jdbc:tc:mysql:5.7.22:///databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction` The init function must be a public static method which takes a `java.sql.Connection` as its only parameter, e.g. ```java @@ -98,7 +102,7 @@ public class JDBCDriverTest { By default database container is being stopped as soon as last connection is closed. There are cases when you might need to start container and keep it running till you stop it explicitly or JVM is shutdown. To do this, add `TC_DAEMON` parameter to the URL as follows: - `jdbc:tc:mysql:5.7.22://hostname/databasename?TC_DAEMON=true` + `jdbc:tc:mysql:5.7.22:///databasename?TC_DAEMON=true` With this parameter database container will keep running even when there're no open connections. @@ -109,7 +113,7 @@ Container can have `tmpfs` mounts for storing data in host memory. This is usefu To pass this option to the container, add `TC_TMPFS` paramater to the URL as follows: - `jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw` + `jdbc:tc:postgresql:9.6.8:///databasename?TC_TMPFS=/testtmpfs:rw` If you need more than one option, seperate them by comma (e.g. `TC_TMPFS=key:value,key1:value1&other_parameters=foo`). From 9f8a73e18bcf3e648a6c1af4b126051cdd60b837 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 1 Oct 2019 20:58:30 +0100 Subject: [PATCH 0312/4969] Update to latest version in docs --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 39d2c8d8164..9d857ad21a9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,4 +82,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.12.1 + latest_version: 1.12.2 From dbb8472a334bdd76009db95632989a18c78794c0 Mon Sep 17 00:00:00 2001 From: Mitchell Just Date: Wed, 2 Oct 2019 06:25:37 +1000 Subject: [PATCH 0313/4969] Add support for DockerClient event streaming (#1886) Probably fixes #1473 Co-authored-by: Sergei Egorov --- .../okhttp/OkHttpInvocationBuilder.java | 24 ++++++- .../transport/okhttp/UnixSocketFactory.java | 8 +++ .../dockerclient/EventStreamTest.java | 64 +++++++++++++++++++ 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java index a03914d5f07..c7f679eb22b 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java @@ -42,6 +42,8 @@ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) class OkHttpInvocationBuilder implements InvocationBuilder { + static final ThreadLocal CLOSING = ThreadLocal.withInitial(() -> false); + ObjectMapper objectMapper; OkHttpClient okHttpClient; @@ -101,8 +103,15 @@ public T get(TypeReference typeReference) { @Override public void get(TypeReference typeReference, ResultCallback resultCallback) { - // FIXME - throw new IllegalStateException("doesn't seem to be used in docker-java"); + Request request = requestBuilder + .get() + .build(); + + executeAndStream( + request, + resultCallback, + new JsonSink<>(objectMapper, typeReference, resultCallback) + ); } @Override @@ -292,7 +301,16 @@ protected void executeAndStream(OkHttpClient okHttpClient, Request request, Response response = execute(okHttpClient, request.newBuilder().tag("streaming").build()); BufferedSource source = response.body().source(); ) { - callback.onStart(response); + callback.onStart(() -> { + boolean previous = CLOSING.get(); + CLOSING.set(true); + try { + response.close(); + } finally { + CLOSING.set(previous); + } + }); + sourceConsumer.accept(source); callback.onComplete(); } catch (Exception e) { diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java index a9eb9f30086..2fbdb936447 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java @@ -37,6 +37,14 @@ public InputStream getInputStream() { public void close() throws IOException { shutdownInput(); } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (OkHttpInvocationBuilder.CLOSING.get()) { + return 0; + } + return super.read(b, off, len); + } }; } diff --git a/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java b/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java new file mode 100644 index 00000000000..4d7a4e21133 --- /dev/null +++ b/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java @@ -0,0 +1,64 @@ +package org.testcontainers.dockerclient; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Event; +import com.github.dockerjava.core.command.EventsResultCallback; +import org.jetbrains.annotations.NotNull; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.Timeout; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; + +import java.io.IOException; +import java.time.Instant; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Test that event streaming from the {@link DockerClient} works correctly + */ +public class EventStreamTest { + + @Rule + public Timeout timeout = new Timeout(10, TimeUnit.SECONDS); + + /** + * Test that docker events can be streamed from the client. + */ + @Test + public void test() throws IOException, InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + + try ( + GenericContainer container = new GenericContainer<>() + .withCommand("true") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + String createdAt = container.getContainerInfo().getCreated(); + + // Request all events between startTime and endTime for the container + try ( + EventsResultCallback response = DockerClientFactory.instance().client().eventsCmd() + .withContainerFilter(container.getContainerId()) + .withEventFilter("create") + .withSince(Instant.parse(createdAt).getEpochSecond() + "") + .exec(new EventsResultCallback() { + @Override + public void onNext(@NotNull Event event) { + // Check that a create event for the container is received + if (event.getId().equals(container.getContainerId()) && event.getStatus().equals("create")) { + latch.countDown(); + } + } + }) + ) { + response.awaitStarted(5, TimeUnit.SECONDS); + latch.await(5, TimeUnit.SECONDS); + } + } + } + +} From 232e9b03f199299f8e01cc60e8fa3e5ca0c549ed Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2019 07:03:58 +0000 Subject: [PATCH 0314/4969] Bump mockito-core from 3.0.0 to 3.1.0 in /modules/junit-jupiter (#1931) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 75367d57720..e286af1e149 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.1' testCompile 'redis.clients:jedis:3.1.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' - testCompile ('org.mockito:mockito-core:3.0.0') { + testCompile ('org.mockito:mockito-core:3.1.0') { exclude(module: 'hamcrest-core') } From ca8a35dc5ccf31142919c5fb5635c664d4f89302 Mon Sep 17 00:00:00 2001 From: MariuszCwikla <47976407+MariuszCwikla@users.noreply.github.com> Date: Thu, 3 Oct 2019 08:16:06 +0200 Subject: [PATCH 0315/4969] ConnectionWrapper#rollback(Savepoint) delegates to wrong method #1909 (#1937) * ConnectionWrapper#rollback(Savepoint) delegates to wrong method #1909 * fix whitespaces and use @AllArgsConstructor * Update ConnectionDelegate.java --- .../jdbc/ConnectionDelegate.java | 13 + .../jdbc/ConnectionWrapper.java | 290 +----------------- 2 files changed, 23 insertions(+), 280 deletions(-) create mode 100644 modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java new file mode 100644 index 00000000000..e7f59b2df4f --- /dev/null +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java @@ -0,0 +1,13 @@ +package org.testcontainers.jdbc; + +import lombok.RequiredArgsConstructor; +import lombok.Value; +import lombok.experimental.Delegate; + +import java.sql.Connection; + +@RequiredArgsConstructor +class ConnectionDelegate implements Connection { + @Delegate + private final Connection delegate; +} diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java index 5a783c96947..3e1f67c5b86 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java @@ -1,294 +1,24 @@ package org.testcontainers.jdbc; -import java.sql.*; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.Executor; +import java.sql.Connection; +import java.sql.SQLException; -/** - * @author richardnorth - */ -class ConnectionWrapper implements Connection { - private final Connection delegate; - private final Runnable closeCallback; - - public ConnectionWrapper(Connection delegate, Runnable closeCallback) { - this.delegate = delegate; - this.closeCallback = closeCallback; - } - - @Override - public Statement createStatement() throws SQLException { - return delegate.createStatement(); - } - - @Override - public PreparedStatement prepareStatement(String sql) throws SQLException { - return delegate.prepareStatement(sql); - } - - @Override - public CallableStatement prepareCall(String sql) throws SQLException { - return delegate.prepareCall(sql); - } - - @Override - public String nativeSQL(String sql) throws SQLException { - return delegate.nativeSQL(sql); - } - - @Override - public void setAutoCommit(boolean autoCommit) throws SQLException { - delegate.setAutoCommit(autoCommit); - } - - @Override - public boolean getAutoCommit() throws SQLException { - return delegate.getAutoCommit(); - } +public class ConnectionWrapper extends ConnectionDelegate { - @Override - public void commit() throws SQLException { - delegate.commit(); - } + private final Runnable closeCallback; - @Override - public void rollback() throws SQLException { - delegate.rollback(); + public ConnectionWrapper(Connection connection, Runnable runnable) { + super(connection); + this.closeCallback = runnable; } @Override public void close() throws SQLException { - delegate.close(); + super.close(); try { - this.closeCallback.run(); - } catch (Exception e) { + closeCallback.run(); + } catch(Exception e) { e.printStackTrace(); } } - - @Override - public boolean isClosed() throws SQLException { - return delegate.isClosed(); - } - - @Override - public DatabaseMetaData getMetaData() throws SQLException { - return delegate.getMetaData(); - } - - @Override - public void setReadOnly(boolean readOnly) throws SQLException { - delegate.setReadOnly(readOnly); - } - - @Override - public boolean isReadOnly() throws SQLException { - return delegate.isReadOnly(); - } - - @Override - public void setCatalog(String catalog) throws SQLException { - delegate.setCatalog(catalog); - } - - @Override - public String getCatalog() throws SQLException { - return delegate.getCatalog(); - } - - @Override - public void setTransactionIsolation(int level) throws SQLException { - delegate.setTransactionIsolation(level); - } - - @Override - public int getTransactionIsolation() throws SQLException { - return delegate.getTransactionIsolation(); - } - - @Override - public SQLWarning getWarnings() throws SQLException { - return delegate.getWarnings(); - } - - @Override - public void clearWarnings() throws SQLException { - delegate.clearWarnings(); - } - - @Override - public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - return delegate.createStatement(resultSetType, resultSetConcurrency); - } - - @Override - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency); - } - - @Override - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - return delegate.prepareCall(sql, resultSetType, resultSetConcurrency); - } - - @Override - public Map> getTypeMap() throws SQLException { - return delegate.getTypeMap(); - } - - @Override - public void setTypeMap(Map> map) throws SQLException { - delegate.setTypeMap(map); - } - - @Override - public void setHoldability(int holdability) throws SQLException { - delegate.setHoldability(holdability); - } - - @Override - public int getHoldability() throws SQLException { - return delegate.getHoldability(); - } - - @Override - public Savepoint setSavepoint() throws SQLException { - return delegate.setSavepoint(); - } - - @Override - public Savepoint setSavepoint(String name) throws SQLException { - return delegate.setSavepoint(name); - } - - @Override - public void rollback(Savepoint savepoint) throws SQLException { - delegate.rollback(); - } - - @Override - public void releaseSavepoint(Savepoint savepoint) throws SQLException { - delegate.releaseSavepoint(savepoint); - } - - @Override - public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - return delegate.prepareStatement(sql, autoGeneratedKeys); - } - - @Override - public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - return delegate.prepareStatement(sql, columnIndexes); - } - - @Override - public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - return delegate.prepareStatement(sql, columnNames); - } - - @Override - public Clob createClob() throws SQLException { - return delegate.createClob(); - } - - @Override - public Blob createBlob() throws SQLException { - return delegate.createBlob(); - } - - @Override - public NClob createNClob() throws SQLException { - return delegate.createNClob(); - } - - @Override - public SQLXML createSQLXML() throws SQLException { - return delegate.createSQLXML(); - } - - @Override - public boolean isValid(int timeout) throws SQLException { - return delegate.isValid(timeout); - } - - @Override - public void setClientInfo(String name, String value) throws SQLClientInfoException { - delegate.setClientInfo(name, value); - } - - @Override - public void setClientInfo(Properties properties) throws SQLClientInfoException { - delegate.setClientInfo(properties); - } - - @Override - public String getClientInfo(String name) throws SQLException { - return delegate.getClientInfo(name); - } - - @Override - public Properties getClientInfo() throws SQLException { - return delegate.getClientInfo(); - } - - @Override - public Array createArrayOf(String typeName, Object[] elements) throws SQLException { - return delegate.createArrayOf(typeName, elements); - } - - @Override - public Struct createStruct(String typeName, Object[] attributes) throws SQLException { - return delegate.createStruct(typeName, attributes); - } - - @Override - public void setSchema(String schema) throws SQLException { - delegate.setSchema(schema); - } - - @Override - public String getSchema() throws SQLException { - return delegate.getSchema(); - } - - @Override - public void abort(Executor executor) throws SQLException { - delegate.abort(executor); - } - - @Override - public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { - delegate.setNetworkTimeout(executor, milliseconds); - } - - @Override - public int getNetworkTimeout() throws SQLException { - return delegate.getNetworkTimeout(); - } - - @Override - public T unwrap(Class iface) throws SQLException { - return delegate.unwrap(iface); - } - - @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return delegate.isWrapperFor(iface); - } } From 1beff7ca8c19f7d62e68fecc0019aacddd90d8fe Mon Sep 17 00:00:00 2001 From: Guillaume Le Floch Date: Thu, 3 Oct 2019 15:17:44 +0200 Subject: [PATCH 0316/4969] Localstack: fix typo in stepfunctions service name (#1930) --- .../containers/localstack/LocalStackContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index d16babb51e8..a5005abe239 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -134,7 +134,7 @@ public enum Service { CLOUDWATCH("cloudwatch", 4582), SSM("ssm", 4583), SECRETSMANAGER("secretsmanager", 4584), - STEPFUNCTIONS("stepsfunctions", 4585), + STEPFUNCTIONS("stepfunctions", 4585), CLOUDWATCHLOGS("cloudwatchlogs", 4586), STS("sts", 4592), IAM("iam", 4593); From 15140c5320ba726447c303aa51bbda467e9f9bb9 Mon Sep 17 00:00:00 2001 From: Pavel Popov Date: Thu, 3 Oct 2019 18:57:41 +0300 Subject: [PATCH 0317/4969] Add cockroach db support (#499) Co-authored-by: Kevin Wittek Co-authored-by: Richard North --- docs/modules/databases/cockroachdb.md | 26 +++++++ mkdocs.yml | 1 + modules/cockroachdb/build.gradle | 5 ++ .../containers/CockroachContainer.java | 78 +++++++++++++++++++ .../CockroachContainerProvider.java | 18 +++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + modules/jdbc-test/build.gradle | 1 + .../testcontainers/jdbc/JDBCDriverTest.java | 3 +- .../junit/SimpleCockroachDBTest.java | 44 +++++++++++ .../junit/SimplePostgreSQLTest.java | 7 ++ 10 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 docs/modules/databases/cockroachdb.md create mode 100644 modules/cockroachdb/build.gradle create mode 100644 modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java create mode 100644 modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainerProvider.java create mode 100644 modules/cockroachdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleCockroachDBTest.java diff --git a/docs/modules/databases/cockroachdb.md b/docs/modules/databases/cockroachdb.md new file mode 100644 index 00000000000..d9e6def4e48 --- /dev/null +++ b/docs/modules/databases/cockroachdb.md @@ -0,0 +1,26 @@ +# CockroachDB Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:cockroachdb:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + cockroachdb + {{latest_version}} + test + +``` + +!!! hint + Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/mkdocs.yml b/mkdocs.yml index 9d857ad21a9..976c1b7c95f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,6 +40,7 @@ nav: - Databases: - modules/databases/index.md - modules/databases/cassandra.md + - modules/databases/cockroachdb.md - modules/databases/couchbase.md - modules/databases/clickhouse.md - modules/databases/db2.md diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle new file mode 100644 index 00000000000..e52f9f3729c --- /dev/null +++ b/modules/cockroachdb/build.gradle @@ -0,0 +1,5 @@ +description = "Testcontainers :: JDBC :: CockroachDB" + +dependencies { + compile project(':jdbc') +} diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java new file mode 100644 index 00000000000..fb13ced60d7 --- /dev/null +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -0,0 +1,78 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; + +import java.time.Duration; + +public class CockroachContainer extends JdbcDatabaseContainer { + public static final String NAME = "cockroach"; + public static final String IMAGE = "cockroachdb/cockroach"; + public static final String IMAGE_TAG = "v19.1.1"; + private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; + private static final String JDBC_URL_PREFIX = "jdbc:postgresql"; + private static final String TEST_QUERY_STRING = "SELECT 1"; + private static final int REST_API_PORT = 8080; + private static final int DB_PORT = 26257; + + private String databaseName = "postgres"; + private String username = "root"; + private String password = ""; + + public CockroachContainer() { + this(IMAGE + ":" + IMAGE_TAG); + } + + public CockroachContainer(final String dockerImageName) { + super(dockerImageName); + + withExposedPorts(REST_API_PORT, DB_PORT); + waitingFor( + new HttpWaitStrategy() + .forPath("/health") + .forPort(REST_API_PORT) + .forStatusCode(200) + .withStartupTimeout(Duration.ofMinutes(1)) + ); + withCommand("start --insecure"); + } + + @Override + public String getDriverClassName() { + return JDBC_DRIVER_CLASS_NAME; + } + + @Override + public String getJdbcUrl() { + return JDBC_URL_PREFIX + "://" + getContainerIpAddress() + ":" + getMappedPort(DB_PORT) + "/" + databaseName; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getTestQueryString() { + return TEST_QUERY_STRING; + } + + @Override + public CockroachContainer withUsername(String username) { + throw new UnsupportedOperationException("The CockroachDB docker image does not currently support this - please see https://github.com/cockroachdb/cockroach/issues/19826"); + } + + @Override + public CockroachContainer withPassword(String password) { + throw new UnsupportedOperationException("The CockroachDB docker image does not currently support this - please see https://github.com/cockroachdb/cockroach/issues/19826"); + } + + @Override + public CockroachContainer withDatabaseName(final String databaseName) { + throw new UnsupportedOperationException("The CockroachDB docker image does not currently support this - please see https://github.com/cockroachdb/cockroach/issues/19826"); + } +} diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainerProvider.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainerProvider.java new file mode 100644 index 00000000000..96cafd54f31 --- /dev/null +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainerProvider.java @@ -0,0 +1,18 @@ +package org.testcontainers.containers; + +public class CockroachContainerProvider extends JdbcDatabaseContainerProvider { + @Override + public boolean supports(String databaseType) { + return databaseType.equals(CockroachContainer.NAME); + } + + @Override + public JdbcDatabaseContainer newInstance() { + return newInstance(CockroachContainer.IMAGE_TAG); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new CockroachContainer(CockroachContainer.IMAGE + ":" + tag); + } +} diff --git a/modules/cockroachdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/cockroachdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..3b58b4c6799 --- /dev/null +++ b/modules/cockroachdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.containers.CockroachContainerProvider \ No newline at end of file diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 9300ba49a4d..842f2a761eb 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -7,6 +7,7 @@ repositories { dependencies { compile project(':mysql') compile project(':postgresql') + compile project(':cockroachdb') compile project(':mariadb') compile project(':oracle-xe') compile project(':mssqlserver') diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index 0508a54e13d..2089513df06 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -65,7 +65,8 @@ public static Iterable data() { {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", EnumSet.of(Options.CustomIniFile)}, {"jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken)}, {"jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:cockroach://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)} }); } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleCockroachDBTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleCockroachDBTest.java new file mode 100644 index 00000000000..c21a5ddfaf1 --- /dev/null +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleCockroachDBTest.java @@ -0,0 +1,44 @@ +package org.testcontainers.junit; + +import org.junit.Test; +import org.testcontainers.containers.CockroachContainer; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.LogManager; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class SimpleCockroachDBTest extends AbstractContainerDatabaseTest { + + static { + // Postgres JDBC driver uses JUL; disable it to avoid annoying, irrelevant, stderr logs during connection testing + LogManager.getLogManager().getLogger("").setLevel(Level.OFF); + } + + @Test + public void testSimple() throws SQLException { + try (CockroachContainer cockroach = new CockroachContainer()) { + cockroach.start(); + + ResultSet resultSet = performQuery(cockroach, "SELECT 1"); + + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } + + @Test + public void testExplicitInitScript() throws SQLException { + try (CockroachContainer cockroach = new CockroachContainer() + .withInitScript("somepath/init_postgresql.sql")) { // CockroachDB is expected to be compatible with Postgres + cockroach.start(); + + ResultSet resultSet = performQuery(cockroach, "SELECT foo FROM bar"); + + String firstColumnValue = resultSet.getString(1); + assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + } + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java index 4624268cb2b..7189e05fb16 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java @@ -5,12 +5,19 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.LogManager; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { + static { + // Postgres JDBC driver uses JUL; disable it to avoid annoying, irrelevant, stderr logs during connection testing + LogManager.getLogManager().getLogger("").setLevel(Level.OFF); + } + @Test public void testSimple() throws SQLException { try (PostgreSQLContainer postgres = new PostgreSQLContainer<>()) { From cc1b86d72482d2f3122f86427eacd10d805e409f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 06:03:09 +0000 Subject: [PATCH 0318/4969] Bump mariadb-java-client from 2.4.4 to 2.5.0 in /modules/mariadb (#1942) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 9393f6c65c7..89449edc9ec 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.4.4' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.26' From 58e62a26c58fb5d93674de30726d4b4cd8ef547c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 07:05:34 +0000 Subject: [PATCH 0319/4969] Bump rest-assured from 4.1.1 to 4.1.2 in /modules/vault (#1943) --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 41807d2573b..b37a74602ff 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Vault" dependencies { compile project(':testcontainers') - testCompile 'io.rest-assured:rest-assured:4.1.1' + testCompile 'io.rest-assured:rest-assured:4.1.2' } From cd0b7cb4e1014ea89d6eb5479ba95102c2b9e30a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 08:14:17 +0000 Subject: [PATCH 0320/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#1934) --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index e8431190e8b..11c8b57f07a 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.3.2" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.4.0" testCompile "org.elasticsearch.client:transport:6.7.1" } From 43aa38af157126fac47185fec5262a361fcea863 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 09:18:14 +0000 Subject: [PATCH 0321/4969] Bump org.springframework.boot in /examples (#1944) --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index cf3b6567982..9f3aed047b3 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.8.RELEASE' + id 'org.springframework.boot' version '2.1.9.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 487c60e51dd..f6ef68f9866 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.8.RELEASE' + id 'org.springframework.boot' version '2.1.9.RELEASE' } apply plugin: 'io.spring.dependency-management' From bc082a84f24ec9fdb0dc06eed7204d61ea45c2db Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 4 Oct 2019 15:20:04 +0100 Subject: [PATCH 0322/4969] =?UTF-8?q?Fix=20for=20streaming=20readBytes=20t?= =?UTF-8?q?imeout=20on=20Windows=20with=20npipe=20strat=E2=80=A6=20(#1947)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transport/okhttp/NamedPipeSocketFactory.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java index ce272d6e1a6..d150eedb6a5 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java @@ -55,16 +55,25 @@ public void connect(SocketAddress endpoint, int timeout) { is = new InputStream() { @Override public int read(byte[] bytes, int off, int len) throws IOException { + if (OkHttpInvocationBuilder.CLOSING.get()) { + return 0; + } return file.read(bytes, off, len); } @Override public int read() throws IOException { + if (OkHttpInvocationBuilder.CLOSING.get()) { + return 0; + } return file.read(); } @Override public int read(byte[] bytes) throws IOException { + if (OkHttpInvocationBuilder.CLOSING.get()) { + return 0; + } return file.read(bytes); } }; From 5aa389af939102f767d3a8f58f3d451239915549 Mon Sep 17 00:00:00 2001 From: Guillaume Le Floch Date: Fri, 4 Oct 2019 16:21:14 +0200 Subject: [PATCH 0323/4969] Automatically set SHM for selenium container, and allow SHM size to be configured (#1751) --- .../containers/BrowserWebDriverContainer.java | 4 ++ .../junit/BrowserWebDriverContainerTest.java | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index b92a4877cd2..32245dee3b0 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -165,6 +165,10 @@ protected void configure() { setCommand("/opt/bin/entry_point.sh"); + if (getShmSize() == null) { + addFileSystemBind("/dev/shm", "/dev/shm", BindMode.READ_WRITE); + } + /* * Some unreliability of the selenium browser containers has been observed, so allow multiple attempts to start. */ diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java index 036262a6bd1..74f2d430383 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java @@ -1,10 +1,16 @@ package org.testcontainers.junit; +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.apache.commons.io.FileUtils; import org.junit.Test; import org.openqa.selenium.chrome.ChromeOptions; import org.testcontainers.containers.BrowserWebDriverContainer; +import java.util.List; +import java.util.stream.Collectors; + import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class BrowserWebDriverContainerTest { @@ -39,4 +45,40 @@ public void provideDefaultNoProxyEnvironmentIfNotSet() { assertEquals("no_proxy should be set to default if not already present", "localhost", noProxy); } } + + + @Test + public void createContainerWithShmVolume() { + try ( + BrowserWebDriverContainer webDriverContainer = new BrowserWebDriverContainer() + ) { + webDriverContainer.start(); + + final List mounts = webDriverContainer.getContainerInfo().getMounts(); + assertEquals("Shm mounts present", mounts.size(), 1); + + final InspectContainerResponse.Mount shmMount = mounts.get(0); + assertEquals("Shm mount source is correct", "/dev/shm", shmMount.getSource()); + assertEquals("Shm mount destination is correct", "/dev/shm", shmMount.getDestination().getPath()); + assertEquals("Shm mount mode is correct", shmMount.getMode(), "rw"); + } + } + + @Test + public void createContainerWithoutShmVolume() { + try ( + BrowserWebDriverContainer webDriverContainer = new BrowserWebDriverContainer<>() + .withSharedMemorySize(512 * FileUtils.ONE_MB) + ) { + webDriverContainer.start(); + assertEquals("Shared memory size is configured", 512 * FileUtils.ONE_MB, webDriverContainer.getShmSize()); + + final long shmMountCount = webDriverContainer.getContainerInfo().getMounts() + .stream() + .filter(m -> "/dev/shm".equals(m.getSource())) + .count(); + assertEquals("No shm mounts present", shmMountCount, 0L); + } + } + } From a9aa07cde52c80d37328d0e01eb2da4cd7db8d6c Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 4 Oct 2019 16:22:03 +0200 Subject: [PATCH 0324/4969] Update Gradle to 5.6.2 (#1510) Co-authored-by: Kevin Wittek Co-authored-by: Richard North --- build.gradle | 7 +++++-- core/build.gradle | 1 + examples/disque-job-queue/build.gradle | 3 ++- examples/spring-boot/build.gradle | 3 ++- gradle/wrapper/gradle-wrapper.jar | Bin 56177 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 3 +-- gradlew | 22 +++++++++++++++++++--- gradlew.bat | 18 +++++++++++++++++- 8 files changed, 47 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index ecdf48cd3f7..7bbf71af9f9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ plugins { - id 'com.gradle.build-scan' version '1.16' + id 'com.gradle.build-scan' version '2.4.2' id 'io.franzbecker.gradle-lombok' version '3.1.0' id 'nebula.provided-base' version '3.0.3' - id 'com.github.johnrengelman.shadow' version '2.0.2' + id 'com.github.johnrengelman.shadow' version '5.1.0' id "com.jfrog.bintray" version "1.8.4" apply false } @@ -32,6 +32,9 @@ subprojects { args(srcDir, "-d", outputDir) } } + delombok.onlyIf { + project.sourceSets.main.java.srcDirs.find { it.exists() } + } repositories { jcenter() diff --git a/core/build.gradle b/core/build.gradle index f08e7763b18..f7c4f727069 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -119,6 +119,7 @@ dependencies { testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" + jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' jarFileTestCompile 'org.assertj:assertj-core:3.12.2' jarFileTestCompile 'org.ow2.asm:asm-debug-all:5.2' diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index bb4aa6edaaa..fbebb1d8e9f 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,7 +7,8 @@ repositories { } dependencies { - compileOnly 'org.projectlombok:lombok:1.18.10' + compileOnly "org.projectlombok:lombok:1.18.10" + annotationProcessor "org.projectlombok:lombok:1.18.10" implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.guava:guava:23.0' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index f6ef68f9866..9d2d2db76ad 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -9,7 +9,8 @@ repositories { } dependencies { - compileOnly 'org.projectlombok:lombok:1.18.10' + compileOnly "org.projectlombok:lombok:1.18.10" + annotationProcessor "org.projectlombok:lombok:1.18.10" implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 29953ea141f55e3b8fc691d31b5ca8816d89fa87..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch delta 47360 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 delta 47987 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 P{tQ5B1&<&s7}); Date: Sat, 5 Oct 2019 09:03:22 +0100 Subject: [PATCH 0325/4969] Bump mockito-core from 3.0.0 to 3.1.0 in /core (#1932) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.0.0...v3.1.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index f7c4f727069..0bd3a019931 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -109,7 +109,7 @@ dependencies { testCompile 'redis.clients:jedis:3.1.0' testCompile 'com.rabbitmq:amqp-client:5.7.3' testCompile 'org.mongodb:mongo-java-driver:3.11.0' - testCompile ('org.mockito:mockito-core:3.0.0') { + testCompile ('org.mockito:mockito-core:3.1.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 52420d872c1a2832ab1785719b856e67faed7b5a Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 5 Oct 2019 09:18:22 +0100 Subject: [PATCH 0326/4969] Bump flaky test review dates (#1952) as we've not had time to look at these properly --- .../couchbase/BaseCouchbaseContainerTest.java | 6 +++--- .../org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java | 2 +- .../java/org/testcontainers/containers/ToxiproxyTest.java | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java index 1c5e702727a..19eead1b23a 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java @@ -32,7 +32,7 @@ public abstract class BaseCouchbaseContainerTest extends AbstractCouchbaseTest { public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-10-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldInsertDocument() { RawJsonDocument expected = RawJsonDocument.create(ID, DOCUMENT); getBucket().upsert(expected); @@ -41,7 +41,7 @@ public void shouldInsertDocument() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-10-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldExecuteN1ql() { getBucket().query(N1qlQuery.simple("INSERT INTO " + TEST_BUCKET + " (KEY, VALUE) VALUES ('" + ID + "', " + DOCUMENT + ")")); @@ -54,7 +54,7 @@ public void shouldExecuteN1ql() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-10-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldCreateView() { View view = DefaultView.create(VIEW_NAME, VIEW_FUNCTION); DesignDocument document = DesignDocument.create(VIEW_NAME, Lists.newArrayList(view)); diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java index 38c97686679..fb9794e29a8 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -20,7 +20,7 @@ public class DatabaseDriverTmpfsTest { public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1687", reviewDate = "2019-10-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1687", reviewDate = "2019-12-01") public void tmpfs() throws IOException, InterruptedException, SQLException { final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw"; try (Connection ignored = DriverManager.getConnection(jdbcUrl)) { diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index 8fa28431ab5..840165fb8ee 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -45,7 +45,7 @@ public void testDirect() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-10-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-12-01") public void testLatencyViaProxy() throws IOException { // obtainProxyObject { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); @@ -72,7 +72,7 @@ public void testLatencyViaProxy() throws IOException { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-10-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-12-01") public void testConnectionCut() { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); final Jedis jedis = new Jedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); @@ -97,7 +97,7 @@ public void testConnectionCut() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-10-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-12-01") public void testMultipleProxiesCanBeCreated() { try (GenericContainer secondRedis = new GenericContainer("redis:5.0.4") .withExposedPorts(6379) From 94c903d755c89340aecb7eeb8f77834c6c88e095 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 6 Oct 2019 08:16:36 +0100 Subject: [PATCH 0327/4969] Fix use of SHM for Selenium containers on Windows (#1948) * Change assertion used for SHM testing to support Windows * Make test resilient to future changes in default mounts by only checking counts of SHM volumes * WIP - experimental * Tweak assertion to cope with /dev/shm/ * Switch to directly adding SHM bind rather than using addFileSystemBind * Simplify assertion code --- .../testcontainers/utility/MountableFile.java | 2 + .../containers/BrowserWebDriverContainer.java | 5 ++- .../junit/BrowserWebDriverContainerTest.java | 39 +++++++++++-------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index cd83a81781f..56d5bda3ffa 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -167,7 +167,9 @@ private static String unencodeResourceURIToFilePath(@NotNull final String resour private String resolvePath() { String result = getResourcePath(); + // Special case for Windows if (SystemUtils.IS_OS_WINDOWS && result.startsWith("/")) { + // Remove leading / result = result.substring(1); } diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 32245dee3b0..9e1a2733a2e 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -1,5 +1,8 @@ package org.testcontainers.containers; +import com.github.dockerjava.api.model.AccessMode; +import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.Volume; import com.google.common.collect.ImmutableSet; import com.github.dockerjava.api.command.InspectContainerResponse; @@ -166,7 +169,7 @@ protected void configure() { setCommand("/opt/bin/entry_point.sh"); if (getShmSize() == null) { - addFileSystemBind("/dev/shm", "/dev/shm", BindMode.READ_WRITE); + this.getBinds().add(new Bind("/dev/shm", new Volume("/dev/shm"), AccessMode.rw)); } /* diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java index 74f2d430383..7b7d3a46733 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java @@ -4,13 +4,14 @@ import org.apache.commons.io.FileUtils; import org.junit.Test; import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.firefox.FirefoxOptions; import org.testcontainers.containers.BrowserWebDriverContainer; import java.util.List; -import java.util.stream.Collectors; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toList; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class BrowserWebDriverContainerTest { @@ -51,34 +52,40 @@ public void provideDefaultNoProxyEnvironmentIfNotSet() { public void createContainerWithShmVolume() { try ( BrowserWebDriverContainer webDriverContainer = new BrowserWebDriverContainer() + .withCapabilities(new FirefoxOptions()) ) { webDriverContainer.start(); - final List mounts = webDriverContainer.getContainerInfo().getMounts(); - assertEquals("Shm mounts present", mounts.size(), 1); + final List shmVolumes = shmVolumes(webDriverContainer); - final InspectContainerResponse.Mount shmMount = mounts.get(0); - assertEquals("Shm mount source is correct", "/dev/shm", shmMount.getSource()); - assertEquals("Shm mount destination is correct", "/dev/shm", shmMount.getDestination().getPath()); - assertEquals("Shm mount mode is correct", shmMount.getMode(), "rw"); + assertEquals("Only one shm mount present", 1, shmVolumes.size()); + assertEquals("Shm mount source is correct", "/dev/shm", shmVolumes.get(0).getSource()); + assertEquals("Shm mount mode is correct", "rw", shmVolumes.get(0).getMode()); } } @Test public void createContainerWithoutShmVolume() { try ( - BrowserWebDriverContainer webDriverContainer = new BrowserWebDriverContainer<>() - .withSharedMemorySize(512 * FileUtils.ONE_MB) + BrowserWebDriverContainer webDriverContainer = new BrowserWebDriverContainer<>() + .withSharedMemorySize(512 * FileUtils.ONE_MB) + .withCapabilities(new FirefoxOptions()) ) { webDriverContainer.start(); - assertEquals("Shared memory size is configured", 512 * FileUtils.ONE_MB, webDriverContainer.getShmSize()); - final long shmMountCount = webDriverContainer.getContainerInfo().getMounts() - .stream() - .filter(m -> "/dev/shm".equals(m.getSource())) - .count(); - assertEquals("No shm mounts present", shmMountCount, 0L); + assertEquals("Shared memory size is configured", + 512 * FileUtils.ONE_MB, + webDriverContainer.getShmSize()); + + assertEquals("No shm mounts present", emptyList(), shmVolumes(webDriverContainer)); } } + private List shmVolumes(final BrowserWebDriverContainer container) { + return container.getContainerInfo().getMounts() + .stream() + // destination path is always /dev/shm + .filter(m -> m.getDestination().getPath().equals("/dev/shm")) + .collect(toList()); + } } From 343bcd2f554b31b5ba04acd0212675192eb3fbef Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 6 Oct 2019 17:06:25 +0200 Subject: [PATCH 0328/4969] Lock the version of AWS S3 SDK in the build script. (#1955) see https://github.com/myniva/gradle-s3-build-cache/issues/20 --- settings.gradle | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/settings.gradle b/settings.gradle index 72e7d312555..e8fb1efe910 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,12 +1,18 @@ buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.9.0" + } + + configurations.classpath { + resolutionStrategy { + force 'com.amazonaws:aws-java-sdk-s3:1.11.582' + } } - } - dependencies { - classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.9.0" - } } apply plugin: 'ch.myniva.s3-build-cache' From 9a50a771894fe8e966fd4b95eb3ba8b9a781473b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2019 06:38:59 +0000 Subject: [PATCH 0329/4969] Bump cucumber-java from 4.7.2 to 4.7.4 in /examples (#1958) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 7e73852ca1d..61dfe948d4c 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.7.2' + implementation 'io.cucumber:cucumber-java:4.7.4' testImplementation 'io.cucumber:cucumber-junit:4.7.2' testImplementation 'org.testcontainers:selenium' } From a46f3021135cb5a69bcd3948141d10bfe4b56f5d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2019 07:30:50 +0000 Subject: [PATCH 0330/4969] Bump cucumber-junit from 4.7.2 to 4.7.4 in /examples (#1957) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 61dfe948d4c..7e536842bf0 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.7.4' - testImplementation 'io.cucumber:cucumber-junit:4.7.2' + testImplementation 'io.cucumber:cucumber-junit:4.7.4' testImplementation 'org.testcontainers:selenium' } From b08308f46f5d0403d779f785cef5a84e1569658b Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 8 Oct 2019 14:57:34 -0500 Subject: [PATCH 0331/4969] Always copy to "/" (root). Fixes #1954 (#1956) --- .../containers/GenericContainer.java | 7 ++----- .../junit/CopyFileToContainerTest.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index baf79474aaa..e3a16c2dacb 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1154,16 +1154,13 @@ public void copyFileToContainer(Transferable transferable, String containerPath) ) { tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); - int lastSlashIndex = StringUtils.removeEnd(containerPath, "/").lastIndexOf("/"); - String extractArchiveTo = containerPath.substring(0, lastSlashIndex + 1); - String pathInArchive = containerPath.substring(lastSlashIndex + 1); - transferable.transferTo(tarArchive, pathInArchive); + transferable.transferTo(tarArchive, containerPath); tarArchive.finish(); dockerClient .copyArchiveToContainerCmd(containerId) .withTarInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) - .withRemotePath(extractArchiveTo) + .withRemotePath("/") .exec(); } } diff --git a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java index 0641bc7d50d..ed6ee561505 100644 --- a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java @@ -59,4 +59,18 @@ public void shouldUseCopyOnlyWithReadOnlyClasspathResources() { assertFalse("uses mount for read-only with Selinux", copyMap.containsValue("/readOnlyShared")); assertFalse("uses mount for read-write", copyMap.containsValue("/readWrite")); } + + @Test + public void shouldCreateFoldersStructureWithCopy() throws Exception { + String resource = "/test_copy_to_container.txt"; + try ( + GenericContainer container = new GenericContainer<>() + .withCommand("sleep", "3000") + .withClasspathResourceMapping(resource, "/a/b/c/file", BindMode.READ_ONLY) + ) { + container.start(); + String filesList = container.execInContainer("ls", "/a/b/c/").getStdout(); + assertTrue("file list contains the file", filesList.contains("file")); + } + } } From e2272021b6ffaf329211349f0daa2b6b3c4cd584 Mon Sep 17 00:00:00 2001 From: worldtiki Date: Tue, 8 Oct 2019 20:59:12 +0100 Subject: [PATCH 0332/4969] Add a simple example with how to use the mock server container (#1950) * Add a simple example with how to use the mock server container * Move examples for mockserver to unit tests --- docs/modules/mockserver.md | 17 +++++ .../containers/MockServerContainerTest.java | 63 +++++++++++-------- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/docs/modules/mockserver.md b/docs/modules/mockserver.md index b6c0cd92457..051cecf076e 100644 --- a/docs/modules/mockserver.md +++ b/docs/modules/mockserver.md @@ -1,5 +1,21 @@ # Mockserver Module +Mock Server can be used to mock HTTP services by matching requests against user-defined expectations. + +## Usage example + +The following example shows how to start Mockserver. + + +[Creating a MockServer container](../../modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java) inside_block:creatingProxy + + +And how to set a simple expectation using the Java MockServerClient. + + +[Setting a simple expectation](../../modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java) inside_block:testSimpleExpectation + + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: @@ -16,3 +32,4 @@ testCompile "org.testcontainers:mockserver:{{latest_version}}" test ``` + diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index 8cb8ac88448..be1495a04c7 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import lombok.Cleanup; +import org.junit.Rule; import org.junit.Test; import org.mockserver.client.MockServerClient; @@ -11,12 +12,43 @@ import java.net.URLConnection; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; public class MockServerContainerTest { + // creatingProxy { + @Rule + public MockServerContainer mockServer = new MockServerContainer(); + // } + + private static String responseFromMockserver(MockServerContainer mockServer, String path) throws IOException { + URLConnection urlConnection = new URL(mockServer.getEndpoint() + path).openConnection(); + @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + return reader.readLine(); + } + + @Test + public void shouldReturnExpectation() throws Exception { + // testSimpleExpectation { + new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort()) + .when(request() + .withPath("/person") + .withQueryStringParameter("name", "peter")) + .respond(response() + .withBody("Peter the person!")); + + // ...a GET request to '/person?name=peter' returns "Peter the person!" + // } + + assertThat("Expectation returns expected response body", + responseFromMockserver(mockServer, "/person?name=peter"), + containsString("Peter the person") + ); + } + @Test public void shouldCallActualMockserverVersion() throws Exception { String actualVersion = MockServerClient.class.getPackage().getImplementationVersion(); @@ -25,33 +57,14 @@ public void shouldCallActualMockserverVersion() throws Exception { String expectedBody = "Hello World!"; - assertThat("MockServer returns correct result", - responseFromMockserver(mockServer, expectedBody, "/hello"), - containsString(expectedBody) - ); - } - } + new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort()) + .when(request().withPath("/hello")) + .respond(response().withBody(expectedBody)); - @Test - public void shouldCallDefaultMockserverVersion() throws Exception { - try (MockServerContainer mockServerDefault = new MockServerContainer()) { - mockServerDefault.start(); - String expectedBody = "Hello Default World!"; - - assertThat("MockServer returns correct result for default constructor", - responseFromMockserver(mockServerDefault, expectedBody, "/hellodefault"), - containsString(expectedBody) + assertThat("MockServer returns correct result", + responseFromMockserver(mockServer, "/hello"), + equalTo(expectedBody) ); } } - - private static String responseFromMockserver(MockServerContainer mockServer, String expectedBody, String path) throws IOException { - new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort()) - .when(request(path)) - .respond(response(expectedBody)); - - URLConnection urlConnection = new URL(mockServer.getEndpoint() + path).openConnection(); - @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - return reader.readLine(); - } } From ce759bd869de75e53e6db61b4d0a36cf881aab9e Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 8 Oct 2019 21:18:17 +0100 Subject: [PATCH 0333/4969] Switch travis build JDK to openjdk8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d7d5f94270d..85bef8cff9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ if: branch = master OR tag is present language: java jdk: - - oraclejdk8 + - openjdk8 sudo: required services: From 11fa0f9d8907811aa62847274f5fc1ad472e0a8e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2019 08:26:19 +0100 Subject: [PATCH 0334/4969] Bump gson from 2.8.5 to 2.8.6 in /examples (#1960) Bumps [gson](https://github.com/google/gson) from 2.8.5 to 2.8.6. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.8.5...gson-parent-2.8.6) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/disque-job-queue/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index fbebb1d8e9f..1f4e257cad1 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.10" annotationProcessor "org.projectlombok:lombok:1.18.10" implementation 'biz.paluch.redis:spinach:0.3' - implementation 'com.google.code.gson:gson:2.8.5' + implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.mockito:mockito-all:1.10.19' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index e68ccfea24f..e339878813c 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.28' implementation 'redis.clients:jedis:3.1.0' - implementation 'com.google.code.gson:gson:2.8.5' + implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 8b1a5638243..727c1649b07 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.28' implementation 'redis.clients:jedis:3.1.0' - implementation 'com.google.code.gson:gson:2.8.5' + implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.12' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 26a437909fe..250eb755632 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation 'redis.clients:jedis:3.1.0' - implementation 'com.google.code.gson:gson:2.8.5' + implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.28' From 8104c0c5c92d4f24003fc6a7f8dcc18835488c6e Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 10 Oct 2019 21:54:22 +0100 Subject: [PATCH 0335/4969] Update .travis.yml Add info level logging --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85bef8cff9c..810b5827757 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,29 +15,29 @@ jobs: include: - stage: test env: [ NAME=core ] - script: ./gradlew testcontainers:check javadoc --scan --no-daemon + script: ./gradlew testcontainers:check javadoc --scan --no-daemon -i - stage: test env: [ NAME=core ] jdk: openjdk11 - script: ./gradlew testcontainers:check --scan --no-daemon + script: ./gradlew testcontainers:check --scan --no-daemon -i - stage: test env: [ NAME=core ] jdk: openjdk12 - script: ./gradlew testcontainers:check --scan --no-daemon + script: ./gradlew testcontainers:check --scan --no-daemon -i - env: [ NAME=selenium ] - script: ./gradlew selenium:check --scan --no-daemon + script: ./gradlew selenium:check --scan --no-daemon -i - env: [ NAME=modules ] - script: ./gradlew check -x testcontainers:check -x selenium:check -x jdbc-test:check --scan --no-daemon + script: ./gradlew check -x testcontainers:check -x selenium:check -x jdbc-test:check --scan --no-daemon -i - env: [ NAME=jdbc ] - script: ./gradlew jdbc-test:check --scan --no-daemon + script: ./gradlew jdbc-test:check --scan --no-daemon -i - env: [ NAME=examples ] - script: cd examples && ../gradlew check --no-daemon + script: cd examples && ../gradlew check --no-daemon -i # Run Docker-in-Docker tests inside Alpine - env: [ NAME="docker-in-alpine-docker" ] @@ -49,7 +49,7 @@ jobs: -v "$(pwd)":"$(pwd)" \ -w "$(pwd)" \ openjdk:8-jdk-alpine \ - ./gradlew --no-daemon testcontainers:test --tests '*GenericContainerRuleTest' --scan + ./gradlew --no-daemon testcontainers:test --tests '*GenericContainerRuleTest' --scan -i - stage: deploy sudo: false @@ -58,7 +58,7 @@ jobs: script: skip deploy: provider: script - script: ./gradlew -Pversion=$TRAVIS_TAG release --scan --no-daemon + script: ./gradlew -Pversion=$TRAVIS_TAG release --scan --no-daemon -i on: tags: true branch: master From 32e8c53cf0d8bebf6d0056d5e6c12dbce499e599 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 12 Oct 2019 16:07:05 +0100 Subject: [PATCH 0336/4969] Fix docker-compose issue in Travis build --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.travis.yml b/.travis.yml index 810b5827757..02196e895fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,16 @@ jdk: sudo: required services: - docker + +env: + - DOCKER_COMPOSE_VERSION=1.24.1 + +# Fix for https://travis-ci.community/t/problematic-docker-compose-version-1-23-1/5362/3 +before_install: + - sudo rm /usr/local/bin/docker-compose + - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + - chmod +x docker-compose + - sudo mv docker-compose /usr/local/bin install: - ./gradlew build -x check --scan --no-daemon From 92b751d11e40a8ca7f54ec92ebcc8831dff79d04 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 12 Oct 2019 16:38:17 +0100 Subject: [PATCH 0337/4969] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02196e895fe..e069ed68bc6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,12 +9,12 @@ services: - docker env: - - DOCKER_COMPOSE_VERSION=1.24.1 + - DOCKER_COMPOSE_VERSION= # Fix for https://travis-ci.community/t/problematic-docker-compose-version-1-23-1/5362/3 before_install: - sudo rm /usr/local/bin/docker-compose - - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + - curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-Linux-x86_64 > docker-compose - chmod +x docker-compose - sudo mv docker-compose /usr/local/bin From 1a5cd16421c9747bc303ccbfcb704420b78a5d47 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 12 Oct 2019 16:38:28 +0100 Subject: [PATCH 0338/4969] Update .travis.yml --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e069ed68bc6..d21033b942a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,6 @@ jdk: sudo: required services: - docker - -env: - - DOCKER_COMPOSE_VERSION= # Fix for https://travis-ci.community/t/problematic-docker-compose-version-1-23-1/5362/3 before_install: From a502c8c3b21769c3dfa483bd7967339cd083eb6f Mon Sep 17 00:00:00 2001 From: Steve Hill Date: Sat, 12 Oct 2019 09:53:32 -0700 Subject: [PATCH 0339/4969] Update example dependency specified in junit_5.md (#1817) `testCompile` is deprecated and has been superseded by `testImplementation` --- docs/test_framework_integration/junit_5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test_framework_integration/junit_5.md b/docs/test_framework_integration/junit_5.md index 442fb485185..371240a8d54 100644 --- a/docs/test_framework_integration/junit_5.md +++ b/docs/test_framework_integration/junit_5.md @@ -126,7 +126,7 @@ This extension has only be tested with sequential test execution. Using it with Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:junit-jupiter:{{latest_version}}" +testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" ``` ```xml tab='Maven' From fcf3b0f642d0a80cf752ce2d4ac624baf449bc64 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2019 17:59:19 +0100 Subject: [PATCH 0340/4969] Bump jna-platform from 5.3.1 to 5.4.0 in /core (#1796) Bumps [jna-platform](https://github.com/java-native-access/jna) from 5.3.1 to 5.4.0. - [Release notes](https://github.com/java-native-access/jna/releases) - [Changelog](https://github.com/java-native-access/jna/blob/master/CHANGES.md) - [Commits](https://github.com/java-native-access/jna/compare/5.3.1...5.4.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 0bd3a019931..45fdf5d1b0b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -76,7 +76,7 @@ dependencies { exclude(group: "log4j", module: "log4j") } - compile "net.java.dev.jna:jna-platform:5.3.1" + compile "net.java.dev.jna:jna-platform:5.4.0" shaded ('org.scala-sbt.ipcsocket:ipcsocket:1.0.0') { exclude(group: "net.java.dev.jna") From ce7a57200f1f889c18d384ab1dad438edfa14efc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 13 Oct 2019 18:12:03 +0100 Subject: [PATCH 0341/4969] Bump okhttp from 3.14.2 to 3.14.4 in /core (#1924) Bumps [okhttp](https://github.com/square/okhttp) from 3.14.2 to 3.14.4. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/docs/changelog_3x.md) - [Commits](https://github.com/square/okhttp/compare/parent-3.14.2...parent-3.14.4) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 45fdf5d1b0b..1d3ca56f89f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -97,7 +97,7 @@ dependencies { shaded "org.yaml:snakeyaml:1.25" - shaded 'com.squareup.okhttp3:okhttp:3.14.2' + shaded 'com.squareup.okhttp3:okhttp:3.14.4' shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From fbdfeddeed79d818ab9dd2d0b1ba18ba0453bbb0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 18:55:42 +0000 Subject: [PATCH 0342/4969] Bump mongo-java-driver from 3.11.0 to 3.11.1 in /core (#1970) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 1d3ca56f89f..2b631f46bce 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,7 +108,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.1.0' testCompile 'com.rabbitmq:amqp-client:5.7.3' - testCompile 'org.mongodb:mongo-java-driver:3.11.0' + testCompile 'org.mongodb:mongo-java-driver:3.11.1' testCompile ('org.mockito:mockito-core:3.1.0') { exclude(module: 'hamcrest-core') } From cea37a8219176db8d568d2049d9cb27e38451ebb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 19:55:54 +0100 Subject: [PATCH 0343/4969] Bump tomcat-jdbc from 9.0.26 to 9.0.27 in /modules/mariadb (#1967) Bumps tomcat-jdbc from 9.0.26 to 9.0.27. Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 89449edc9ec..9c2150a51cd 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.26' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.27' testCompile 'org.vibur:vibur-dbcp:22.2' } From 69cd9ebc9780925f2fc2124a925faddb6ccc015c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:16:48 +0100 Subject: [PATCH 0344/4969] Bump mariadb-java-client from 2.5.0 to 2.5.1 in /modules/mariadb (#1983) Bumps [mariadb-java-client](https://github.com/MariaDB/mariadb-connector-j) from 2.5.0 to 2.5.1. - [Release notes](https://github.com/MariaDB/mariadb-connector-j/releases) - [Commits](https://github.com/MariaDB/mariadb-connector-j/compare/2.5.0...2.5.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 9c2150a51cd..f6d65f4a5f0 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.0' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.1' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.27' From c6e76b4e00b895a7ecaeee08efd9b4365178132e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:17:11 +0100 Subject: [PATCH 0345/4969] Bump cucumber-junit from 4.7.4 to 4.8.0 in /examples (#1973) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 4.7.4 to 4.8.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v4.7.4...v4.8.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 7e536842bf0..7b489671506 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' implementation 'io.cucumber:cucumber-java:4.7.4' - testImplementation 'io.cucumber:cucumber-junit:4.7.4' + testImplementation 'io.cucumber:cucumber-junit:4.8.0' testImplementation 'org.testcontainers:selenium' } From 33e26deb6c524cff82078e2f21ba11540cd4f51d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:17:28 +0100 Subject: [PATCH 0346/4969] =?UTF-8?q?Bump=20mysql-connector-java=20from=20?= =?UTF-8?q?8.0.17=20to=208.0.18=20in=20/modules/mys=E2=80=A6=20(#1968)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.17 to 8.0.18. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index dbb6747e80f..3c856aca872 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { compile project(':jdbc') - testCompile 'mysql:mysql-connector-java:8.0.17' + testCompile 'mysql:mysql-connector-java:8.0.18' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.26' testCompile 'commons-dbutils:commons-dbutils:1.7' From 0f55de13309ad25266dd981d37e5bcda19d010fe Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:17:36 +0100 Subject: [PATCH 0347/4969] Bump tomcat-jdbc from 9.0.26 to 9.0.27 in /modules/mysql (#1969) Bumps tomcat-jdbc from 9.0.26 to 9.0.27. Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 3c856aca872..7704f56c54f 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.18' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.26' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.27' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From 3bff1d0b614b23b8a56292aa5de77637f5860198 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:18:11 +0100 Subject: [PATCH 0348/4969] =?UTF-8?q?Bump=20mysql-connector-java=20from=20?= =?UTF-8?q?8.0.17=20to=208.0.18=20in=20/modules/spo=E2=80=A6=20(#1972)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.17 to 8.0.18. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 552fd3883cd..d84e8776af3 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -14,5 +14,5 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testRuntime 'org.postgresql:postgresql:42.2.8' - testRuntime 'mysql:mysql-connector-java:8.0.17' + testRuntime 'mysql:mysql-connector-java:8.0.18' } From e36ec2ba8dfc5b7b786dafa81b3d419498923bef Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:18:22 +0100 Subject: [PATCH 0349/4969] Bump cucumber-java from 4.7.4 to 4.8.0 in /examples (#1974) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 4.7.4 to 4.8.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v4.7.4...v4.8.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 7b489671506..5d2caed8c2a 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.7.4' + implementation 'io.cucumber:cucumber-java:4.8.0' testImplementation 'io.cucumber:cucumber-junit:4.8.0' testImplementation 'org.testcontainers:selenium' } From 8cf76c09f065d6fb8fdb03a236cc270412b9afa0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:18:34 +0100 Subject: [PATCH 0350/4969] =?UTF-8?q?Bump=20mysql-connector-java=20from=20?= =?UTF-8?q?8.0.17=20to=208.0.18=20in=20/modules/jun=E2=80=A6=20(#1971)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.17 to 8.0.18. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index e286af1e149..f6f23aa8959 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -14,7 +14,7 @@ dependencies { } testRuntime 'org.postgresql:postgresql:42.2.8' - testRuntime 'mysql:mysql-connector-java:8.0.17' + testRuntime 'mysql:mysql-connector-java:8.0.18' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.2' } From c27f4016c791d811dfe1cf392606ae0f65d4e6e7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 20 Oct 2019 13:05:28 +0000 Subject: [PATCH 0351/4969] Bump org.springframework.boot in /examples (#1985) --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 9f3aed047b3..2c15c3038ba 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.9.RELEASE' + id 'org.springframework.boot' version '2.2.0.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 9d2d2db76ad..df18e6a5f03 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.1.9.RELEASE' + id 'org.springframework.boot' version '2.2.0.RELEASE' } apply plugin: 'io.spring.dependency-management' From 38062356bf955b177f8890155da5e182c7caf151 Mon Sep 17 00:00:00 2001 From: Jonathan Vila Date: Sun, 20 Oct 2019 15:16:39 +0200 Subject: [PATCH 0352/4969] Added documentation example of using local Docker Compose (#1987) Co-authored-by: Jonathan Vila --- docs/modules/docker_compose.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index 965b6c7084a..fa584d7f631 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -112,7 +112,13 @@ public static DockerComposeContainer environment = You can override Testcontainers' default behaviour and make it use a `docker-compose` binary installed on the local machine. This will generally yield an experience that is closer to running docker-compose locally, with the caveat that Docker Compose needs to be present on dev and CI machines. - +```java +public static DockerComposeContainer environment = + new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) + .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()) + .waitingFor("db_1", Wait.forLogMessage("started", 1)) + .withLocalCompose(true); +``` ## Using private repositories in Docker compose When Docker Compose is used in container mode (not local), it's needs to be made aware of Docker settings for private repositories. By default, those setting are located in `$HOME/.docker/config.json`. From 43a76abb5d27f322a6a7a30ffc148beb31cd5736 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 26 Oct 2019 11:34:22 +0300 Subject: [PATCH 0353/4969] Reusable containers (stage1, alpha) (#1781) * Simplify Kafka container by deferring the Kafka command * WIP: reusable containers based on labels * do not call `newInstance` from `newInstanceFromConnectionUrl` * disable the port forwarding in `ReusabilityUnitTests` * Simplify the startup sequence * speed up port detection by running the checks as a single command * Separate "environment" and "classpath" properties (for global things) * Update TestcontainersConfiguration.java * Add test for the reuse env property * Add `@UnstableAPI` annotation * Add `VisibleForTesting` on `findContainerForReuse` --- .../java/org/testcontainers/UnstableAPI.java | 21 ++ .../containers/GenericContainer.java | 126 +++++++++-- .../containers/LazyDockerClient.java | 15 ++ .../utility/TestcontainersConfiguration.java | 8 +- .../containers/ReusabilityUnitTests.java | 200 ++++++++++++++++++ .../TestcontainersConfigurationTest.java | 11 + .../JdbcDatabaseContainerProvider.java | 10 +- .../testcontainers/jdbc/ConnectionUrl.java | 6 + .../jdbc/ContainerDatabaseDriver.java | 2 +- 9 files changed, 380 insertions(+), 19 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/UnstableAPI.java create mode 100644 core/src/main/java/org/testcontainers/containers/LazyDockerClient.java create mode 100644 core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java diff --git a/core/src/main/java/org/testcontainers/UnstableAPI.java b/core/src/main/java/org/testcontainers/UnstableAPI.java new file mode 100644 index 00000000000..21fd2c3176c --- /dev/null +++ b/core/src/main/java/org/testcontainers/UnstableAPI.java @@ -0,0 +1,21 @@ +package org.testcontainers; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks that the annotated API is a subject to change and SHOULD NOT be considered + * a stable API. + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ + ElementType.TYPE, + ElementType.METHOD, + ElementType.FIELD, +}) +@Documented +public @interface UnstableAPI { +} diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index e3a16c2dacb..f17e8dfd0b2 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1,5 +1,9 @@ package org.testcontainers.containers; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.InspectContainerResponse; @@ -12,13 +16,15 @@ import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.api.model.VolumesFrom; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; import lombok.AccessLevel; import lombok.Data; -import lombok.EqualsAndHashCode; import lombok.NonNull; import lombok.Setter; import lombok.SneakyThrows; +import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; @@ -33,6 +39,7 @@ import org.rnorth.visibleassertions.VisibleAssertions; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; +import org.testcontainers.UnstableAPI; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.startupcheck.IsRunningStartupCheckStrategy; import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy; @@ -62,11 +69,14 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.file.Path; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -100,6 +110,8 @@ public class GenericContainer> public static final String INTERNAL_HOST_HOSTNAME = "host.testcontainers.internal"; + static final String HASH_LABEL = "org.testcontainers.hash"; + /* * Default settings */ @@ -168,11 +180,12 @@ public class GenericContainer> protected final Set dependencies = new HashSet<>(); - /* + /** * Unique instance of DockerClient for use by this container object. + * We use {@link LazyDockerClient} here to avoid eager client creation */ @Setter(AccessLevel.NONE) - protected DockerClient dockerClient = DockerClientFactory.instance().client(); + protected DockerClient dockerClient = LazyDockerClient.INSTANCE; /* * Info about the Docker server; lazily fetched. @@ -222,6 +235,8 @@ public class GenericContainer> @Nullable private Map tmpFsMapping; + @Setter(AccessLevel.NONE) + private boolean shouldBeReused = false; public GenericContainer() { this(TestcontainersConfiguration.getInstance().getTinyImage()); @@ -276,13 +291,15 @@ protected void doStart() { try { configure(); + Instant startedAt = Instant.now(); + logger().debug("Starting container: {}", getDockerImageName()); logger().debug("Trying to start container: {}", image.get()); AtomicInteger attempt = new AtomicInteger(0); Unreliables.retryUntilSuccess(startupAttempts, () -> { logger().debug("Trying to start container: {} (attempt {}/{})", image.get(), attempt.incrementAndGet(), startupAttempts); - tryStart(); + tryStart(startedAt); return true; }); @@ -291,7 +308,25 @@ protected void doStart() { } } - private void tryStart() { + @UnstableAPI + @SneakyThrows + protected boolean canBeReused() { + for (Class type = getClass(); type != GenericContainer.class; type = type.getSuperclass()) { + try { + Method method = type.getDeclaredMethod("containerIsCreated", String.class); + if (method.getDeclaringClass() != GenericContainer.class) { + logger().warn("{} can't be reused because it overrides {}", getClass(), method.getName()); + return false; + } + } catch (NoSuchMethodException e) { + // ignore + } + } + + return true; + } + + private void tryStart(Instant startedAt) { try { String dockerImageName = image.get(); logger().debug("Starting container: {}", dockerImageName); @@ -300,16 +335,49 @@ private void tryStart() { CreateContainerCmd createCommand = dockerClient.createContainerCmd(dockerImageName); applyConfiguration(createCommand); - containerId = createCommand.exec().getId(); + createCommand.getLabels().put(DockerClientFactory.TESTCONTAINERS_LABEL, "true"); - connectToPortForwardingNetwork(createCommand.getNetworkMode()); + boolean reused = false; + if (shouldBeReused) { + if (!canBeReused()) { + throw new IllegalStateException("This container does not support reuse"); + } - copyToFileContainerPathMap.forEach(this::copyFileToContainer); + if (TestcontainersConfiguration.getInstance().environmentSupportsReuse()) { + String hash = hash(createCommand); - containerIsCreated(containerId); + containerId = findContainerForReuse(hash).orElse(null); - logger().info("Starting container with ID: {}", containerId); - dockerClient.startContainerCmd(containerId).exec(); + if (containerId != null) { + logger().info("Reusing container with ID: {} and hash: {}", containerId, hash); + reused = true; + } else { + logger().debug("Can't find a reusable running container with hash: {}", hash); + + createCommand.getLabels().put(HASH_LABEL, hash); + } + } else { + logger().info("Reuse was requested but the environment does not support the reuse of containers"); + } + } else { + createCommand.getLabels().put(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL, DockerClientFactory.SESSION_ID); + } + + if (!reused) { + containerId = createCommand.exec().getId(); + + // TODO add to the hash + copyToFileContainerPathMap.forEach(this::copyFileToContainer); + } + + connectToPortForwardingNetwork(createCommand.getNetworkMode()); + + if (!reused) { + containerIsCreated(containerId); + + logger().info("Starting container with ID: {}", containerId); + dockerClient.startContainerCmd(containerId).exec(); + } logger().info("Container {} is starting: {}", dockerImageName, containerId); @@ -331,7 +399,7 @@ private void tryStart() { // Wait until the process within the container has become ready for use (e.g. listening on network, log message emitted, etc). waitUntilContainerStarted(); - logger().info("Container {} started", dockerImageName); + logger().info("Container {} started in {}", dockerImageName, Duration.between(startedAt, Instant.now())); containerIsStarted(containerInfo); } catch (Exception e) { logger().error("Could not start container", e); @@ -351,6 +419,31 @@ private void tryStart() { } } + @UnstableAPI + @SneakyThrows(JsonProcessingException.class) + final String hash(CreateContainerCmd createCommand) { + // TODO add Testcontainers' version to the hash + String commandJson = new ObjectMapper() + .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY) + .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) + .writeValueAsString(createCommand); + + return DigestUtils.sha1Hex(commandJson); + } + + @VisibleForTesting + Optional findContainerForReuse(String hash) { + // TODO locking + return dockerClient.listContainersCmd() + .withLabelFilter(ImmutableMap.of(HASH_LABEL, hash)) + .withLimit(1) + .withStatusFilter(Arrays.asList("running")) + .exec() + .stream() + .findAny() + .map(it -> it.getId()); + } + /** * Set any custom settings for the create command such as shared memory size. */ @@ -613,7 +706,6 @@ private void applyConfiguration(CreateContainerCmd createCommand) { if (createCommand.getLabels() != null) { combinedLabels.putAll(createCommand.getLabels()); } - combinedLabels.putAll(DockerClientFactory.DEFAULT_LABELS); createCommand.withLabels(combinedLabels); } @@ -1215,7 +1307,7 @@ public SELF withStartupAttempts(int attempts) { } /** - * Allow low level modifications of {@link CreateContainerCmd} after it was pre-configured in {@link #tryStart()}. + * Allow low level modifications of {@link CreateContainerCmd} after it was pre-configured in {@link #tryStart(Instant)}. * Invocation happens eagerly on a moment when container is created. * Warning: this does expose the underlying docker-java API so might change outside of our control. * @@ -1247,6 +1339,12 @@ public SELF withTmpFs(Map mapping) { return self(); } + @UnstableAPI + public SELF withReuse(boolean reusable) { + this.shouldBeReused = reusable; + return self(); + } + @Override public boolean equals(Object o) { return this == o; diff --git a/core/src/main/java/org/testcontainers/containers/LazyDockerClient.java b/core/src/main/java/org/testcontainers/containers/LazyDockerClient.java new file mode 100644 index 00000000000..b1341b52755 --- /dev/null +++ b/core/src/main/java/org/testcontainers/containers/LazyDockerClient.java @@ -0,0 +1,15 @@ +package org.testcontainers.containers; + +import com.github.dockerjava.api.DockerClient; +import lombok.experimental.Delegate; +import org.testcontainers.DockerClientFactory; + +enum LazyDockerClient implements DockerClient { + + INSTANCE; + + @Delegate + final DockerClient getDockerClient() { + return DockerClientFactory.instance().client(); + } +} diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 21f9bdfb333..e5a45a05b64 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -2,6 +2,7 @@ import lombok.*; import lombok.extern.slf4j.Slf4j; +import org.testcontainers.UnstableAPI; import java.io.*; import java.net.MalformedURLException; @@ -89,12 +90,17 @@ public boolean isDisableChecks() { return Boolean.parseBoolean((String) environmentProperties.getOrDefault("checks.disable", "false")); } + @UnstableAPI + public boolean environmentSupportsReuse() { + return Boolean.parseBoolean((String) environmentProperties.getOrDefault("testcontainers.reuse.enable", "false")); + } + public String getDockerClientStrategyClassName() { return (String) environmentProperties.get("docker.client.strategy"); } /** - * + * * @deprecated we no longer have different transport types */ @Deprecated diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java new file mode 100644 index 00000000000..b05db5b5077 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -0,0 +1,200 @@ +package org.testcontainers.containers; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.*; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.core.command.CreateContainerCmdImpl; +import com.github.dockerjava.core.command.InspectContainerCmdImpl; +import com.github.dockerjava.core.command.ListContainersCmdImpl; +import com.github.dockerjava.core.command.StartContainerCmdImpl; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.junit.Assume; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.Parameterized; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; +import org.rnorth.visibleassertions.VisibleAssertions; +import org.testcontainers.containers.startupcheck.StartupCheckStrategy; +import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; +import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.utility.TestcontainersConfiguration; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@RunWith(Enclosed.class) +public class ReusabilityUnitTests { + + static final CompletableFuture IMAGE_FUTURE = CompletableFuture.completedFuture( + TestcontainersConfiguration.getInstance().getTinyImage() + ); + + @RunWith(Parameterized.class) + @RequiredArgsConstructor + @FieldDefaults(makeFinal = true) + public static class CanBeReusedTest { + + @Parameterized.Parameters(name = "{0}") + public static Object[][] data() { + return new Object[][] { + { "generic", new GenericContainer(IMAGE_FUTURE), true }, + { "anonymous generic", new GenericContainer(IMAGE_FUTURE) {}, true }, + { "custom", new CustomContainer(), true }, + { "anonymous custom", new CustomContainer() {}, true }, + { "custom with containerIsCreated", new CustomContainerWithContainerIsCreated(), false }, + }; + } + + String name; + + GenericContainer container; + + boolean reusable; + + @Test + public void shouldBeReusable() { + if (reusable) { + VisibleAssertions.assertTrue("Is reusable", container.canBeReused()); + } else { + VisibleAssertions.assertFalse("Is not reusable", container.canBeReused()); + } + } + + static class CustomContainer extends GenericContainer { + CustomContainer() { + super(IMAGE_FUTURE); + } + } + + static class CustomContainerWithContainerIsCreated extends GenericContainer { + + CustomContainerWithContainerIsCreated() { + super(IMAGE_FUTURE); + } + + @Override + protected void containerIsCreated(String containerId) { + super.containerIsCreated(containerId); + } + } + } + + @RunWith(BlockJUnit4ClassRunner.class) + @FieldDefaults(makeFinal = true) + public static class HashTest { + + StartupCheckStrategy startupCheckStrategy = new StartupCheckStrategy() { + @Override + public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { + return StartupStatus.SUCCESSFUL; + } + }; + + WaitStrategy waitStrategy = new AbstractWaitStrategy() { + @Override + protected void waitUntilReady() { + + } + }; + + DockerClient client = Mockito.mock(DockerClient.class); + + GenericContainer container = new GenericContainer(IMAGE_FUTURE) + .withNetworkMode("none") // to disable the port forwarding + .withStartupCheckStrategy(startupCheckStrategy) + .waitingFor(waitStrategy) + .withReuse(true); + + { + container.dockerClient = client; + } + + @Test + public void shouldStartIfListReturnsEmpty() { + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); + when(client.listContainersCmd()).then(listContainersAnswer()); + when(client.startContainerCmd(containerId)).then(startContainerAnswer()); + when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); + + container.start(); + + Mockito.verify(client, Mockito.atLeastOnce()).startContainerCmd(containerId); + } + + @Test + public void shouldReuseIfListReturnsID() { + // TODO mock TestcontainersConfiguration + Assume.assumeTrue("supports reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); + when(client.createContainerCmd(any())).then(createContainerAnswer(randomContainerId())); + String existingContainerId = randomContainerId(); + when(client.listContainersCmd()).then(listContainersAnswer(existingContainerId)); + when(client.inspectContainerCmd(existingContainerId)).then(inspectContainerAnswer()); + + container.start(); + + Mockito.verify(client, Mockito.never()).startContainerCmd(existingContainerId); + } + + private String randomContainerId() { + return UUID.randomUUID().toString(); + } + + private Answer listContainersAnswer(String... ids) { + return invocation -> { + ListContainersCmd.Exec exec = command -> { + return new ObjectMapper().convertValue( + Stream.of(ids) + .map(id -> Collections.singletonMap("Id", id)) + .collect(Collectors.toList()), + new TypeReference>() {} + ); + }; + return new ListContainersCmdImpl(exec); + }; + } + + private Answer createContainerAnswer(String containerId) { + return invocation -> { + CreateContainerCmd.Exec exec = command -> { + CreateContainerResponse response = new CreateContainerResponse(); + response.setId(containerId); + return response; + }; + return new CreateContainerCmdImpl(exec, null, "image:latest"); + }; + } + + private Answer startContainerAnswer() { + return invocation -> { + StartContainerCmd.Exec exec = command -> { + return null; + }; + return new StartContainerCmdImpl(exec, invocation.getArgument(0)); + }; + } + + private Answer inspectContainerAnswer() { + return invocation -> { + InspectContainerCmd.Exec exec = command -> { + return new InspectContainerResponse(); + }; + return new InspectContainerCmdImpl(exec, invocation.getArgument(0)); + }; + } + + } +} diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index ad2a0be6cd3..49a378554f1 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -37,6 +37,17 @@ public void shouldReadDockerClientStrategyFromEnvironmentOnly() { assertEquals("Docker client strategy is changed", "foo", newConfig().getDockerClientStrategyClassName()); } + @Test + public void shouldReadReuseFromEnvironmentOnly() { + assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); + + classpathProperties.setProperty("testcontainers.reuse.enable", "true"); + assertFalse("reuse is not affected by classpath properties", newConfig().environmentSupportsReuse()); + + environmentProperties.setProperty("testcontainers.reuse.enable", "true"); + assertTrue("reuse enabled", newConfig().environmentSupportsReuse()); + } + private TestcontainersConfiguration newConfig() { return new TestcontainersConfiguration(environmentProperties, classpathProperties); } diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java index f2ebde857c5..f8694306384 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java @@ -45,11 +45,14 @@ public JdbcDatabaseContainer newInstance() { * @return Instance of {@link JdbcDatabaseContainer} */ public JdbcDatabaseContainer newInstance(ConnectionUrl url) { + final JdbcDatabaseContainer result; if (url.getImageTag().isPresent()) { - return newInstance(url.getImageTag().get()); + result = newInstance(url.getImageTag().get()); } else { - return newInstance(); + result = newInstance(); } + result.withReuse(url.isReusable()); + return result; } protected JdbcDatabaseContainer newInstanceFromConnectionUrl(ConnectionUrl connectionUrl, final String userParamName, final String pwdParamName) { @@ -59,7 +62,7 @@ protected JdbcDatabaseContainer newInstanceFromConnectionUrl(ConnectionUrl conne final String user = connectionUrl.getQueryParameters().getOrDefault(userParamName, "test"); final String password = connectionUrl.getQueryParameters().getOrDefault(pwdParamName, "test"); - final JdbcDatabaseContainer instance; + final JdbcDatabaseContainer instance; if (connectionUrl.getImageTag().isPresent()) { instance = newInstance(connectionUrl.getImageTag().get()); } else { @@ -67,6 +70,7 @@ protected JdbcDatabaseContainer newInstanceFromConnectionUrl(ConnectionUrl conne } return instance + .withReuse(connectionUrl.isReusable()) .withDatabaseName(databaseName) .withUsername(user) .withPassword(password); diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java index e236d723c82..4c590474bf7 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java @@ -13,6 +13,7 @@ import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.testcontainers.UnstableAPI; import static java.util.stream.Collectors.toMap; @@ -49,6 +50,9 @@ public class ConnectionUrl { private Optional initScriptPath = Optional.empty(); + @UnstableAPI + private boolean reusable = false; + private Optional initFunction = Optional.empty(); private Optional queryString; @@ -132,6 +136,8 @@ private void parseUrl() { initScriptPath = Optional.ofNullable(containerParameters.get("TC_INITSCRIPT")); + reusable = Boolean.parseBoolean(containerParameters.get("TC_REUSABLE")); + Matcher funcMatcher = Patterns.INITFUNCTION_MATCHING_PATTERN.matcher(this.getUrl()); if (funcMatcher.matches()) { initFunction = Optional.of(new InitFunctionDef(funcMatcher.group(2), funcMatcher.group(4))); diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java index 6d3df6c7cc5..c5413fe7efb 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java @@ -151,7 +151,7 @@ public synchronized Connection connect(String url, final Properties info) throws */ private Connection wrapConnection(final Connection connection, final JdbcDatabaseContainer container, final ConnectionUrl connectionUrl) { - final boolean isDaemon = connectionUrl.isInDaemonMode(); + final boolean isDaemon = connectionUrl.isInDaemonMode() || connectionUrl.isReusable(); Set connections = containerConnections.computeIfAbsent(container.getContainerId(), k -> new HashSet<>()); From 92f0a4f7ffb9d46023ec77e6588e74831ee8e29f Mon Sep 17 00:00:00 2001 From: Benjamin Muskalla Date: Sat, 26 Oct 2019 10:35:38 +0200 Subject: [PATCH 0354/4969] Allow @Testcontainers to be inherited from superclass (#1843) (#2001) * Updated existing test with now expected behaviour * @Testcontainers is now @Inherited --- .../org/testcontainers/junit/jupiter/Testcontainers.java | 6 ++++++ .../junit/jupiter/inheritance/AbstractTestBase.java | 2 -- .../junit/jupiter/inheritance/InheritedTests.java | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java index 6a364cd19e6..8e05dfdc576 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -18,6 +19,10 @@ * last test method has executed. Containers declared as instance fields will * be started and stopped for every test method.

* + *

The annotation {@code @Testcontainers} can be used on a superclass in + * the test hierarchy as well. All subclasses will automatically inherit + * support for the extension.

+ * *

Note: This extension has only be tested with sequential * test execution. Using it with parallel test execution is unsupported and * may have unintended side effects.

@@ -52,6 +57,7 @@ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(TestcontainersExtension.class) +@Inherited public @interface Testcontainers { /** diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java index 930f16f035d..3766c3f7a60 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java @@ -3,8 +3,6 @@ import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import java.util.concurrent.atomic.AtomicLong; - @Testcontainers abstract class AbstractTestBase { diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java index 37e535d25e7..f050e428692 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java @@ -6,7 +6,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -@Testcontainers class InheritedTests extends AbstractTestBase { @Container From 12cb54baa4f702c8d5dd9f05a0194114e061c6ed Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 26 Oct 2019 12:44:40 +0300 Subject: [PATCH 0355/4969] Update mkdocs.yml to 1.12.3 --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 976c1b7c95f..5c78e884662 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -83,4 +83,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.12.2 + latest_version: 1.12.3 From 71e3d75d4897399c788c276f9f86d0023bbeb862 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 09:28:17 +0000 Subject: [PATCH 0356/4969] Bump influxdb-java from 2.15 to 2.16 in /modules/influxdb (#2010) --- modules/influxdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index d122f786591..186174c242f 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { compile project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.15' + compileOnly 'org.influxdb:influxdb-java:2.16' testCompile 'org.influxdb:influxdb-java:2.15' } From 8fbd1f8a9c0966781db939718141daa50e8e1bb3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 09:40:24 +0000 Subject: [PATCH 0357/4969] Bump assertj-core from 3.13.2 to 3.14.0 in /modules/pulsar (#2009) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.13.2 to 3.14.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.13.2...assertj-core-3.14.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 05d9a711420..046debc2b9b 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,5 +4,5 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.4.1' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.13.2' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.14.0' } From 63099ca0c8e2f44ff62558307a1398a3b9cbb074 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 09:40:37 +0000 Subject: [PATCH 0358/4969] Bump assertj-core from 3.13.2 to 3.14.0 in /modules/neo4j (#2006) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.13.2 to 3.14.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.13.2...assertj-core-3.14.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 4889196ccef..00e1e36f8b7 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -30,5 +30,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.13.2' + testCompile 'org.assertj:assertj-core:3.14.0' } From eb69320384a8c2988f17907b297760a0d4cf0167 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 09:48:44 +0000 Subject: [PATCH 0359/4969] =?UTF-8?q?Bump=20assertj-core=20from=203.13.2?= =?UTF-8?q?=20to=203.14.0=20in=20/modules/database-co=E2=80=A6=20(#2007)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.13.2 to 3.14.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.13.2...assertj-core-3.14.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 7c820909d61..ea3e0b07360 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.13.2' + testCompile 'org.assertj:assertj-core:3.14.0' } From 0940e0caa58a44e902c2d0345fc72eb99ba4f997 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 09:49:13 +0000 Subject: [PATCH 0360/4969] Bump kafka-clients from 2.3.0 to 2.3.1 in /modules/kafka (#2002) Bumps kafka-clients from 2.3.0 to 2.3.1. Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 9d86482cf2f..f53c428886f 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.3.0' + testCompile 'org.apache.kafka:kafka-clients:2.3.1' testCompile 'org.assertj:assertj-core:3.13.2' testCompile 'com.google.guava:guava:23.0' } From 5b24a298fad5cc3f432c7a7627d1c3d43a0c01c6 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 09:49:40 +0000 Subject: [PATCH 0361/4969] Bump assertj-core from 3.13.2 to 3.14.0 in /core (#2005) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.13.2 to 3.14.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.13.2...assertj-core-3.14.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 2b631f46bce..a580d73c340 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -115,12 +115,12 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.13.2' + testCompile 'org.assertj:assertj-core:3.14.0' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' - jarFileTestCompile 'org.assertj:assertj-core:3.12.2' + jarFileTestCompile 'org.assertj:assertj-core:3.14.0' jarFileTestCompile 'org.ow2.asm:asm-debug-all:5.2' } From 3725b791d11d0251e3e3b900b94a5a2b4003c2be Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 11:12:47 +0000 Subject: [PATCH 0362/4969] Bump assertj-core from 3.13.2 to 3.14.0 in /modules/kafka (#2008) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index f53c428886f..d9d7c20ca4a 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.3.1' - testCompile 'org.assertj:assertj-core:3.13.2' + testCompile 'org.assertj:assertj-core:3.14.0' testCompile 'com.google.guava:guava:23.0' } From c5c24a55e62e4610c23adbd7a30138b0ee4045b9 Mon Sep 17 00:00:00 2001 From: David Harris Date: Wed, 30 Oct 2019 08:44:58 -0600 Subject: [PATCH 0363/4969] Slf4jLogConsumer improvements (#1986) * Adds support for MDC in Slf4jLogConsumer * Uses SLF4J levels instead of including the level as part of the message * make separation of output streams to different log levels configurable * use `with` prefix on method --- .../containers/output/Slf4jLogConsumer.java | 65 ++++++++++++++++--- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java b/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java index 26b017d4a36..a274cd63004 100644 --- a/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java @@ -1,16 +1,27 @@ package org.testcontainers.containers.output; +import java.util.HashMap; +import java.util.Map; + import org.slf4j.Logger; +import org.slf4j.MDC; /** * A consumer for container output that logs output to an SLF4J logger. */ public class Slf4jLogConsumer extends BaseConsumer { private final Logger logger; + private final Map mdc = new HashMap<>(); + private boolean separateOutputStreams; private String prefix = ""; public Slf4jLogConsumer(Logger logger) { + this(logger, false); + } + + public Slf4jLogConsumer(Logger logger, boolean separateOutputStreams) { this.logger = logger; + this.separateOutputStreams = separateOutputStreams; } public Slf4jLogConsumer withPrefix(String prefix) { @@ -18,21 +29,57 @@ public Slf4jLogConsumer withPrefix(String prefix) { return this; } + public Slf4jLogConsumer withMdc(String key, String value) { + mdc.put(key, value); + return this; + } + + public Slf4jLogConsumer withMdc(Map mdc) { + this.mdc.putAll(mdc); + return this; + } + + public Slf4jLogConsumer withSeparateOutputStreams() { + this.separateOutputStreams = true; + return this; + } + @Override public void accept(OutputFrame outputFrame) { OutputFrame.OutputType outputType = outputFrame.getType(); String utf8String = outputFrame.getUtf8String(); utf8String = utf8String.replaceAll(FrameConsumerResultCallback.LINE_BREAK_AT_END_REGEX, ""); - switch (outputType) { - case END: - break; - case STDOUT: - case STDERR: - logger.info("{}{}: {}", prefix, outputType, utf8String); - break; - default: - throw new IllegalArgumentException("Unexpected outputType " + outputType); + + Map originalMdc = MDC.getCopyOfContextMap(); + MDC.setContextMap(mdc); + try { + switch (outputType) { + case END: + break; + case STDOUT: + if (separateOutputStreams) { + logger.info("{}{}", prefix.isEmpty() ? "" : (prefix + ": "), utf8String); + } else { + logger.info("{}{}: {}", prefix, outputType, utf8String); + } + break; + case STDERR: + if (separateOutputStreams) { + logger.error("{}{}", prefix.isEmpty() ? "" : (prefix + ": "), utf8String); + } else { + logger.info("{}{}: {}", prefix, outputType, utf8String); + } + break; + default: + throw new IllegalArgumentException("Unexpected outputType " + outputType); + } + } finally { + if (originalMdc == null) { + MDC.clear(); + } else { + MDC.setContextMap(originalMdc); + } } } } From a2ecd4b813aba905eaa56159a17e2ec0820d93d9 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 30 Oct 2019 14:47:04 +0000 Subject: [PATCH 0364/4969] Slf4j log consumer improvements - add docs (#2016) --- docs/features/container_logs.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/features/container_logs.md b/docs/features/container_logs.md index a9e2832eb70..d603981059a 100644 --- a/docs/features/container_logs.md +++ b/docs/features/container_logs.md @@ -36,6 +36,25 @@ Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER); container.followOutput(logConsumer); ``` +By default both standard out and standard error will both be emitted at INFO level. +Standard error may be emitted at ERROR level, if desired: + +```java +Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log).withSeparateOutputStreams() +``` + +The [Mapped Diagnostic Context (MDC)](http://logback.qos.ch/manual/mdc.html) for emitted messages may be configured using the `withMdc(...)` option: + +```java +Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log).withMdc("key", "value") +``` + +or using an existing map of key-value pairs: + +```java +Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log).withMdc(map) +``` + ### Capturing container output as a String To stream logs live or customize the decoding, `ToStringConsumer` may be used: From a753bb1bd1aa132ac89463393a1b9c037197ec77 Mon Sep 17 00:00:00 2001 From: Yuri Orlov Date: Wed, 30 Oct 2019 17:47:37 +0300 Subject: [PATCH 0365/4969] Small code style fix (#2004) Co-authored-by: Richard North --- .../java/org/testcontainers/utility/CommandLine.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/CommandLine.java b/core/src/main/java/org/testcontainers/utility/CommandLine.java index 65788357898..a217823c40f 100644 --- a/core/src/main/java/org/testcontainers/utility/CommandLine.java +++ b/core/src/main/java/org/testcontainers/utility/CommandLine.java @@ -35,12 +35,11 @@ public static String runShellCommand(String... command) { LOGGER.debug("Executing shell command: `{}`", joinedCommand); try { - ProcessResult result; - result = new ProcessExecutor() - .command(command) - .readOutput(true) - .exitValueNormal() - .execute(); + ProcessResult result = new ProcessExecutor() + .command(command) + .readOutput(true) + .exitValueNormal() + .execute(); return result.outputUTF8().trim(); } catch (IOException | InterruptedException | TimeoutException | InvalidExitValueException e) { From 9a31ab351b3697dd29369f82b504c3fc43339de8 Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Wed, 30 Oct 2019 15:50:22 +0100 Subject: [PATCH 0366/4969] Fix vault module, add new test with java client v2 (#1791) * fix vault module, add new test with java client (cherry picked from commit 8931f8643bdda8edc5318b76ea5f27f9cf98d271) * adds test for try with resource adds tests for default constructor sets default image to vault:latest * Update VaultContainer.java * Update VaultContainer.java * Update VaultClientTest.java * Update VaultContainer.java * Update VaultContainerTest.java * fix vault cli test * Update modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java Co-Authored-By: Richard North * * Use health endpoint for discovering vault readiness * Move customizations to constructor to allow overrides * Use a single startup attempt, as 1 should be sufficient Co-authored-by: Roberto Franchini Co-authored-by: Sergei Egorov Co-authored-by: Richard North --- modules/vault/build.gradle | 3 + .../testcontainers/vault/VaultContainer.java | 66 ++++++++----------- .../testcontainers/vault/VaultClientTest.java | 58 ++++++++++++++++ .../vault/VaultContainerTest.java | 63 +++++++++--------- 4 files changed, 118 insertions(+), 72 deletions(-) create mode 100644 modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index b37a74602ff..052446bef6f 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -3,5 +3,8 @@ description = "Testcontainers :: Vault" dependencies { compile project(':testcontainers') + testCompile 'com.bettercloud:vault-java-driver:4.0.0' testCompile 'io.rest-assured:rest-assured:4.1.2' + testCompile 'org.assertj:assertj-core:3.12.0' + } diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java index 3f0f7684e82..ac4e730adb3 100644 --- a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java +++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java @@ -2,11 +2,10 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.traits.LinkableContainer; +import org.testcontainers.containers.wait.strategy.Wait; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,33 +17,30 @@ * GenericContainer subclass for Vault specific configuration and features. The main feature is the * withSecretInVault method, where users can specify which secrets to be pre-loaded into Vault for * their specific test scenario. - * + *

* Other helpful features include the withVaultPort, and withVaultToken methods for convenience. */ -public class VaultContainer> extends GenericContainer - implements LinkableContainer { +public class VaultContainer> extends GenericContainer { - private static final String VAULT_PORT = "8200"; - - private boolean vaultPortRequested = false; + private static final int VAULT_PORT = 8200; private Map> secretsMap = new HashMap<>(); + private int port = VAULT_PORT; + public VaultContainer() { - this("vault:0.7.0"); + this("vault:1.1.3"); } public VaultContainer(String dockerImageName) { super(dockerImageName); - } - @Override - protected void configure() { - setStartupAttempts(3); + // Use the vault healthcheck endpoint to check for readiness, per https://www.vaultproject.io/api/system/health.html + setWaitStrategy(Wait.forHttp("/v1/sys/health").forStatusCode(200)); + withCreateContainerCmdModifier(cmd -> cmd.withCapAdd(IPC_LOCK)); - if(!isVaultPortRequested()){ - withEnv("VAULT_ADDR", "http://0.0.0.0:" + VAULT_PORT); - } + withEnv("VAULT_ADDR", "http://0.0.0.0:" + port); + withExposedPorts(port); } @Override @@ -53,11 +49,10 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { } private void addSecrets() { - if(!secretsMap.isEmpty()){ + if (!secretsMap.isEmpty()) { try { this.execInContainer(buildExecCommand(secretsMap)).getStdout().contains("Success"); - } - catch (IOException | InterruptedException e) { + } catch (IOException | InterruptedException e) { logger().error("Failed to add these secrets {} into Vault via exec command. Exception message: {}", secretsMap, e.getMessage()); } } @@ -66,10 +61,10 @@ private void addSecrets() { private String[] buildExecCommand(Map> map) { StringBuilder stringBuilder = new StringBuilder(); map.forEach((path, secrets) -> { - stringBuilder.append(" && vault write " + path); + stringBuilder.append(" && vault kv put " + path); secrets.forEach(item -> stringBuilder.append(" " + item)); }); - return new String[] { "/bin/sh", "-c", stringBuilder.toString().substring(4)}; + return new String[]{"/bin/sh", "-c", stringBuilder.toString().substring(4)}; } /** @@ -89,45 +84,36 @@ public SELF withVaultToken(String token) { * * @param port the port number you want to have the Vault container listen on for tests. * @return this + * @deprecated the exposed port will be randomized automatically. As calling this method provides no additional value, you are recommended to remove the call. getFirstMappedPort() may be used to obtain the listening vault port. */ - public SELF withVaultPort(int port){ - setVaultPortRequested(true); - String vaultPort = String.valueOf(port); - withEnv("VAULT_ADDR", "http://0.0.0.0:" + VAULT_PORT); - setPortBindings(Arrays.asList(vaultPort + ":" + VAULT_PORT)); + @Deprecated + public SELF withVaultPort(int port) { + this.port = port; return self(); } /** * Pre-loads secrets into Vault container. User may specify one or more secrets and all will be added to each path * that is specified. Thus this can be called more than once for multiple paths to be added to Vault. - * + *

* The secrets are added to vault directly after the container is up via the * {@link #addSecrets() addSecrets}, called from {@link #containerIsStarted(InspectContainerResponse) containerIsStarted} * - * @param path specific Vault path to store specified secrets - * @param firstSecret first secret to add to specifed path + * @param path specific Vault path to store specified secrets + * @param firstSecret first secret to add to specifed path * @param remainingSecrets var args list of secrets to add to specified path * @return this */ public SELF withSecretInVault(String path, String firstSecret, String... remainingSecrets) { List list = new ArrayList<>(); list.add(firstSecret); - for(String secret : remainingSecrets) { + for (String secret : remainingSecrets) { list.add(secret); } if (secretsMap.containsKey(path)) { list.addAll(list); } - secretsMap.putIfAbsent(path,list); + secretsMap.putIfAbsent(path, list); return self(); } - - private void setVaultPortRequested(boolean vaultPortRequested) { - this.vaultPortRequested = vaultPortRequested; - } - - private boolean isVaultPortRequested() { - return vaultPortRequested; - } -} \ No newline at end of file +} diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java new file mode 100644 index 00000000000..8091980d234 --- /dev/null +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java @@ -0,0 +1,58 @@ +package org.testcontainers.vault; + +import com.bettercloud.vault.Vault; +import com.bettercloud.vault.VaultConfig; +import com.bettercloud.vault.VaultException; +import com.bettercloud.vault.response.LogicalResponse; +import org.junit.Test; +import org.testcontainers.containers.wait.strategy.Wait; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class VaultClientTest { + + private static final String VAULT_TOKEN = "my-root-token"; + + @Test + public void writeAndReadMultipleValues() throws VaultException { + try ( + VaultContainer vaultContainer = new VaultContainer<>() + .withVaultToken(VAULT_TOKEN) + ) { + + vaultContainer.start(); + + final VaultConfig config = new VaultConfig() + .address("http://" + vaultContainer.getContainerIpAddress() + ":" + vaultContainer.getFirstMappedPort()) + .token(VAULT_TOKEN) + .build(); + + final Vault vault = new Vault(config); + + final Map secrets = new HashMap<>(); + secrets.put("value", "world"); + secrets.put("other_value", "another world"); + + // Write operation + final LogicalResponse writeResponse = vault.logical() + .write("secret/hello", secrets); + + assertThat(writeResponse.getRestResponse().getStatus()).isEqualTo(200); + + // Read operation + final Map value = vault.logical() + .read("secret/hello") + .getData(); + + + assertThat(value) + .containsEntry("value", "world") + .containsEntry("other_value", "another world"); + + } + + } +} diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java index 5e1c55b33ac..fae9209c8e7 100644 --- a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java @@ -3,13 +3,11 @@ import org.junit.ClassRule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.Wait; import java.io.IOException; import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; /** @@ -18,32 +16,31 @@ */ public class VaultContainerTest { - private static final int VAULT_PORT = 8201; //using non-default port to show other ports can be passed besides 8200 - private static final String VAULT_TOKEN = "my-root-token"; @ClassRule public static VaultContainer vaultContainer = new VaultContainer<>() - .withVaultToken(VAULT_TOKEN) - .withVaultPort(VAULT_PORT) - .withSecretInVault("secret/testing1", "top_secret=password123") - .withSecretInVault("secret/testing2", "secret_one=password1", - "secret_two=password2", "secret_three=password3", "secret_three=password3", - "secret_four=password4") - .waitingFor(Wait.forHttp("/v1/secret/testing1").forStatusCode(400)); + .withVaultToken(VAULT_TOKEN) + .withSecretInVault("secret/testing1", "top_secret=password123") + .withSecretInVault("secret/testing2", + "secret_one=password1", + "secret_two=password2", + "secret_three=password3", + "secret_three=password3", + "secret_four=password4"); @Test public void readFirstSecretPathWithCli() throws IOException, InterruptedException { - GenericContainer.ExecResult result = vaultContainer.execInContainer("vault", - "read", "-field=top_secret", "secret/testing1"); - assertThat(result.getStdout(), containsString("password123")); + GenericContainer.ExecResult result = vaultContainer.execInContainer("vault", "kv", "get", "-format=json", "secret/testing1"); + final String output = result.getStdout().replaceAll("\\r?\\n", ""); + assertThat(output, containsString("password123")); } @Test public void readSecondSecretPathWithCli() throws IOException, InterruptedException { - GenericContainer.ExecResult result = vaultContainer.execInContainer("vault", - "read", "secret/testing2"); - String output = result.getStdout(); + GenericContainer.ExecResult result = vaultContainer.execInContainer("vault", "kv", "get", "-format=json", "secret/testing2"); + final String output = result.getStdout().replaceAll("\\r?\\n", ""); + System.out.println("output = " + output); assertThat(output, containsString("password1")); assertThat(output, containsString("password2")); assertThat(output, containsString("password3")); @@ -54,26 +51,28 @@ public void readSecondSecretPathWithCli() throws IOException, InterruptedExcepti public void readFirstSecretPathOverHttpApi() throws InterruptedException { given(). header("X-Vault-Token", VAULT_TOKEN). - when(). - get("http://"+getHostAndPort()+"/v1/secret/testing1"). - then(). - assertThat().body("data.top_secret", equalTo("password123")); + when(). + get("http://" + getHostAndPort() + "/v1/secret/data/testing1"). + then(). + assertThat().body("data.data.top_secret", equalTo("password123")); } @Test - public void readSecondecretPathOverHttpApi() throws InterruptedException { + public void readSecondSecretPathOverHttpApi() throws InterruptedException { given(). header("X-Vault-Token", VAULT_TOKEN). - when(). - get("http://"+getHostAndPort()+"/v1/secret/testing2"). - then(). - assertThat().body("data.secret_one", containsString("password1")). - assertThat().body("data.secret_two", containsString("password2")). - assertThat().body("data.secret_three", containsString("password3")). - assertThat().body("data.secret_four", containsString("password4")); + when(). + get("http://" + getHostAndPort() + "/v1/secret/data/testing2"). + then(). + assertThat().body("data.data.secret_one", containsString("password1")). + assertThat().body("data.data.secret_two", containsString("password2")). + assertThat().body("data.data.secret_three", hasItem("password3")). + assertThat().body("data.data.secret_four", containsString("password4")); } - private String getHostAndPort(){ - return vaultContainer.getContainerIpAddress()+":"+vaultContainer.getMappedPort(8200); + private String getHostAndPort() { + return vaultContainer.getContainerIpAddress() + ":" + vaultContainer.getMappedPort(8200); } + + } From 6568a5a47d9de9c3480b0e5455045b7fa8af7091 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2019 09:16:07 +0000 Subject: [PATCH 0367/4969] Bump assertj-core from 3.12.0 to 3.14.0 in /modules/vault (#2018) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.12.0 to 3.14.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.12.0...assertj-core-3.14.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 052446bef6f..145cb86bdf2 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:4.0.0' testCompile 'io.rest-assured:rest-assured:4.1.2' - testCompile 'org.assertj:assertj-core:3.12.0' + testCompile 'org.assertj:assertj-core:3.14.0' } From 6d99da8f87c12cf455af9a1f7cad399f71268b21 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2019 09:16:24 +0000 Subject: [PATCH 0368/4969] Bump vault-java-driver from 4.0.0 to 5.0.0 in /modules/vault (#2019) Bumps [vault-java-driver](https://github.com/BetterCloud/vault-java-driver) from 4.0.0 to 5.0.0. - [Release notes](https://github.com/BetterCloud/vault-java-driver/releases) - [Commits](https://github.com/BetterCloud/vault-java-driver/compare/v4.0.0...v5.0.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 145cb86bdf2..55249f74fb0 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Vault" dependencies { compile project(':testcontainers') - testCompile 'com.bettercloud:vault-java-driver:4.0.0' + testCompile 'com.bettercloud:vault-java-driver:5.0.0' testCompile 'io.rest-assured:rest-assured:4.1.2' testCompile 'org.assertj:assertj-core:3.14.0' From 7ab24309e6821c22f90e3516ad4bcd8dd5c1a187 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2019 11:28:57 +0000 Subject: [PATCH 0369/4969] Bump jna-platform from 5.4.0 to 5.5.0 in /core (#2017) Bumps [jna-platform](https://github.com/java-native-access/jna) from 5.4.0 to 5.5.0. - [Release notes](https://github.com/java-native-access/jna/releases) - [Changelog](https://github.com/java-native-access/jna/blob/master/CHANGES.md) - [Commits](https://github.com/java-native-access/jna/compare/5.4.0...5.5.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index a580d73c340..d6b862852e3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -76,7 +76,7 @@ dependencies { exclude(group: "log4j", module: "log4j") } - compile "net.java.dev.jna:jna-platform:5.4.0" + compile "net.java.dev.jna:jna-platform:5.5.0" shaded ('org.scala-sbt.ipcsocket:ipcsocket:1.0.0') { exclude(group: "net.java.dev.jna") From 87bae54f236971f89b05a16e0e7d747eff0aa28d Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 2 Nov 2019 19:35:06 +0000 Subject: [PATCH 0370/4969] Fix docker image name parsing bugs (#2022) * Fix DockerImageName secondary constructor It was cutting down last char of registry name * Add comprehensive unit tests for parsing of image names * Fix bug * Reduce assumptions repeated in test * Switch to using parameterized tests --- .../utility/DockerImageName.java | 4 +- .../utility/DockerImageNameTest.java | 133 ++++++++++++++---- 2 files changed, 105 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/DockerImageName.java b/core/src/main/java/org/testcontainers/utility/DockerImageName.java index bd1c713e26a..d57f1044e80 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerImageName.java +++ b/core/src/main/java/org/testcontainers/utility/DockerImageName.java @@ -61,13 +61,13 @@ public DockerImageName(String name, String tag) { registry = ""; remoteName = name; } else { - registry = name.substring(0, slashIndex - 1); + registry = name.substring(0, slashIndex); remoteName = name.substring(slashIndex + 1); } if (tag.startsWith("sha256:")) { repo = remoteName; - versioning = new Sha256Versioning(tag); + versioning = new Sha256Versioning(tag.replace("sha256:", "")); } else { repo = remoteName; versioning = new TagVersioning(tag); diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index caef1bcf9ec..37d2472949f 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -1,46 +1,119 @@ package org.testcontainers.utility; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.rnorth.visibleassertions.VisibleAssertions; -import static org.junit.Assert.fail; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +@RunWith(Enclosed.class) public class DockerImageNameTest { - @Test - public void validNames() { - testValid("myname:latest"); - testValid("myname:latest"); - testValid("repo/my-name:1.0"); - testValid("repo.foo.com:1234/my-name:1.0"); - testValid("repo.foo.com/my-name:1.0"); - testValid("repo.foo.com:1234/repo_here/my-name:1.0"); - testValid("repo.foo.com:1234/repo-here/my-name@sha256:1234abcd1234abcd1234abcd1234abcd"); - testValid("repo.foo.com:1234/my-name@sha256:1234abcd1234abcd1234abcd1234abcd"); - testValid("1.2.3.4/my-name:1.0"); - testValid("1.2.3.4:1234/my-name:1.0"); - testValid("1.2.3.4/repo-here/my-name:1.0"); - testValid("1.2.3.4:1234/repo-here/my-name:1.0"); - } + @RunWith(Parameterized.class) + public static class ValidNames { + + @Parameterized.Parameters(name = "{0}") + public static String[] getNames() { + return new String[]{"myname:latest", + "myname:latest", + "repo/my-name:1.0", + "registry.foo.com:1234/my-name:1.0", + "registry.foo.com/my-name:1.0", + "registry.foo.com:1234/repo_here/my-name:1.0", + "registry.foo.com:1234/repo-here/my-name@sha256:1234abcd1234abcd1234abcd1234abcd", + "registry.foo.com:1234/my-name@sha256:1234abcd1234abcd1234abcd1234abcd", + "1.2.3.4/my-name:1.0", + "1.2.3.4:1234/my-name:1.0", + "1.2.3.4/repo-here/my-name:1.0", + "1.2.3.4:1234/repo-here/my-name:1.0"}; + } - @Test - public void invalidNames() { - testInvalid(":latest"); - testInvalid("/myname:latest"); - testInvalid("/myname@sha256:latest"); - testInvalid("/myname@sha256:gggggggggggggggggggggggggggggggg"); - testInvalid("repo:notaport/myname:latest"); + @Parameterized.Parameter + public String imageName; + + @Test + public void testValidNameAccepted() { + new DockerImageName(imageName).assertValid(); + } } - private void testValid(String s) { - new DockerImageName(s).assertValid(); + @RunWith(Parameterized.class) + public static class InvalidNames { + + @Parameterized.Parameters(name = "{0}") + public static String[] getNames() { + return new String[]{":latest", + "/myname:latest", + "/myname@sha256:latest", + "/myname@sha256:gggggggggggggggggggggggggggggggg", + "repo:notaport/myname:latest"}; + } + + @Parameterized.Parameter + public String imageName; + + @Test(expected = IllegalArgumentException.class) + public void testInvalidNameRejected() { + new DockerImageName(imageName).assertValid(); + } } - private void testInvalid(String myname) { - try { - new DockerImageName(myname).assertValid(); - fail(); - } catch (IllegalArgumentException expected) { + @RunWith(Parameterized.class) + public static class Parsing { + + @Parameterized.Parameters(name = "{0}{1}{2}{3}{4}") + public static String[][] getNames() { + return new String[][]{ + {"", "", "myname", ":", "latest"}, + {"", "", "repo/myname", ":", "latest"}, + {"registry.foo.com:1234", "/", "my-name", ":", "1.0"}, + {"registry.foo.com", "/", "my-name", ":", "1.0"}, + {"registry.foo.com:1234", "/", "repo_here/my-name", ":", "1.0"}, + {"1.2.3.4:1234", "/", "repo_here/my-name", ":", "1.0"}, + {"1.2.3.4:1234", "/", "my-name", ":", "1.0"}, + {"", "", "myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, + {"", "", "repo/myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, + {"registry.foo.com:1234", "/", "repo-here/my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, + {"registry.foo.com:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, + {"1.2.3.4", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, + {"1.2.3.4:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, + {"1.2.3.4", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, + {"1.2.3.4:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"} + }; + } + + @Parameterized.Parameter(0) + public String registry; + @Parameterized.Parameter(1) + public String registrySeparator; + @Parameterized.Parameter(2) + public String repo; + @Parameterized.Parameter(3) + public String versionSeparator; + @Parameterized.Parameter(4) + public String version; + + @Test + public void testParsing() { + final String unversionedPart = registry + registrySeparator + repo; + final String combined = unversionedPart + versionSeparator + version; + + VisibleAssertions.context("For " + combined); + VisibleAssertions.context("Using single-arg constructor:", 2); + + final DockerImageName imageName = new DockerImageName(combined); + assertEquals(combined + " has registry address: " + registry, registry, imageName.getRegistry()); + assertEquals(combined + " has unversioned part: " + unversionedPart, unversionedPart, imageName.getUnversionedPart()); + assertEquals(combined + " has version part: " + version, version, imageName.getVersionPart()); + + VisibleAssertions.context("Using two-arg constructor:", 2); + final DockerImageName imageNameFromSecondaryConstructor = new DockerImageName(unversionedPart, version); + assertEquals(combined + " has registry address: " + registry, registry, imageNameFromSecondaryConstructor.getRegistry()); + assertEquals(combined + " has unversioned part: " + unversionedPart, unversionedPart, imageNameFromSecondaryConstructor.getUnversionedPart()); + assertEquals(combined + " has version part: " + version, version, imageNameFromSecondaryConstructor.getVersionPart()); } } } From 033f51d531dcb2410d3f560b1430ad01cd4c93b0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2019 19:32:39 +0100 Subject: [PATCH 0371/4969] Bump slf4j-api from 1.7.28 to 1.7.29 in /examples (#2031) Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.28 to 1.7.29. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/commits) Signed-off-by: dependabot-preview[bot] --- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 1680aa3b963..eb10aed7159 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { jcenter() } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.28' + compileOnly 'org.slf4j:slf4j-api:1.7.29' implementation 'com.squareup.okhttp3:okhttp:3.14.4' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.8' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index e339878813c..8b133f0cc1b 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.28' + compileOnly 'org.slf4j:slf4j-api:1.7.29' implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 727c1649b07..a95000e8d71 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.28' + compileOnly 'org.slf4j:slf4j-api:1.7.29' implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 250eb755632..6cb2e6d77c5 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:3.1.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:1.7.28' + compileOnly 'org.slf4j:slf4j-api:1.7.29' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:testcontainers' From 9b1077bb86ee6bad919915aeb8e70504101c77ab Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Wed, 6 Nov 2019 12:56:29 +0100 Subject: [PATCH 0372/4969] Compare to `0` instead of expecting `1` in `TestEnvironmentTest` (#2036) Future-proofing `TestEnvironmentTest` by making sure we rely on `Comparable#compareTo` contract and not on `ComparableVersion`'s implementation details. --- .../java/org/testcontainers/utility/TestEnvironmentTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java b/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java index f34df95137c..de97d100a39 100644 --- a/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java @@ -11,7 +11,7 @@ public class TestEnvironmentTest { @Test public void testCompareVersionGreaterThanSameMajor() { - assertTrue("1.22 > 1.20", new ComparableVersion("1.22").compareTo(new ComparableVersion("1.20")) == 1); + assertTrue("1.22 > 1.20", new ComparableVersion("1.22").compareTo(new ComparableVersion("1.20")) > 0); } @Test @@ -21,7 +21,7 @@ public void testCompareVersionEqual() { @Test public void testCompareVersionGreaterThan() { - assertTrue("2.10 > 1.20", new ComparableVersion("2.10").compareTo(new ComparableVersion("1.20")) == 1); + assertTrue("2.10 > 1.20", new ComparableVersion("2.10").compareTo(new ComparableVersion("1.20")) > 0); } @Test From 3b308b862fde3afafb6a78b51106e96011ae541d Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 9 Nov 2019 08:26:16 +0000 Subject: [PATCH 0373/4969] Localstack support for HOSTNAME_EXTERNAL (#1891) * Infer sensible default for HOSTNAME_EXTERNAL Co-authored-by: CauchyPeano <431522+CauchyPeano@users.noreply.github.com> * Restore import style * Update modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java Co-Authored-By: Sergei Egorov * Use nested containers for Localstack tests --- .editorconfig | 8 + .../containers/GenericContainer.java | 1 + docs/modules/localstack.md | 49 ++++-- modules/localstack/build.gradle | 4 +- .../localstack/LocalStackContainer.java | 19 +++ .../localstack/LocalstackContainerTest.java | 152 ++++++++++++++++++ .../localstack/SimpleLocalstackTest.java | 93 ----------- 7 files changed, 217 insertions(+), 109 deletions(-) create mode 100644 modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java delete mode 100644 modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java diff --git a/.editorconfig b/.editorconfig index ce20a2be466..4d023ed18d5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,3 +14,11 @@ trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false + +[*.java] +indent_style = space +indent_size = 4 +# Never use star imports +ij_java_names_count_to_use_import_on_demand = 99 +ij_java_class_count_to_use_import_on_demand = 99 +ij_java_layout_static_imports_separately = true \ No newline at end of file diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index f17e8dfd0b2..c5df0d4fea1 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -616,6 +616,7 @@ private void applyConfiguration(CreateContainerCmd createCommand) { } String[] envArray = env.entrySet().stream() + .filter(it -> it.getValue() != null) .map(it -> it.getKey() + "=" + it.getValue()) .toArray(String[]::new); createCommand.withEnv(envArray); diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index 7062b684931..bf520b1fac6 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -7,24 +7,45 @@ Testcontainers module for the Atlassian's [LocalStack](https://github.com/locals Running LocalStack as a stand-in for AWS S3 during a test: ```java -public class SomeTest { +@Rule +public LocalStackContainer localstack = new LocalStackContainer() + .withServices(S3); - @Rule - public LocalStackContainer localstack = new LocalStackContainer() - .withServices(S3); +@Test +public void someTestMethod() { + AmazonS3 s3 = AmazonS3ClientBuilder + .standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) + .withCredentials(localstack.getDefaultCredentialsProvider()) + .build(); - @Test - public void someTestMethod() { - AmazonS3 s3 = AmazonS3ClientBuilder - .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) - .withCredentials(localstack.getDefaultCredentialsProvider()) - .build(); - - s3.createBucket("foo"); - s3.putObject("foo", "bar", "baz"); + s3.createBucket("foo"); + s3.putObject("foo", "bar", "baz"); ``` +Environment variables listed in [Localstack's README](https://github.com/localstack/localstack#configurations) may be used to customize Localstack's configuration. +Use the `.withEnv(key, value)` method on `LocalStackContainer` to apply configuration settings. + +## `HOSTNAME_EXTERNAL` and hostname-sensitive services + +Some Localstack APIs, such as SQS, require the container to be aware of the hostname that it is accessible on - for example, for construction of queue URLs in responses. + +Testcontainers will inform Localstack of the best hostname automatically, using the `HOSTNAME_EXTERNAL` environment variable: + +* when running the Localstack container directly without a custom network defined, it is expected that all calls to the container will be from the test host. As such, the container address will be used (typically localhost or the address where the Docker daemon is running). + + + [Localstack container running without a custom network](../../modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java) inside_block:without_network + + +* when running the Localstack container [with a custom network defined](/features/networking/#advanced-networking), it is expected that all calls to the container will be **from other containers on that network**. `HOSTNAME_EXTERNAL` will be set to the *last* network alias that has been configured for the Localstack container. + + + [Localstack container running without a custom network](../../modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java) inside_block:with_network + + +* Other usage scenarios, such as where the Localstack container is used from both the test host and containers on a custom network are not automatically supported. If you have this use case, you should set `HOSTNAME_EXTERNAL` manually. + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index eacbc7bb5ae..1ee679abf98 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.479' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.479' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.636' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' } diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index a5005abe239..36eaacba89b 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -30,6 +30,7 @@ public class LocalStackContainer extends GenericContainer { public static final String VERSION = "0.9.4"; + private static final String HOSTNAME_EXTERNAL_ENV_VAR = "HOSTNAME_EXTERNAL"; private final List services = new ArrayList<>(); @@ -52,6 +53,19 @@ protected void configure() { withEnv("SERVICES", services.stream().map(Service::getLocalStackName).collect(Collectors.joining(","))); + String hostnameExternalReason; + if (getEnvMap().containsKey(HOSTNAME_EXTERNAL_ENV_VAR)) { + // do nothing + hostnameExternalReason = "explicitly as environment variable"; + } else if (getNetwork() != null && getNetworkAliases() != null && getNetworkAliases().size() >= 1) { + withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getNetworkAliases().get(getNetworkAliases().size() - 1)); // use the last network alias set + hostnameExternalReason = "to match last network alias on container with non-default network"; + } else { + withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getContainerIpAddress()); + hostnameExternalReason = "to match host-routable address for container"; + } + logger().info("{} environment variable set to {} ({})", HOSTNAME_EXTERNAL_ENV_VAR, getEnvMap().get(HOSTNAME_EXTERNAL_ENV_VAR), hostnameExternalReason); + for (Service service : services) { addExposedPort(service.getPort()); } @@ -76,6 +90,11 @@ public LocalStackContainer withServices(Service... services) { .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); + * + *

Please note that this method is only intended to be used for configuring AWS SDK clients + * that are running on the test host. If other containers need to call this one, they should be configured + * specifically to do so using a Docker network and appropriate addressing.

+ * * @param service the service that is to be accessed * @return an {@link AwsClientBuilder.EndpointConfiguration} */ diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java new file mode 100644 index 00000000000..1b222c0fbc7 --- /dev/null +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -0,0 +1,152 @@ +package org.testcontainers.containers.localstack; + + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.Bucket; +import com.amazonaws.services.s3.model.ObjectListing; +import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.sqs.AmazonSQS; +import com.amazonaws.services.sqs.AmazonSQSClientBuilder; +import com.amazonaws.services.sqs.model.CreateQueueResult; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.Container; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; + +/** + * Tests for Localstack Container, used both in bridge network (exposed to host) and docker network modes. + *

+ * These tests attempt simple interactions with the container to verify behaviour. The bridge network tests use the + * Java AWS SDK, whereas the docker network tests use an AWS CLI container within the network, to simulate usage of + * Localstack from within a Docker network. + */ +@Slf4j +@RunWith(Enclosed.class) +public class LocalstackContainerTest { + + public static class WithoutNetwork { + + // without_network { + @ClassRule + public static LocalStackContainer localstack = new LocalStackContainer() + .withServices(S3, SQS); + // } + + @Test + public void s3TestOverBridgeNetwork() throws IOException { + AmazonS3 s3 = AmazonS3ClientBuilder + .standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) + .withCredentials(localstack.getDefaultCredentialsProvider()) + .build(); + + s3.createBucket("foo"); + s3.putObject("foo", "bar", "baz"); + + final List buckets = s3.listBuckets(); + assertEquals("The created bucket is present", 1, buckets.size()); + final Bucket bucket = buckets.get(0); + + assertEquals("The created bucket has the right name", "foo", bucket.getName()); + assertEquals("The created bucket has the right name", "foo", bucket.getName()); + + final ObjectListing objectListing = s3.listObjects("foo"); + assertEquals("The created bucket has 1 item in it", 1, objectListing.getObjectSummaries().size()); + + final S3Object object = s3.getObject("foo", "bar"); + final String content = IOUtils.toString(object.getObjectContent(), Charset.forName("UTF-8")); + assertEquals("The object can be retrieved", "baz", content); + } + + @Test + public void sqsTestOverBridgeNetwork() { + AmazonSQS sqs = AmazonSQSClientBuilder.standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(SQS)) + .withCredentials(localstack.getDefaultCredentialsProvider()) + .build(); + + CreateQueueResult queueResult = sqs.createQueue("baz"); + String fooQueueUrl = queueResult.getQueueUrl(); + assertThat("Created queue has external hostname URL", fooQueueUrl, + containsString("http://" + DockerClientFactory.instance().dockerHostIpAddress() + ":" + localstack.getMappedPort(SQS.getPort()))); + + sqs.sendMessage(fooQueueUrl, "test"); + final long messageCount = sqs.receiveMessage(fooQueueUrl).getMessages().stream() + .filter(message -> message.getBody().equals("test")) + .count(); + assertEquals("the sent message can be received", 1L, messageCount); + } + } + + public static class WithNetwork { + // with_network { + private static Network network = Network.newNetwork(); + + @ClassRule + public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer() + .withNetwork(network) + .withNetworkAliases("notthis", "localstack") // the last alias is used for HOSTNAME_EXTERNAL + .withServices(S3, SQS); + // } + + @ClassRule + public static GenericContainer awsCliInDockerNetwork = new GenericContainer<>("atlassian/pipelines-awscli") + .withNetwork(network) + .withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("top")) + .withEnv("AWS_ACCESS_KEY_ID", "accesskey") + .withEnv("AWS_SECRET_ACCESS_KEY", "secretkey") + .withEnv("AWS_REGION", "eu-west-1"); + + + @Test + public void s3TestOverDockerNetwork() throws Exception { + runAwsCliAgainstDockerNetworkContainer("s3api create-bucket --bucket foo", S3.getPort()); + runAwsCliAgainstDockerNetworkContainer("s3api list-buckets", S3.getPort()); + runAwsCliAgainstDockerNetworkContainer("s3 ls s3://foo", S3.getPort()); + } + + @Test + public void sqsTestOverDockerNetwork() throws Exception { + final String queueCreationResponse = runAwsCliAgainstDockerNetworkContainer("sqs create-queue --queue-name baz", SQS.getPort()); + + assertThat("Created queue has external hostname URL", queueCreationResponse, + containsString("http://localstack:" + SQS.getPort())); + + runAwsCliAgainstDockerNetworkContainer( + String.format("sqs send-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz --message-body test", SQS.getPort(), SQS.getPort()), SQS.getPort()); + final String message = runAwsCliAgainstDockerNetworkContainer( + String.format("sqs receive-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz", SQS.getPort(), SQS.getPort()), SQS.getPort()); + + assertTrue("the sent message can be received", message.contains("\"Body\": \"test\"")); + } + + private String runAwsCliAgainstDockerNetworkContainer(String command, final int port) throws Exception { + final String[] commandParts = String.format("/usr/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", command, port).split(" "); + final Container.ExecResult execResult = awsCliInDockerNetwork.execInContainer(commandParts); + Assert.assertEquals(0, execResult.getExitCode()); + + final String logs = execResult.getStdout() + execResult.getStderr(); + log.info(logs); + return logs; + } + } +} diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java deleted file mode 100644 index f3495d2d8b6..00000000000 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/SimpleLocalstackTest.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.testcontainers.containers.localstack; - - -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import com.amazonaws.services.s3.model.Bucket; -import com.amazonaws.services.s3.model.ObjectListing; -import com.amazonaws.services.s3.model.S3Object; -import com.amazonaws.services.sqs.AmazonSQS; -import com.amazonaws.services.sqs.AmazonSQSClientBuilder; -import com.amazonaws.services.sqs.model.CreateQueueResult; -import com.amazonaws.services.sqs.model.Message; -import org.apache.commons.io.IOUtils; -import org.junit.ClassRule; -import org.junit.Test; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Set; - -import static java.util.stream.Collectors.toSet; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; - -/** - * The only tests that should go here are for those Localstack services that require special testcontainers code to work with them. - * For example, S3 needs a test to ensure special HTTP routing to the S3 container works. - */ -public class SimpleLocalstackTest { - - private static final String BUCKET_1 = "bucket1"; - private static final String BUCKET_2 = "bucket2"; - private static final String ITEM_KEY = "bar"; - private static final String DUMMY_CONTENT = "baz"; - - @ClassRule - public static LocalStackContainer localstack = new LocalStackContainer() - .withServices(S3, SQS); - - @Test - public void simpleS3Test() throws IOException { - AmazonS3 s3 = AmazonS3ClientBuilder - .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) - .withCredentials(localstack.getDefaultCredentialsProvider()) - .build(); - - s3.createBucket(BUCKET_1); - s3.putObject(BUCKET_1, ITEM_KEY, DUMMY_CONTENT); - - s3.createBucket(BUCKET_2); - s3.putObject(BUCKET_2, ITEM_KEY, DUMMY_CONTENT); - - final Set bucketNames = s3.listBuckets().stream() - .map(Bucket::getName) - .collect(toSet()); - assertTrue("The created buckets have the right name", - bucketNames.contains(BUCKET_1) && bucketNames.contains(BUCKET_2)); - - assertBucketContentsCorrect(s3, BUCKET_1); - assertBucketContentsCorrect(s3, BUCKET_2); - } - - private void assertBucketContentsCorrect(AmazonS3 s3, String bucketName) throws IOException { - final ObjectListing objectListing1 = s3.listObjects(bucketName); - assertEquals("The created bucket has 1 item in it", 1, objectListing1.getObjectSummaries().size()); - - final S3Object object = s3.getObject(bucketName, ITEM_KEY); - final String content = IOUtils.toString(object.getObjectContent(), StandardCharsets.UTF_8); - assertEquals("The object can be retrieved", DUMMY_CONTENT, content); - } - - @Test - public void simpleSQSTest() { - AmazonSQS sqs = AmazonSQSClientBuilder.standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(SQS)) - .withCredentials(localstack.getDefaultCredentialsProvider()) - .build(); - - CreateQueueResult queueResult = sqs.createQueue("baz"); - String queueUrl = queueResult.getQueueUrl(); - - sqs.sendMessage(queueUrl, "ping"); - - final List messages = sqs.receiveMessage(queueUrl).getMessages(); - - assertTrue("the message queue contains a message", messages.size() > 0); - assertEquals("the first message is the one we sent", "ping", messages.get(0).getBody()); - } -} From d62705a898d95d71c36d61f371fb8120f326323c Mon Sep 17 00:00:00 2001 From: Florian LOPES Date: Sat, 9 Nov 2019 09:27:04 +0100 Subject: [PATCH 0374/4969] Fix typo in index.md (#2043) --- docs/modules/databases/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index b0e5335b7e8..2511502f650 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -111,10 +111,10 @@ With this parameter database container will keep running even when there're no o Container can have `tmpfs` mounts for storing data in host memory. This is useful if you want to speed up your database tests. Be aware that the data will be lost when the container stops. -To pass this option to the container, add `TC_TMPFS` paramater to the URL as follows: +To pass this option to the container, add `TC_TMPFS` parameter to the URL as follows: `jdbc:tc:postgresql:9.6.8:///databasename?TC_TMPFS=/testtmpfs:rw` -If you need more than one option, seperate them by comma (e.g. `TC_TMPFS=key:value,key1:value1&other_parameters=foo`). +If you need more than one option, separate them by comma (e.g. `TC_TMPFS=key:value,key1:value1&other_parameters=foo`). For more information about `tmpfs` mount, see [the official Docker documentation](https://docs.docker.com/storage/tmpfs/). From 055f78323f584a9f8b3248196d5ca99fd3cc454f Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 9 Nov 2019 08:28:03 +0000 Subject: [PATCH 0375/4969] Add docker compose support for --build and --rmi options (#1625) * 924: Add docker compose support for --build and --rmi options * Fix bug with merge * Use standard enum style * Refactor test to verify removal of images * Fix param name * Switch to using parameterized tests Co-authored-by: Soner Dastan --- .../containers/DockerComposeContainer.java | 64 ++++++++++++- .../DockerComposeContainerWithBuildTest.java | 92 +++++++++++++++++++ .../resources/compose-build-test/Dockerfile | 3 + .../compose-build-test/docker-compose.yml | 6 ++ 4 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java create mode 100644 core/src/test/resources/compose-build-test/Dockerfile create mode 100644 core/src/test/resources/compose-build-test/docker-compose.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index b21e160d892..73628a19ad7 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -64,6 +64,7 @@ public class DockerComposeContainer> e private DockerClient dockerClient; private boolean localCompose; private boolean pull = true; + private boolean build = false; private boolean tailChildContainers; private String project; @@ -84,6 +85,7 @@ public class DockerComposeContainer> e * necessarily to containers that are spawned by Compose itself) */ private Map env = new HashMap<>(); + private RemoveImages removeImages; @Deprecated public DockerComposeContainer(File composeFile, String identifier) { @@ -170,11 +172,17 @@ public SELF withServices(@NonNull String... services) { private void createServices() { // Run the docker-compose container, which starts up the services - if(services.isEmpty()) { - runWithCompose("up -d"); - } else { - runWithCompose("up -d " + String.join(" ", services)); + String command = "up -d"; + + if (build) { + command += " --build"; + } + + if (!services.isEmpty()) { + command += " " + String.join(" ", services); } + + runWithCompose(command); } private void waitUntilServiceStarted() { @@ -326,7 +334,11 @@ public void stop() { // Kill the services using docker-compose try { - runWithCompose("down -v"); + String cmd = "down -v"; + if (removeImages != null) { + cmd += " --rmi " + removeImages.dockerRemoveImagesType(); + } + runWithCompose(cmd); // If we reach here then docker-compose down has cleared networks and containers; // we can unregister from ResourceReaper @@ -513,6 +525,26 @@ public SELF withLogConsumer(String serviceName, Consumer consumer) return self(); } + /** + * Whether to always build images before starting containers. + * + * @return this instance, for chaining + */ + public SELF withBuild(boolean build) { + this.build = build; + return self(); + } + + /** + * Remove images after containers shutdown. + * + * @return this instance, for chaining + */ + public SELF withRemoveImages(RemoveImages removeImages) { + this.removeImages = removeImages; + return self(); + } + private void followLogs(String containerId, Consumer consumer) { LogUtils.followOutput(DockerClientFactory.instance().client(), containerId, consumer); } @@ -524,6 +556,28 @@ private SELF self() { private String randomProjectId() { return identifier + Base58.randomString(6).toLowerCase(); } + + public enum RemoveImages { + /** + * Remove all images used by any service. + */ + ALL("all"), + + /** + * Remove only images that don't have a custom tag set by the `image` field. + */ + LOCAL("local"); + + private final String dockerRemoveImagesType; + + RemoveImages(final String dockerRemoveImagesType) { + this.dockerRemoveImagesType = dockerRemoveImagesType; + } + + public String dockerRemoveImagesType() { + return dockerRemoveImagesType; + } + } } interface DockerCompose { diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java new file mode 100644 index 00000000000..1b1efc878af --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java @@ -0,0 +1,92 @@ +package org.testcontainers.junit; + +import com.github.dockerjava.api.model.Container; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.DockerComposeContainer; + +import java.io.File; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.testcontainers.containers.DockerComposeContainer.RemoveImages.ALL; +import static org.testcontainers.containers.DockerComposeContainer.RemoveImages.LOCAL; + +@RunWith(Parameterized.class) +public class DockerComposeContainerWithBuildTest { + + public DockerComposeContainerWithBuildTest(final DockerComposeContainer.RemoveImages removeMode, + final boolean shouldBuiltImageBePresentAfterRunning, + final boolean shouldPulledImageBePresentAfterRunning) { + this.removeMode = removeMode; + this.shouldBuiltImageBePresentAfterRunning = shouldBuiltImageBePresentAfterRunning; + this.shouldPulledImageBePresentAfterRunning = shouldPulledImageBePresentAfterRunning; + } + + public final DockerComposeContainer.RemoveImages removeMode; + public final boolean shouldBuiltImageBePresentAfterRunning; + public final boolean shouldPulledImageBePresentAfterRunning; + + @Parameterized.Parameters(name = "removeMode = {0}") + public static Object[][] params() { + return new Object[][]{ + {null, true, true}, + {LOCAL, false, true}, + {ALL, false, false}, + }; + } + + @Test + public void performTest() { + final File composeFile = new File("src/test/resources/compose-build-test/docker-compose.yml"); + + final AtomicReference builtImageName = new AtomicReference<>(""); + final AtomicReference pulledImageName = new AtomicReference<>(""); + try (DockerComposeContainer environment = new DockerComposeContainer<>(composeFile) + .withExposedService("customredis", 6379) + .withBuild(true) + .withRemoveImages(removeMode)) { + + environment.start(); + + builtImageName.set(imageNameForRunningContainer("_customredis_1")); + final boolean isBuiltImagePresentWhileRunning = isImagePresent(builtImageName.get()); + assertEquals("the built image is present while running", true, isBuiltImagePresentWhileRunning); + + pulledImageName.set(imageNameForRunningContainer("_normalredis_1")); + final boolean isPulledImagePresentWhileRunning = isImagePresent(pulledImageName.get()); + assertEquals("the pulled image is present while running", true, isPulledImagePresentWhileRunning); + } + + Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { + final boolean isBuiltImagePresentAfterRunning = isImagePresent(builtImageName.get()); + assertEquals("the built image is not present after running", shouldBuiltImageBePresentAfterRunning, isBuiltImagePresentAfterRunning); + return null; + }); + + Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { + final boolean isPulledImagePresentAfterRunning = isImagePresent(pulledImageName.get()); + assertEquals("the pulled image is present after running", shouldPulledImageBePresentAfterRunning, isPulledImagePresentAfterRunning); + return null; + }); + } + + private String imageNameForRunningContainer(final String containerNameSuffix) { + return DockerClientFactory.instance().client().listContainersCmd().exec().stream() + .filter(it -> Stream.of(it.getNames()).anyMatch(name -> name.endsWith(containerNameSuffix))) + .findFirst() + .map(Container::getImage) + .orElseThrow(IllegalStateException::new); + } + + private boolean isImagePresent(final String imageName) { + return DockerClientFactory.instance().client().listImagesCmd().withImageNameFilter(imageName).exec().stream() + .findFirst() + .isPresent(); + } +} diff --git a/core/src/test/resources/compose-build-test/Dockerfile b/core/src/test/resources/compose-build-test/Dockerfile new file mode 100644 index 00000000000..521e2d23b80 --- /dev/null +++ b/core/src/test/resources/compose-build-test/Dockerfile @@ -0,0 +1,3 @@ +FROM redis + +CMD ["redis-server"] diff --git a/core/src/test/resources/compose-build-test/docker-compose.yml b/core/src/test/resources/compose-build-test/docker-compose.yml new file mode 100644 index 00000000000..333b2fa46f1 --- /dev/null +++ b/core/src/test/resources/compose-build-test/docker-compose.yml @@ -0,0 +1,6 @@ +version: '2.0' +services: + customredis: + build: . + normalredis: + image: redis:latest From fb9e7ef1c9aefd18a334708e33c2771760ab8c24 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2019 08:28:24 +0000 Subject: [PATCH 0376/4969] =?UTF-8?q?Bump=20org.springframework.boot=20fro?= =?UTF-8?q?m=202.2.0.RELEASE=20to=202.2.1.RELEA=E2=80=A6=20(#2042)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.2.0.RELEASE to 2.2.1.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.0.RELEASE...v2.2.1.RELEASE) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 2c15c3038ba..5386234dccb 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.0.RELEASE' + id 'org.springframework.boot' version '2.2.1.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index df18e6a5f03..2a67123fa03 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.0.RELEASE' + id 'org.springframework.boot' version '2.2.1.RELEASE' } apply plugin: 'io.spring.dependency-management' From e86fb093d80e7c9576f8063415861eb2dc30fa91 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2019 08:28:35 +0000 Subject: [PATCH 0377/4969] Bump mongo-java-driver from 3.11.1 to 3.11.2 in /core (#2035) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.11.1 to 3.11.2. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.11.1...r3.11.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d6b862852e3..1b037390956 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,7 +108,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.1.0' testCompile 'com.rabbitmq:amqp-client:5.7.3' - testCompile 'org.mongodb:mongo-java-driver:3.11.1' + testCompile 'org.mongodb:mongo-java-driver:3.11.2' testCompile ('org.mockito:mockito-core:3.1.0') { exclude(module: 'hamcrest-core') } From 84b86aff56efe8b1ff20dc29ad455b4116cd1092 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2019 08:28:44 +0000 Subject: [PATCH 0378/4969] Bump slf4j-api from 1.7.28 to 1.7.29 in /core (#2030) Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.28 to 1.7.29. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Kevin Wittek --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 1b037390956..9da3288d0c3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -57,7 +57,7 @@ project.tasks.check.dependsOn(jarFileTest) dependencies { compile 'junit:junit:4.12' - compile 'org.slf4j:slf4j-api:1.7.28' + compile 'org.slf4j:slf4j-api:1.7.29' compile 'org.jetbrains:annotations:17.0.0' compile 'javax.annotation:javax.annotation-api:1.3.2' compile 'org.apache.commons:commons-compress:1.19' From f3011b6cfaf058fef26583d259bad00f9103a2ea Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 9 Nov 2019 11:09:54 +0100 Subject: [PATCH 0379/4969] Check container's status if `WaitStrategy` fails. (#1837) * Check container's status if `WaitStrategy` fails. Fixes #1834 * Try "128Gb" * Update core/src/main/java/org/testcontainers/containers/GenericContainer.java Co-Authored-By: Richard North * Use `/dev/null` as dd's target, ignore startup check strategy * Achieve OOMKill in a way that works reliably on CI On CircleCI there were two problems: * `dd: /dev/urandom: Bad address` when `/dev/urandom` was used, which would cause exit code 1, not the desired OOMKill * Once worked-around, `dd` was only processing a partial block: ``` 0+1 records in 0+1 records out ``` I suspect that `dd` might internally be respecting, or suffering limited buffers due to the cgroup memory limit, though I'm not clear why this behaviour only appeared on CircleCI and Azure pipelines. * Limit loop * Allocate more memory to trigger the OOM killer * increase the memory even more --- .../containers/GenericContainer.java | 45 ++++++++++- .../containers/GenericContainerTest.java | 75 +++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/org/testcontainers/containers/GenericContainerTest.java diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index c5df0d4fea1..18c53f8b80f 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -7,6 +7,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.ContainerNetwork; import com.github.dockerjava.api.model.ExposedPort; @@ -69,7 +70,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; import java.nio.charset.Charset; import java.nio.file.Path; import java.time.Duration; @@ -397,11 +400,51 @@ private void tryStart(Instant startedAt) { } // Wait until the process within the container has become ready for use (e.g. listening on network, log message emitted, etc). - waitUntilContainerStarted(); + try { + waitUntilContainerStarted(); + } catch (Exception e) { + logger().debug("Wait strategy threw an exception", e); + InspectContainerResponse inspectContainerResponse = null; + try { + inspectContainerResponse = dockerClient.inspectContainerCmd(containerId).exec(); + } catch (NotFoundException notFoundException) { + logger().debug("Container {} not found", containerId, notFoundException); + } + + if (inspectContainerResponse == null) { + throw new IllegalStateException("Container is removed"); + } + + InspectContainerResponse.ContainerState state = inspectContainerResponse.getState(); + if (Boolean.TRUE.equals(state.getDead())) { + throw new IllegalStateException("Container is dead"); + } + + if (Boolean.TRUE.equals(state.getOOMKilled())) { + throw new IllegalStateException("Container crashed with out-of-memory (OOMKilled)"); + } + + String error = state.getError(); + if (!StringUtils.isBlank(error)) { + throw new IllegalStateException("Container crashed: " + error); + } + + if (!Boolean.TRUE.equals(state.getRunning())) { + throw new IllegalStateException("Container exited with code " + state.getExitCode()); + } + + throw e; + } logger().info("Container {} started in {}", dockerImageName, Duration.between(startedAt, Instant.now())); containerIsStarted(containerInfo); } catch (Exception e) { + if (e instanceof UndeclaredThrowableException && e.getCause() instanceof Exception) { + e = (Exception) e.getCause(); + } + if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) { + e = (Exception) e.getCause(); + } logger().error("Could not start container", e); if (containerId != null) { diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java new file mode 100644 index 00000000000..c69a3b69594 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -0,0 +1,75 @@ +package org.testcontainers.containers; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.InspectContainerResponse.ContainerState; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.experimental.FieldDefaults; +import org.apache.commons.io.FileUtils; +import org.junit.Test; +import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.containers.startupcheck.StartupCheckStrategy; +import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; + +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class GenericContainerTest { + + @Test + public void shouldReportOOMAfterWait() { + try ( + GenericContainer container = new GenericContainer<>() + .withStartupCheckStrategy(new NoopStartupCheckStrategy()) + .waitingFor(new WaitForState(ContainerState::getOOMKilled)) + .withCreateContainerCmdModifier(it -> { + it.getHostConfig().withMemory(4 * FileUtils.ONE_MB); + }) + .withCommand("sh", "-c", "A='0123456789'; for i in $(seq 0 32); do A=$A$A; done") + ) { + assertThatThrownBy(container::start) + .hasStackTraceContaining("Container crashed with out-of-memory"); + } + } + + @Test + public void shouldReportErrorAfterWait() { + try ( + GenericContainer container = new GenericContainer<>() + .withStartupCheckStrategy(new NoopStartupCheckStrategy()) + .waitingFor(new WaitForState(state -> state.getExitCode() > 0)) + .withCommand("sh", "-c", "usleep 100; exit 123") + ) { + assertThatThrownBy(container::start) + .hasStackTraceContaining("Container exited with code 123"); + } + } + + static class NoopStartupCheckStrategy extends StartupCheckStrategy { + + @Override + public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { + return StartupStatus.SUCCESSFUL; + } + } + + @RequiredArgsConstructor + @FieldDefaults(makeFinal = true) + static class WaitForState extends AbstractWaitStrategy { + + Predicate predicate; + + @Override + @SneakyThrows + protected void waitUntilReady() { + Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, () -> { + ContainerState state = waitStrategyTarget.getCurrentContainerInfo().getState(); + return predicate.test(state); + }); + + throw new IllegalStateException("Nope!"); + } + } +} From 6aced9f4954053b57d6f72623711099bb643a1e4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 10 Nov 2019 09:33:54 +0100 Subject: [PATCH 0380/4969] debug `GenericContainerTest` --- .../containers/GenericContainerTest.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index c69a3b69594..a5fbd9541e8 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; @@ -23,7 +24,7 @@ public void shouldReportOOMAfterWait() { try ( GenericContainer container = new GenericContainer<>() .withStartupCheckStrategy(new NoopStartupCheckStrategy()) - .waitingFor(new WaitForState(ContainerState::getOOMKilled)) + .waitingFor(new WaitForExitedState(ContainerState::getOOMKilled)) .withCreateContainerCmdModifier(it -> { it.getHostConfig().withMemory(4 * FileUtils.ONE_MB); }) @@ -39,7 +40,7 @@ public void shouldReportErrorAfterWait() { try ( GenericContainer container = new GenericContainer<>() .withStartupCheckStrategy(new NoopStartupCheckStrategy()) - .waitingFor(new WaitForState(state -> state.getExitCode() > 0)) + .waitingFor(new WaitForExitedState(state -> state.getExitCode() > 0)) .withCommand("sh", "-c", "usleep 100; exit 123") ) { assertThatThrownBy(container::start) @@ -57,7 +58,8 @@ public StartupStatus checkStartupState(DockerClient dockerClient, String contain @RequiredArgsConstructor @FieldDefaults(makeFinal = true) - static class WaitForState extends AbstractWaitStrategy { + @Slf4j + static class WaitForExitedState extends AbstractWaitStrategy { Predicate predicate; @@ -66,6 +68,12 @@ static class WaitForState extends AbstractWaitStrategy { protected void waitUntilReady() { Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, () -> { ContainerState state = waitStrategyTarget.getCurrentContainerInfo().getState(); + + log.debug("Current state: {}", state); + if (!"exited".equalsIgnoreCase(state.getStatus())) { + Thread.sleep(100); + return false; + } return predicate.test(state); }); From 7562e05b9771b48113b7602deebb2c9971594566 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 10 Nov 2019 10:45:19 +0100 Subject: [PATCH 0381/4969] Add sleep to GenericContainerTest --- .../org/testcontainers/containers/GenericContainerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index a5fbd9541e8..f805ee1aa9f 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -28,7 +28,7 @@ public void shouldReportOOMAfterWait() { .withCreateContainerCmdModifier(it -> { it.getHostConfig().withMemory(4 * FileUtils.ONE_MB); }) - .withCommand("sh", "-c", "A='0123456789'; for i in $(seq 0 32); do A=$A$A; done") + .withCommand("sh", "-c", "A='0123456789'; for i in $(seq 0 32); do A=$A$A; sleep 0.01; done; sleep 10m") ) { assertThatThrownBy(container::start) .hasStackTraceContaining("Container crashed with out-of-memory"); From 2fe206c4cc337e1ab38c401c89ceca56c672cf1f Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 10 Nov 2019 20:43:55 +0100 Subject: [PATCH 0382/4969] Fix session label when reuse is not supported but requested (#2051) --- .../containers/GenericContainer.java | 7 +++++ .../containers/ReusabilityUnitTests.java | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 18c53f8b80f..6ce8a2f5b09 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -341,6 +341,7 @@ private void tryStart(Instant startedAt) { createCommand.getLabels().put(DockerClientFactory.TESTCONTAINERS_LABEL, "true"); boolean reused = false; + final boolean reusable; if (shouldBeReused) { if (!canBeReused()) { throw new IllegalStateException("This container does not support reuse"); @@ -359,10 +360,16 @@ private void tryStart(Instant startedAt) { createCommand.getLabels().put(HASH_LABEL, hash); } + reusable = true; } else { logger().info("Reuse was requested but the environment does not support the reuse of containers"); + reusable = false; } } else { + reusable = false; + } + + if (!reusable) { createCommand.getLabels().put(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL, DockerClientFactory.SESSION_ID); } diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index b05db5b5077..32adbaa837f 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -20,6 +20,7 @@ import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.rnorth.visibleassertions.VisibleAssertions; +import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategy; @@ -29,9 +30,12 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -149,6 +153,26 @@ public void shouldReuseIfListReturnsID() { Mockito.verify(client, Mockito.never()).startContainerCmd(existingContainerId); } + @Test + public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { + // TODO mock TestcontainersConfiguration + Assume.assumeFalse("does not support reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); + AtomicReference commandRef = new AtomicReference<>(); + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId, commandRef::set)); + when(client.startContainerCmd(containerId)).then(startContainerAnswer()); + when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); + + container.start(); + + assertThat(commandRef) + .isNotNull() + .satisfies(command -> { + assertThat(command.get().getLabels()) + .containsKeys(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL); + }); + } + private String randomContainerId() { return UUID.randomUUID().toString(); } @@ -168,8 +192,13 @@ private Answer listContainersAnswer(String... ids) { } private Answer createContainerAnswer(String containerId) { + return createContainerAnswer(containerId, command -> {}); + } + + private Answer createContainerAnswer(String containerId, Consumer cmdConsumer) { return invocation -> { CreateContainerCmd.Exec exec = command -> { + cmdConsumer.accept(command); CreateContainerResponse response = new CreateContainerResponse(); response.setId(containerId); return response; From f59b123f7ee116776b9ae38e7eb030d2be5bbfd4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 10 Nov 2019 21:02:33 +0100 Subject: [PATCH 0383/4969] Try increasing the limit --- .../org/testcontainers/containers/GenericContainerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index f805ee1aa9f..dfc4a955713 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -26,9 +26,9 @@ public void shouldReportOOMAfterWait() { .withStartupCheckStrategy(new NoopStartupCheckStrategy()) .waitingFor(new WaitForExitedState(ContainerState::getOOMKilled)) .withCreateContainerCmdModifier(it -> { - it.getHostConfig().withMemory(4 * FileUtils.ONE_MB); + it.getHostConfig().withMemory(32 * FileUtils.ONE_MB); }) - .withCommand("sh", "-c", "A='0123456789'; for i in $(seq 0 32); do A=$A$A; sleep 0.01; done; sleep 10m") + .withCommand("sh", "-c", "A='0123456789'; for i in $(seq 0 32); do A=$A$A; done; sleep 10m") ) { assertThatThrownBy(container::start) .hasStackTraceContaining("Container crashed with out-of-memory"); From 86bfd78e86cd84207e086921f1d2f3bd2d2bb6b1 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 10 Nov 2019 21:23:27 +0100 Subject: [PATCH 0384/4969] tune some memory params --- .../testcontainers/containers/GenericContainerTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index dfc4a955713..c29f6f37c36 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse.ContainerState; +import com.github.dockerjava.api.model.HostConfig; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -26,7 +27,12 @@ public void shouldReportOOMAfterWait() { .withStartupCheckStrategy(new NoopStartupCheckStrategy()) .waitingFor(new WaitForExitedState(ContainerState::getOOMKilled)) .withCreateContainerCmdModifier(it -> { - it.getHostConfig().withMemory(32 * FileUtils.ONE_MB); + it.getHostConfig() + .withMemory(20 * FileUtils.ONE_MB) + .withMemorySwappiness(0L) + .withMemorySwap(0L) + .withMemoryReservation(0L) + .withKernelMemory(16 * FileUtils.ONE_MB); }) .withCommand("sh", "-c", "A='0123456789'; for i in $(seq 0 32); do A=$A$A; done; sleep 10m") ) { From c0277514327097abadaed58dadaa375c32fcdb5c Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 11 Nov 2019 16:09:25 +0100 Subject: [PATCH 0385/4969] Make `Startables#deepStart` always iterate sequentially (#2053) * Reproduce the issue with passing parallel Stream into Startables#deepStart * Fix the issue by sanitizing the input stream --- .../org/testcontainers/lifecycle/Startables.java | 1 + .../testcontainers/junit/DependenciesTest.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startables.java b/core/src/main/java/org/testcontainers/lifecycle/Startables.java index 0e6452c1914..6cf57cc6f6e 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/Startables.java +++ b/core/src/main/java/org/testcontainers/lifecycle/Startables.java @@ -60,6 +60,7 @@ public CompletableFuture deepStart(Stream startables) { */ private CompletableFuture deepStart(Map> started, Stream startables) { CompletableFuture[] futures = startables + .sequential() .map(it -> { // avoid a recursive update in `computeIfAbsent` Map> subStarted = new HashMap<>(started); diff --git a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java index df7e85a31f8..4f2ee01bc6d 100644 --- a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java +++ b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java @@ -9,9 +9,11 @@ import org.testcontainers.lifecycle.Startables; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import java.util.stream.Stream; public class DependenciesTest { @@ -117,6 +119,19 @@ public void shouldHandleDiamondDependencies() throws Exception { VisibleAssertions.assertEquals("D started", 1, d.getStartInvocationCount().intValue()); } + @Test + public void shouldHandleParallelStream() throws Exception { + List startables = Stream.generate(InvocationCountingStartable::new) + .limit(10) + .collect(Collectors.toList()); + + for (int i = 1; i < startables.size(); i++) { + startables.get(0).getDependencies().add(startables.get(i)); + } + + Startables.deepStart(startables.parallelStream()).get(1, TimeUnit.SECONDS); + } + private static class InvocationCountingStartable implements Startable { @Getter @@ -131,7 +146,6 @@ private static class InvocationCountingStartable implements Startable { @Override public void start() { startInvocationCount.getAndIncrement(); - } @Override From 7e5adade117e94ac0ed4e825b35ac0bdaf45c8fa Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 11 Nov 2019 18:11:11 +0100 Subject: [PATCH 0386/4969] Add `reused` parameter to the hooks (#2052) * Add `containerIsReused` hook * Add `reused` parameter to `containerIs{Starting,Started}` * post-merge fixes --- .../containers/GenericContainer.java | 16 ++- .../containers/ReusabilityUnitTests.java | 134 ++++++++++++++---- .../containers/KafkaContainer.java | 8 +- 3 files changed, 130 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 6ce8a2f5b09..47d08b57528 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -397,7 +397,7 @@ private void tryStart(Instant startedAt) { // Tell subclasses that we're starting containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); containerName = containerInfo.getName(); - containerIsStarting(containerInfo); + containerIsStarting(containerInfo, reused); // Wait until the container has reached the desired running state if (!this.startupCheckStrategy.waitUntilStartupSuccessful(dockerClient, containerId)) { @@ -444,7 +444,7 @@ private void tryStart(Instant startedAt) { } logger().info("Container {} started in {}", dockerImageName, Duration.between(startedAt, Instant.now())); - containerIsStarted(containerInfo); + containerIsStarted(containerInfo, reused); } catch (Exception e) { if (e instanceof UndeclaredThrowableException && e.getCause() instanceof Exception) { e = (Exception) e.getCause(); @@ -582,10 +582,22 @@ protected void containerIsCreated(String containerId) { protected void containerIsStarting(InspectContainerResponse containerInfo) { } + @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) + @UnstableAPI + protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { + containerIsStarting(containerInfo); + } + @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) protected void containerIsStarted(InspectContainerResponse containerInfo) { } + @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) + @UnstableAPI + protected void containerIsStarted(InspectContainerResponse containerInfo, boolean reused) { + containerIsStarted(containerInfo); + } + /** * A hook that is executed before the container is stopped with {@link #stop()}. * Warning! This hook won't be executed if the container is terminated during diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 32adbaa837f..2d0f7a8133a 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -23,9 +23,9 @@ import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.utility.TestcontainersConfiguration; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -98,34 +98,93 @@ protected void containerIsCreated(String containerId) { @RunWith(BlockJUnit4ClassRunner.class) @FieldDefaults(makeFinal = true) - public static class HashTest { + public static class HooksTest extends AbstractReusabilityTest { + + List script = new ArrayList<>(); + + GenericContainer container = makeReusable(new GenericContainer(IMAGE_FUTURE) { - StartupCheckStrategy startupCheckStrategy = new StartupCheckStrategy() { @Override - public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { - return StartupStatus.SUCCESSFUL; + protected boolean canBeReused() { + // Because we override "containerIsCreated" + return true; } - }; - WaitStrategy waitStrategy = new AbstractWaitStrategy() { @Override - protected void waitUntilReady() { + protected void containerIsCreated(String containerId) { + script.add("containerIsCreated"); + } + @Override + protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { + script.add("containerIsStarting(reused=" + reused + ")"); } - }; - DockerClient client = Mockito.mock(DockerClient.class); + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo, boolean reused) { + script.add("containerIsStarted(reused=" + reused + ")"); + } + }); - GenericContainer container = new GenericContainer(IMAGE_FUTURE) - .withNetworkMode("none") // to disable the port forwarding - .withStartupCheckStrategy(startupCheckStrategy) - .waitingFor(waitStrategy) - .withReuse(true); + @Test + public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { + // TODO mock TestcontainersConfiguration + Assume.assumeFalse("does not support reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); + AtomicReference commandRef = new AtomicReference<>(); + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); + when(client.listContainersCmd()).then(listContainersAnswer()); + when(client.startContainerCmd(containerId)).then(startContainerAnswer()); + when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); - { - container.dockerClient = client; + container.start(); + assertThat(script).containsExactly( + "containerIsCreated", + "containerIsStarting(reused=false)", + "containerIsStarted(reused=false)" + ); + } + + @Test + public void shouldCallHookIfReused() { + // TODO mock TestcontainersConfiguration + Assume.assumeTrue("supports reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); + String existingContainerId = randomContainerId(); + when(client.listContainersCmd()).then(listContainersAnswer(existingContainerId)); + when(client.inspectContainerCmd(existingContainerId)).then(inspectContainerAnswer()); + + container.start(); + assertThat(script).containsExactly( + "containerIsStarting(reused=true)", + "containerIsStarted(reused=true)" + ); } + @Test + public void shouldNotCallHookIfNotReused() { + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); + when(client.listContainersCmd()).then(listContainersAnswer()); + when(client.startContainerCmd(containerId)).then(startContainerAnswer()); + when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); + + container.start(); + assertThat(script).containsExactly( + "containerIsCreated", + "containerIsStarting(reused=false)", + "containerIsStarted(reused=false)" + ); + } + } + + @RunWith(BlockJUnit4ClassRunner.class) + @FieldDefaults(makeFinal = true) + public static class HashTest extends AbstractReusabilityTest { + + protected GenericContainer container = makeReusable(new GenericContainer<>(IMAGE_FUTURE)); + @Test public void shouldStartIfListReturnsEmpty() { String containerId = randomContainerId(); @@ -143,13 +202,15 @@ public void shouldStartIfListReturnsEmpty() { public void shouldReuseIfListReturnsID() { // TODO mock TestcontainersConfiguration Assume.assumeTrue("supports reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); - when(client.createContainerCmd(any())).then(createContainerAnswer(randomContainerId())); + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); String existingContainerId = randomContainerId(); when(client.listContainersCmd()).then(listContainersAnswer(existingContainerId)); when(client.inspectContainerCmd(existingContainerId)).then(inspectContainerAnswer()); container.start(); + Mockito.verify(client, Mockito.never()).startContainerCmd(containerId); Mockito.verify(client, Mockito.never()).startContainerCmd(existingContainerId); } @@ -172,12 +233,37 @@ public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { .containsKeys(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL); }); } + } + + @FieldDefaults(makeFinal = true) + static abstract class AbstractReusabilityTest { + + protected DockerClient client = Mockito.mock(DockerClient.class); + + protected > T makeReusable(T container) { + container.dockerClient = client; + container.withNetworkMode("none"); // to disable the port forwarding + container.withStartupCheckStrategy(new StartupCheckStrategy() { + @Override + public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { + return StartupStatus.SUCCESSFUL; + } + }); + container.waitingFor(new AbstractWaitStrategy() { + @Override + protected void waitUntilReady() { + + } + }); + container.withReuse(true); + return container; + } - private String randomContainerId() { + protected String randomContainerId() { return UUID.randomUUID().toString(); } - private Answer listContainersAnswer(String... ids) { + protected Answer listContainersAnswer(String... ids) { return invocation -> { ListContainersCmd.Exec exec = command -> { return new ObjectMapper().convertValue( @@ -191,11 +277,11 @@ private Answer listContainersAnswer(String... ids) { }; } - private Answer createContainerAnswer(String containerId) { + protected Answer createContainerAnswer(String containerId) { return createContainerAnswer(containerId, command -> {}); } - private Answer createContainerAnswer(String containerId, Consumer cmdConsumer) { + protected Answer createContainerAnswer(String containerId, Consumer cmdConsumer) { return invocation -> { CreateContainerCmd.Exec exec = command -> { cmdConsumer.accept(command); @@ -207,7 +293,7 @@ private Answer createContainerAnswer(String containerId, Con }; } - private Answer startContainerAnswer() { + protected Answer startContainerAnswer() { return invocation -> { StartContainerCmd.Exec exec = command -> { return null; @@ -216,7 +302,7 @@ private Answer startContainerAnswer() { }; } - private Answer inspectContainerAnswer() { + protected Answer inspectContainerAnswer() { return invocation -> { InspectContainerCmd.Exec exec = command -> { return new InspectContainerResponse(); diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index b08d6611e6d..ede8cb5d086 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -80,8 +80,12 @@ protected void doStart() { @Override @SneakyThrows - protected void containerIsStarting(InspectContainerResponse containerInfo) { - super.containerIsStarting(containerInfo); + protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { + super.containerIsStarting(containerInfo, reused); + + if (reused) { + return; + } port = getMappedPort(KAFKA_PORT); From 3142e58b9d38205d94aabc9fefef7651c502b95f Mon Sep 17 00:00:00 2001 From: Dominik Weidenfeld Date: Mon, 11 Nov 2019 23:57:10 +0100 Subject: [PATCH 0387/4969] added read timeout to http wait strategy (#2058) This commit adds the possibility to add a read timeout to the HTTP call for the HTTP wait strategy. This is necessary, because with the default Docker settings for Mac can lead to a blocking call to `HttpURLConnection.connect()`. The follow up issue is, that the container will never get healthy and due to automated integration tests the tests are not able to run. The main cause of the problem is the lazy connection establishment during setting up the container. So the time between starting the container and starting the wait strategy checks. The read timeout lets the HTTP call fail, so the `retryUntilSuccess()` is able to send another HTTP call in order to reestablish the connection and not block the whole thread. --- .../wait/strategy/HttpWaitStrategy.java | 19 ++++++++++++++++++- .../wait/strategy/HttpWaitStrategyTest.java | 19 +++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java index 6096e745e36..a44fc46e4b0 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java @@ -2,7 +2,6 @@ import com.google.common.base.Strings; import com.google.common.io.BaseEncoding; -import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.rnorth.ducttape.TimeoutException; import org.testcontainers.containers.ContainerLaunchException; @@ -13,7 +12,9 @@ import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; +import java.time.Duration; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; @@ -41,6 +42,7 @@ public class HttpWaitStrategy extends AbstractWaitStrategy { private Predicate responsePredicate; private Predicate statusCodePredicate = null; private Optional livenessPort = Optional.empty(); + private Duration readTimeout = Duration.ofSeconds(1); /** * Waits for the given status code. @@ -108,6 +110,20 @@ public HttpWaitStrategy withBasicCredentials(String username, String password) { return this; } + /** + * Set the HTTP connections read timeout. + * + * @param timeout the timeout (minimum 1 millisecond) + * @return this + */ + public HttpWaitStrategy withReadTimeout(Duration timeout) { + if (timeout.toMillis() < 1) { + throw new IllegalArgumentException("you cannot specify a value smaller than 1 ms"); + } + this.readTimeout = timeout; + return this; + } + /** * Waits for the response to pass the given predicate * @param responsePredicate The predicate to test the response against @@ -143,6 +159,7 @@ protected void waitUntilReady() { getRateLimiter().doWhenReady(() -> { try { final HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection(); + connection.setReadTimeout(Math.toIntExact(readTimeout.toMillis())); // authenticate if (!Strings.isNullOrEmpty(username)) { diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java index 5820333245a..e048f4bccb8 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java @@ -5,6 +5,7 @@ import org.rnorth.ducttape.RetryCountExceededException; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import java.time.Duration; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; @@ -131,6 +132,15 @@ public void testWaitUntilReadyWithSpecificPort() { )); } + @Test + public void testWaitUntilReadyWithTimoutCausedByReadTimeout() { + waitUntilReadyAndTimeout( + startContainerWithCommand(createShellCommand("0 Connection Refused", GOOD_RESPONSE_BODY, 9090), + createHttpWaitStrategy(ready).forPort(9090).withReadTimeout(Duration.ofMillis(1)), + 9090 + )); + } + /** * @param ready the AtomicBoolean on which to indicate success * @return the WaitStrategy under test @@ -143,6 +153,7 @@ protected HttpWaitStrategy buildWaitStrategy(final AtomicBoolean ready) { /** * Create a HttpWaitStrategy instance with a waitUntilReady implementation + * * @param ready Indicates that the WaitStrategy has completed waiting successfully. * @return the HttpWaitStrategy instance */ @@ -163,9 +174,9 @@ private String createShellCommand(String header, String responseBody) { private String createShellCommand(String header, String responseBody, int port) { int length = responseBody.getBytes().length; - return "while true; do { echo -e \"HTTP/1.1 "+header+NEWLINE+ - "Content-Type: text/html"+NEWLINE+ - "Content-Length: "+length +NEWLINE+ "\";" - +" echo \""+responseBody+"\";} | nc -lp " + port + "; done"; + return "while true; do { echo -e \"HTTP/1.1 " + header + NEWLINE + + "Content-Type: text/html" + NEWLINE + + "Content-Length: " + length + NEWLINE + "\";" + + " echo \"" + responseBody + "\";} | nc -lp " + port + "; done"; } } From e26788a0af57ee23151b8594375049bcf7e8968f Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 12 Nov 2019 08:08:17 +0100 Subject: [PATCH 0388/4969] [hotfix] always obtain port in Kafka --- .../java/org/testcontainers/containers/KafkaContainer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index ede8cb5d086..25cfba9d322 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -83,12 +83,12 @@ protected void doStart() { protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { super.containerIsStarting(containerInfo, reused); + port = getMappedPort(KAFKA_PORT); + if (reused) { return; } - port = getMappedPort(KAFKA_PORT); - final String zookeeperConnect; if (externalZookeeperConnect != null) { zookeeperConnect = externalZookeeperConnect; From 92cbc2f9af019461cdc0431b318944ce72a704a1 Mon Sep 17 00:00:00 2001 From: Willy Lulciuc Date: Tue, 12 Nov 2019 11:05:03 -0800 Subject: [PATCH 0389/4969] Add Marquez as user (#2060) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Marquez as user This PR adds [Marquez](https://marquezproject.github.io/marquez/) to the list of users. Keep up the great work 💯 * Link to website --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index ba99eb6e555..8f95ad5399a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -76,6 +76,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Micronaut Data](https://github.com/micronaut-projects/micronaut-data/) - Testing of Micronaut Data JDBC, a database access toolkit * [JHipster](https://www.jhipster.tech/) - Couchbase and Cassandra integration testing * [wescale](https://www.wescale.com) - Integration testing against HTTP service mocks and various data stores +* [Marquez](https://marquezproject.github.io/marquez) - PostgreSQL integration testing ## License From 8dee638fc4c5ad3c11f0156abf97cb148b58db27 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 18 Nov 2019 14:16:42 +0100 Subject: [PATCH 0390/4969] Stabilize CouchbaseContainer by merging the Socat command (#2081) Fixes #1453 --- .../couchbase/CouchbaseContainer.java | 38 ++++++++++++------- .../couchbase/BaseCouchbaseContainerTest.java | 9 ----- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index ad6fe3d18a9..9e7ace2af04 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -37,7 +37,6 @@ import org.testcontainers.containers.SocatContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.images.builder.Transferable; -import org.testcontainers.utility.Base58; import org.testcontainers.utility.ThrowingFunction; import java.io.DataOutputStream; @@ -47,6 +46,7 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -107,11 +107,10 @@ public CouchbaseContainer() { this(DOCKER_IMAGE_NAME + VERSION); } - public CouchbaseContainer(String containerName) { - super(containerName); + public CouchbaseContainer(String imageName) { + super(imageName); withNetwork(Network.SHARED); - withNetworkAliases("couchbase-" + Base58.randomString(6)); setWaitStrategy(new HttpWaitStrategy().forPath("/ui/index.html")); } @@ -131,15 +130,16 @@ protected void configure() { @Override @SneakyThrows protected void doStart() { - String networkAlias = getNetworkAliases().get(0); - startProxy(networkAlias); - - for (CouchbasePort port : CouchbasePort.values()) { - exposePortThroughProxy(networkAlias, port.getOriginalPort(), getMappedPort(port)); + startProxy(getNetworkAliases().get(0)); + try { + super.doStart(); + } catch (Throwable e) { + proxy.stop(); + throw e; } - super.doStart(); } + @SneakyThrows private void startProxy(String networkAlias) { proxy = new SocatContainer().withNetwork(getNetwork()); @@ -150,18 +150,28 @@ private void startProxy(String networkAlias) { proxy.addExposedPort(port.getOriginalPort()); } } + proxy.setWaitStrategy(null); proxy.start(); - } - private void exposePortThroughProxy(String networkAlias, int originalPort, int mappedPort) { ExecCreateCmdResponse createCmdResponse = dockerClient .execCreateCmd(proxy.getContainerId()) - .withCmd("/usr/bin/socat", "TCP-LISTEN:" + originalPort + ",fork,reuseaddr", "TCP:" + networkAlias + ":" + mappedPort) + .withCmd( + "sh", + "-c", + Stream.of(CouchbasePort.values()) + .map(port -> { + return "/usr/bin/socat " + + "TCP-LISTEN:" + port.getOriginalPort() + ",fork,reuseaddr " + + "TCP:" + networkAlias + ":" + getMappedPort(port); + }) + .collect(Collectors.joining(" & ", "true", "")) + ) .exec(); dockerClient.execStartCmd(createCmdResponse.getId()) - .exec(new ExecStartResultCallback()); + .exec(new ExecStartResultCallback()) + .awaitCompletion(10, TimeUnit.SECONDS); } @Override diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java index 19eead1b23a..845d9bfaf5e 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java @@ -9,10 +9,7 @@ import com.couchbase.client.java.view.View; import com.google.common.collect.Lists; import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; -import org.testcontainers.testsupport.Flaky; -import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; import java.util.List; @@ -28,11 +25,7 @@ public abstract class BaseCouchbaseContainerTest extends AbstractCouchbaseTest { private static final String DOCUMENT = "{\"name\":\"toto\"}"; - @Rule - public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); - @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldInsertDocument() { RawJsonDocument expected = RawJsonDocument.create(ID, DOCUMENT); getBucket().upsert(expected); @@ -41,7 +34,6 @@ public void shouldInsertDocument() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldExecuteN1ql() { getBucket().query(N1qlQuery.simple("INSERT INTO " + TEST_BUCKET + " (KEY, VALUE) VALUES ('" + ID + "', " + DOCUMENT + ")")); @@ -54,7 +46,6 @@ public void shouldExecuteN1ql() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldCreateView() { View view = DefaultView.create(VIEW_NAME, VIEW_FUNCTION); DesignDocument document = DesignDocument.create(VIEW_NAME, Lists.newArrayList(view)); From 839ce65fde0367ccb3eb80d2b24df9c9e3fc9390 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 22 Nov 2019 13:23:39 +0100 Subject: [PATCH 0391/4969] Lazily create/set Network in KafkaContainer (#2079) To make KafkaContainer work with #1781 without having to nullify the network, we should start removed the old, deprecated behaviour where the network was implicitly created in the constructor. --- .../containers/KafkaContainer.java | 36 ++++++++- .../containers/KafkaContainerTest.java | 74 ++++++++++--------- 2 files changed, 71 insertions(+), 39 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 25cfba9d322..4b5e66a7bf5 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -4,7 +4,6 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.core.command.ExecStartResultCallback; import lombok.SneakyThrows; -import org.testcontainers.utility.Base58; import org.testcontainers.utility.TestcontainersConfiguration; import java.util.concurrent.TimeUnit; @@ -25,6 +24,8 @@ public class KafkaContainer extends GenericContainer { private int port = PORT_NOT_ASSIGNED; + private boolean useImplicitNetwork = true; + public KafkaContainer() { this("5.2.1"); } @@ -32,9 +33,6 @@ public KafkaContainer() { public KafkaContainer(String confluentPlatformVersion) { super(TestcontainersConfiguration.getInstance().getKafkaImage() + ":" + confluentPlatformVersion); - // TODO Only for backward compatibility - withNetwork(Network.newNetwork()); - withNetworkAliases("kafka-" + Base58.randomString(6)); withExposedPorts(KAFKA_PORT); // Use two listeners with different names, it will force Kafka to communicate with itself via internal @@ -50,6 +48,36 @@ public KafkaContainer(String confluentPlatformVersion) { withEnv("KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS", "0"); } + @Override + public KafkaContainer withNetwork(Network network) { + useImplicitNetwork = false; + return super.withNetwork(network); + } + + @Override + public Network getNetwork() { + if (useImplicitNetwork) { + // TODO Only for backward compatibility, to be removed soon + logger().warn( + "Deprecation warning! " + + "KafkaContainer#getNetwork without an explicitly set network. " + + "Consider using KafkaContainer#withNetwork", + new Exception("Deprecated method") + ); + Network network = Network.SHARED; + super.withNetwork(network); + + if (getContainerId() != null) { + dockerClient.connectToNetworkCmd() + .withContainerId(getContainerId()) + .withNetworkId(network.getId()) + .exec(); + } + return network; + } + return super.getNetwork(); + } + public KafkaContainer withEmbeddedZookeeper() { externalZookeeperConnect = null; return self(); diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index fc36a3f4356..0b29ee0e6ef 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -31,16 +31,20 @@ public void testUsage() throws Exception { } } + /** + * @deprecated the {@link Network} should be set explicitly with {@link KafkaContainer#withNetwork(Network)}. + */ @Test + @Deprecated public void testExternalZookeeperWithKafkaNetwork() throws Exception { try ( - KafkaContainer kafka = new KafkaContainer() - .withExternalZookeeper("zookeeper:2181"); + KafkaContainer kafka = new KafkaContainer() + .withExternalZookeeper("zookeeper:2181"); - GenericContainer zookeeper = new GenericContainer("confluentinc/cp-zookeeper:4.0.0") - .withNetwork(kafka.getNetwork()) - .withNetworkAliases("zookeeper") - .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); + GenericContainer zookeeper = new GenericContainer("confluentinc/cp-zookeeper:4.0.0") + .withNetwork(kafka.getNetwork()) + .withNetworkAliases("zookeeper") + .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); ) { Stream.of(kafka, zookeeper).parallel().forEach(GenericContainer::start); @@ -51,16 +55,16 @@ public void testExternalZookeeperWithKafkaNetwork() throws Exception { @Test public void testExternalZookeeperWithExternalNetwork() throws Exception { try ( - Network network = Network.newNetwork(); + Network network = Network.newNetwork(); - KafkaContainer kafka = new KafkaContainer() - .withNetwork(network) - .withExternalZookeeper("zookeeper:2181"); + KafkaContainer kafka = new KafkaContainer() + .withNetwork(network) + .withExternalZookeeper("zookeeper:2181"); - GenericContainer zookeeper = new GenericContainer("confluentinc/cp-zookeeper:4.0.0") - .withNetwork(network) - .withNetworkAliases("zookeeper") - .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); + GenericContainer zookeeper = new GenericContainer("confluentinc/cp-zookeeper:4.0.0") + .withNetwork(network) + .withNetworkAliases("zookeeper") + .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); ) { Stream.of(kafka, zookeeper).parallel().forEach(GenericContainer::start); @@ -70,24 +74,24 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { protected void testKafkaFunctionality(String bootstrapServers) throws Exception { try ( - KafkaProducer producer = new KafkaProducer<>( - ImmutableMap.of( - ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, - ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString() - ), - new StringSerializer(), - new StringSerializer() - ); - - KafkaConsumer consumer = new KafkaConsumer<>( - ImmutableMap.of( - ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, - ConsumerConfig.GROUP_ID_CONFIG, "tc-" + UUID.randomUUID(), - ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest" - ), - new StringDeserializer(), - new StringDeserializer() - ); + KafkaProducer producer = new KafkaProducer<>( + ImmutableMap.of( + ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, + ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString() + ), + new StringSerializer(), + new StringSerializer() + ); + + KafkaConsumer consumer = new KafkaConsumer<>( + ImmutableMap.of( + ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, + ConsumerConfig.GROUP_ID_CONFIG, "tc-" + UUID.randomUUID(), + ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest" + ), + new StringDeserializer(), + new StringDeserializer() + ); ) { String topicName = "messages"; consumer.subscribe(Arrays.asList(topicName)); @@ -102,9 +106,9 @@ protected void testKafkaFunctionality(String bootstrapServers) throws Exception } assertThat(records) - .hasSize(1) - .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) - .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); return true; }); From 154e9339aba4a7f9e53f942ecb1b02362f479776 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 22 Nov 2019 14:48:35 +0100 Subject: [PATCH 0392/4969] Add Gradle wrapper to examples/ that points to the parent's wrapper (#2077) * Add Gradle wrapper to examples/ that points to the parent's wrapper * Update CI scripts --- .circleci/config.yml | 2 +- .travis.yml | 2 +- examples/gradlew | 188 +++++++++++++++++++++++++++++++++++++++++++ examples/gradlew.bat | 100 +++++++++++++++++++++++ 4 files changed, 290 insertions(+), 2 deletions(-) create mode 100755 examples/gradlew create mode 100644 examples/gradlew.bat diff --git a/.circleci/config.yml b/.circleci/config.yml index 08c0f4aabab..5ee4097934a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -81,7 +81,7 @@ jobs: steps: - checkout - run: - command: cd examples && ../gradlew check + command: cd examples && ./gradlew check - run: name: Save test results command: | diff --git a/.travis.yml b/.travis.yml index d21033b942a..eda26dc69af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,7 @@ jobs: script: ./gradlew jdbc-test:check --scan --no-daemon -i - env: [ NAME=examples ] - script: cd examples && ../gradlew check --no-daemon -i + script: cd examples && ./gradlew check --no-daemon -i # Run Docker-in-Docker tests inside Alpine - env: [ NAME="docker-in-alpine-docker" ] diff --git a/examples/gradlew b/examples/gradlew new file mode 100755 index 00000000000..56f7b0fc7bf --- /dev/null +++ b/examples/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/../gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/examples/gradlew.bat b/examples/gradlew.bat new file mode 100644 index 00000000000..f3a074d99d4 --- /dev/null +++ b/examples/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\..\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 003ef139a9bdfa07a1fc57c90694f61fcfc61dd8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2019 20:56:42 +0000 Subject: [PATCH 0393/4969] Bump tomcat-jdbc from 9.0.27 to 9.0.29 in /modules/mariadb (#2096) Bumps tomcat-jdbc from 9.0.27 to 9.0.29. Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index f6d65f4a5f0..87462ce158d 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.1' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.27' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.29' testCompile 'org.vibur:vibur-dbcp:22.2' } From 69c54aac43b8e4eed3e35d34424867a3e2c65b60 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2019 20:57:44 +0000 Subject: [PATCH 0394/4969] =?UTF-8?q?Bump=20aws-java-sdk-s3=20from=201.11.?= =?UTF-8?q?636=20to=201.11.680=20in=20/modules/loca=E2=80=A6=20(#2094)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.636 to 1.11.680. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.636...1.11.680) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 1ee679abf98..770294621aa 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.636' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.680' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' } From 53e16333477e261460f170eddae78662c140774b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2019 20:57:56 +0000 Subject: [PATCH 0395/4969] Bump tomcat-jdbc from 9.0.27 to 9.0.29 in /modules/mysql (#2095) Bumps tomcat-jdbc from 9.0.27 to 9.0.29. Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 7704f56c54f..2a71e8f9d04 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.18' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.27' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.29' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:22.2' } From f1e9883bcf50fdeebcbd93cbc0f55f721b2e4330 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2019 15:22:00 +0000 Subject: [PATCH 0396/4969] Bump java-client from 2.7.9 to 2.7.10 in /modules/couchbase (#2057) Bumps [java-client](https://github.com/couchbase/couchbase-java-client) from 2.7.9 to 2.7.10. - [Release notes](https://github.com/couchbase/couchbase-java-client/releases) - [Commits](https://github.com/couchbase/couchbase-java-client/compare/2.7.9...2.7.10) Signed-off-by: dependabot-preview[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 063b12c9d8e..7642bb2fc5b 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.9' + compile 'com.couchbase.client:java-client:2.7.10' testCompile project(':test-support') } From b7565275eba1009b0db1d1cde0979420459555b6 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 23 Nov 2019 16:40:15 +0000 Subject: [PATCH 0397/4969] =?UTF-8?q?Upgrade=20docker-compose=20image=20to?= =?UTF-8?q?=20latest=20version=20and=20perform=20dire=E2=80=A6=20(#1847)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Upgrade docker-compose image to latest version and perform direct image pull Together with using Compose file 2.1 syntax, this is a solution to network cleanup issue described in: * #1767 * #739 * https://github.com/testcontainers/moby-ryuk/issues/2 * https://github.com/docker/compose/issues/6636 Solution to general credential helper authenticated pull issues in: * https://github.com/docker/compose/issues/5854 Tangentially should add support for v3 syntax (not yet tested) re #531 --- .../containers/DockerComposeContainer.java | 170 ++++-------------- .../containers/ParsedDockerComposeFile.java | 95 ++++++++++ .../utility/TestcontainersConfiguration.java | 2 +- .../DockerComposeFileValidationTest.java | 70 -------- ...ParsedDockerComposeFileValidationTest.java | 88 +++++++++ .../junit/DockerComposeErrorHandlingTest.java | 15 +- core/src/test/resources/compose-test.yml | 2 +- .../test/resources/docker-compose-base.yml | 4 +- .../docker-compose-imagename-parsing-v1.yml | 6 + .../docker-compose-imagename-parsing-v2.yml | 10 ++ .../docker-compose-non-default-override.yml | 4 +- .../src/test/resources/local-compose-test.yml | 2 +- .../resources/v2-compose-test-passthrough.yml | 2 +- .../v2-compose-test-with-network.yml | 2 +- core/src/test/resources/v2-compose-test.yml | 2 +- .../src/test/resources/docker-compose.yml | 2 +- .../src/test/resources/docker-compose.yml | 2 +- 17 files changed, 250 insertions(+), 228 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java delete mode 100644 core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java create mode 100644 core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java create mode 100644 core/src/test/resources/docker-compose-imagename-parsing-v1.yml create mode 100644 core/src/test/resources/docker-compose-imagename-parsing-v2.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 73628a19ad7..31d84284584 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -2,14 +2,13 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Container; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Splitter; +import com.google.common.base.Strings; import com.google.common.collect.Maps; import com.google.common.util.concurrent.Uninterruptibles; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; import org.junit.runner.Description; @@ -19,18 +18,16 @@ import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy; -import org.testcontainers.containers.wait.strategy.*; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.containers.wait.strategy.WaitAllStrategy; +import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.lifecycle.Startable; import org.testcontainers.utility.*; -import org.yaml.snakeyaml.Yaml; import org.zeroturnaround.exec.InvalidExitValueException; import org.zeroturnaround.exec.ProcessExecutor; import org.zeroturnaround.exec.stream.slf4j.Slf4jStream; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.*; import java.time.Duration; import java.util.AbstractMap.SimpleEntry; import java.util.*; @@ -38,6 +35,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkArgument; @@ -58,8 +56,7 @@ public class DockerComposeContainer> e */ private final String identifier; private final List composeFiles; - private final Set spawnedContainerIds = new HashSet<>(); - private final Set spawnedNetworkIds = new HashSet<>(); + private Set parsedComposeFiles; private final Map scalingPreferences = new HashMap<>(); private DockerClient dockerClient; private boolean localCompose; @@ -107,10 +104,11 @@ public DockerComposeContainer(String identifier, File... composeFiles) { public DockerComposeContainer(String identifier, List composeFiles) { this.composeFiles = composeFiles; + this.parsedComposeFiles = composeFiles.stream().map(ParsedDockerComposeFile::new).collect(Collectors.toSet()); // Use a unique identifier so that containers created for this compose environment can be identified this.identifier = identifier; - project = randomProjectId(); + this.project = randomProjectId(); this.dockerClient = DockerClientFactory.instance().client(); } @@ -154,7 +152,6 @@ public void start() { log.warn("Exception while pulling images, using local images if available", e); } } - applyScaling(); // scale before up, so that all scaled instances are available first for linking createServices(); startAmbassadorContainers(); waitUntilServiceStarted(); @@ -162,7 +159,18 @@ public void start() { } private void pullImages() { - runWithCompose("pull"); + // Pull images using our docker client rather than compose itself, + // (a) as a workaround for https://github.com/docker/compose/issues/5854, which prevents authenticated image pulls being possible when credential helpers are in use + // (b) so that credential helper-based auth still works when compose is running from within a container + parsedComposeFiles.stream() + .flatMap(it -> it.getServiceImageNames().stream()) + .forEach(imageName -> { + try { + DockerClientFactory.instance().checkAndPullImage(dockerClient, imageName); + } catch (Exception e) { + log.warn("Failed to pull image '{}'. Exception message was {}", imageName, e.getMessage()); + } + }); } public SELF withServices(@NonNull String... services) { @@ -171,18 +179,23 @@ public SELF withServices(@NonNull String... services) { } private void createServices() { - // Run the docker-compose container, which starts up the services - String command = "up -d"; + // Apply scaling + final String servicesWithScalingSettings = Stream.concat(services.stream(), scalingPreferences.keySet().stream()) + .map(service -> "--scale " + service + "=" + scalingPreferences.getOrDefault(service, 1)) + .collect(joining(" ")); + + String flags = "-d"; if (build) { - command += " --build"; + flags += " --build"; } - if (!services.isEmpty()) { - command += " " + String.join(" ", services); + // Run the docker-compose container, which starts up the services + if(Strings.isNullOrEmpty(servicesWithScalingSettings)) { + runWithCompose("up " + flags); + } else { + runWithCompose("up " + flags + " " + servicesWithScalingSettings); } - - runWithCompose(command); } private void waitUntilServiceStarted() { @@ -221,10 +234,6 @@ private void runWithCompose(String cmd) { checkNotNull(composeFiles); checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided"); - for (File composeFile : composeFiles) { - validate(composeFile); - } - final DockerCompose dockerCompose; if (localCompose) { dockerCompose = new LocalDockerCompose(composeFiles, project); @@ -238,72 +247,6 @@ private void runWithCompose(String cmd) { .invoke(); } - @SuppressWarnings("unchecked") - private static void validate(File composeFile) { - Yaml yaml = new Yaml(); - try (FileInputStream fileInputStream = FileUtils.openInputStream(composeFile)) { - Object template = yaml.load(fileInputStream); - validate(template, composeFile.getAbsolutePath()); - } catch (IOException e) { - log.warn("Failed to read YAML from {}", composeFile.getAbsolutePath(), e); - } - } - - @VisibleForTesting - static void validate(Object template, String identifier) { - if (!(template instanceof Map)) { - return; - } - - Map map = (Map) template; - - final Map servicesMap; - if (map.containsKey("version")) { - if (!map.containsKey("services")) { - log.debug("Compose file {} has an unknown format: 'version' is set but 'services' is not defined", identifier); - return; - } - Object services = map.get("services"); - if (!(services instanceof Map)) { - log.debug("Compose file {} has an unknown format: 'services' is not Map", identifier); - return; - } - - servicesMap = (Map) services; - } else { - servicesMap = map; - } - - for (Map.Entry entry : servicesMap.entrySet()) { - String serviceName = entry.getKey(); - Object serviceDefinition = entry.getValue(); - if (!(serviceDefinition instanceof Map)) { - log.debug("Compose file {} has an unknown format: service '{}' is not Map", identifier, serviceName); - break; - } - - if (((Map) serviceDefinition).containsKey("container_name")) { - throw new IllegalStateException(String.format( - "Compose file %s has 'container_name' property set for service '%s' but this property is not supported by Testcontainers, consider removing it", - identifier, - serviceName - )); - } - } - } - - private void applyScaling() { - // Apply scaling - if (!scalingPreferences.isEmpty()) { - StringBuilder sb = new StringBuilder("scale"); - for (Map.Entry scale : scalingPreferences.entrySet()) { - sb.append(" ").append(scale.getKey()).append("=").append(scale.getValue()); - } - - runWithCompose(sb.toString()); - } - } - private void registerContainersForShutdown() { ResourceReaper.instance().registerFilterForCleanup(Arrays.asList( new SimpleEntry<>("label", "com.docker.compose.project=" + project) @@ -333,29 +276,12 @@ public void stop() { ambassadorContainer.stop(); // Kill the services using docker-compose - try { - String cmd = "down -v"; - if (removeImages != null) { - cmd += " --rmi " + removeImages.dockerRemoveImagesType(); - } - runWithCompose(cmd); - - // If we reach here then docker-compose down has cleared networks and containers; - // we can unregister from ResourceReaper - spawnedContainerIds.forEach(ResourceReaper.instance()::unregisterContainer); - spawnedNetworkIds.forEach(ResourceReaper.instance()::unregisterNetwork); - } catch (Exception e) { - // docker-compose down failed; use ResourceReaper to ensure cleanup - - // kill the spawned service containers - spawnedContainerIds.forEach(ResourceReaper.instance()::stopAndRemoveContainer); - - // remove the networks after removing the containers - spawnedNetworkIds.forEach(ResourceReaper.instance()::removeNetworkById); + String cmd = "down -v"; + if (removeImages != null) { + cmd += " --rmi " + removeImages.dockerRemoveImagesType(); } + runWithCompose(cmd); - spawnedContainerIds.clear(); - spawnedNetworkIds.clear(); } finally { project = randomProjectId(); } @@ -597,9 +523,6 @@ interface DockerCompose { class ContainerisedDockerCompose extends GenericContainer implements DockerCompose { private static final String DOCKER_SOCKET_PATH = "/var/run/docker.sock"; - private static final String DOCKER_CONFIG_FILE = "/root/.docker/config.json"; - private static final String DOCKER_CONFIG_ENV = "DOCKER_CONFIG_FILE"; - private static final String DOCKER_CONFIG_PROPERTY = "dockerConfigFile"; public static final char UNIX_PATH_SEPERATOR = ':'; public ContainerisedDockerCompose(List composeFiles, String identifier) { @@ -630,27 +553,6 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { addEnv("DOCKER_HOST", "unix:///docker.sock"); setStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy()); setWorkingDirectory(containerPwd); - - String dockerConfigPath = determineDockerConfigPath(); - if (dockerConfigPath != null && !dockerConfigPath.isEmpty()) { - addFileSystemBind(dockerConfigPath, DOCKER_CONFIG_FILE, READ_ONLY); - } - } - - private String determineDockerConfigPath() { - String dockerConfigEnv = System.getenv(DOCKER_CONFIG_ENV); - String dockerConfigProperty = System.getProperty(DOCKER_CONFIG_PROPERTY); - Path dockerConfig = Paths.get(System.getProperty("user.home"), ".docker", "config.json"); - - if (dockerConfigEnv != null && !dockerConfigEnv.trim().isEmpty() && Files.exists(Paths.get(dockerConfigEnv))) { - return dockerConfigEnv; - } else if (dockerConfigProperty != null && !dockerConfigProperty.trim().isEmpty() && Files.exists(Paths.get(dockerConfigProperty))) { - return dockerConfigProperty; - } else if (Files.exists(dockerConfig)) { - return dockerConfig.toString(); - } else { - return null; - } } private String getDockerSocketHostPath() { diff --git a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java new file mode 100644 index 00000000000..838607d8337 --- /dev/null +++ b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java @@ -0,0 +1,95 @@ +package org.testcontainers.containers; + +import com.google.common.annotations.VisibleForTesting; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.FileInputStream; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Representation of a docker-compose file, with partial parsing for validation and extraction of a minimal set of + * data. + */ +@Slf4j +@EqualsAndHashCode +class ParsedDockerComposeFile { + + private final Map composeFileContent; + private final String composeFileName; + + @Getter + private Set serviceImageNames = new HashSet<>(); + + ParsedDockerComposeFile(File composeFile) { + Yaml yaml = new Yaml(); + try (FileInputStream fileInputStream = FileUtils.openInputStream(composeFile)) { + composeFileContent = yaml.load(fileInputStream); + } catch (Exception e) { + throw new IllegalArgumentException("Unable to parse YAML file from " + composeFile.getAbsolutePath(), e); + } + this.composeFileName = composeFile.getAbsolutePath(); + + parseAndValidate(); + } + + @VisibleForTesting + ParsedDockerComposeFile(Map testContent) { + this.composeFileContent = testContent; + this.composeFileName = ""; + + parseAndValidate(); + } + + private void parseAndValidate() { + final Map servicesMap; + if (composeFileContent.containsKey("version")) { + if ("2.0".equals(composeFileContent.get("version"))) { + log.warn("Testcontainers may not be able to clean up networks spawned using Docker Compose v2.0 files. " + + "Please see https://github.com/testcontainers/moby-ryuk/issues/2, and specify 'version: \"2.1\"' or " + + "higher in {}", composeFileName); + } + + final Object servicesElement = composeFileContent.get("services"); + if (servicesElement == null) { + log.debug("Compose file {} has an unknown format: 'version' is set but 'services' is not defined", composeFileName); + return; + } + if (!(servicesElement instanceof Map)) { + log.debug("Compose file {} has an unknown format: 'services' is not Map", composeFileName); + return; + } + + servicesMap = (Map) servicesElement; + } else { + servicesMap = composeFileContent; + } + + for (Map.Entry entry : servicesMap.entrySet()) { + String serviceName = entry.getKey(); + Object serviceDefinition = entry.getValue(); + if (!(serviceDefinition instanceof Map)) { + log.debug("Compose file {} has an unknown format: service '{}' is not Map", composeFileName, serviceName); + break; + } + + final Map serviceDefinitionMap = (Map) serviceDefinition; + if (serviceDefinitionMap.containsKey("container_name")) { + throw new IllegalStateException(String.format( + "Compose file %s has 'container_name' property set for service '%s' but this property is not supported by Testcontainers, consider removing it", + composeFileName, + serviceName + )); + } + if (serviceDefinitionMap.containsKey("image") && serviceDefinitionMap.get("image") instanceof String) { + serviceImageNames.add((String) serviceDefinitionMap.get("image")); + } + } + } +} diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index e5a45a05b64..1387dc6b9cd 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -51,7 +51,7 @@ public String getVncRecordedContainerImage() { } public String getDockerComposeContainerImage() { - return (String) properties.getOrDefault("compose.container.image", "docker/compose:1.8.0"); + return (String) properties.getOrDefault("compose.container.image", "docker/compose:1.24.1"); } public String getTinyImage() { diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java deleted file mode 100644 index 7a3121dcd32..00000000000 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeFileValidationTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.testcontainers.containers; - -import com.google.common.collect.ImmutableMap; -import org.assertj.core.api.Assertions; -import org.junit.Test; - -import java.io.File; - -import static java.util.Collections.emptyList; - -public class DockerComposeFileValidationTest { - - @Test - public void shouldValidate() { - File file = new File("src/test/resources/docker-compose-container-name-v1.yml"); - try (DockerComposeContainer container = new DockerComposeContainer<>(file)) { - Assertions.assertThatThrownBy(container::start) - .hasMessageContaining(file.getAbsolutePath()) - .hasMessageContaining("'container_name' property set for service 'redis'"); - } - } - - @Test - public void shouldRejectContainerNameV1() { - Assertions - .assertThatThrownBy(() -> { - DockerComposeContainer.validate(ImmutableMap.of( - "redis", ImmutableMap.of("container_name", "redis") - ), ""); - }) - .hasMessageContaining("'container_name' property set for service 'redis'"); - } - - @Test - public void shouldRejectContainerNameV2() { - Assertions - .assertThatThrownBy(() -> { - DockerComposeContainer.validate(ImmutableMap.of( - "version", "2", - "services", ImmutableMap.of( - "redis", ImmutableMap.of("container_name", "redis") - ) - ), ""); - }) - .hasMessageContaining("'container_name' property set for service 'redis'"); - } - - @Test - public void shouldIgnoreUnknownStructure() { - // Everything is a list - DockerComposeContainer.validate(emptyList(), ""); - - // services is not a map but List - DockerComposeContainer.validate(ImmutableMap.of( - "version", "2", - "services", emptyList() - ), ""); - - // services is not a collection - DockerComposeContainer.validate(ImmutableMap.of( - "version", "2", - "services", true - ), ""); - - // no services while version is defined - DockerComposeContainer.validate(ImmutableMap.of( - "version", "9000" - ), ""); - } -} diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java new file mode 100644 index 00000000000..c553d250ec9 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -0,0 +1,88 @@ +package org.testcontainers.containers; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import java.io.File; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class ParsedDockerComposeFileValidationTest { + + @Test + public void shouldValidate() { + File file = new File("src/test/resources/docker-compose-container-name-v1.yml"); + Assertions + .assertThatThrownBy(() -> { + new ParsedDockerComposeFile(file); + }) + .hasMessageContaining(file.getAbsolutePath()) + .hasMessageContaining("'container_name' property set for service 'redis'"); + } + + @Test + public void shouldRejectContainerNameV1() { + Assertions + .assertThatThrownBy(() -> { + new ParsedDockerComposeFile(ImmutableMap.of( + "redis", ImmutableMap.of("container_name", "redis") + )); + }) + .hasMessageContaining("'container_name' property set for service 'redis'"); + } + + @Test + public void shouldRejectContainerNameV2() { + Assertions + .assertThatThrownBy(() -> { + new ParsedDockerComposeFile(ImmutableMap.of( + "version", "2", + "services", ImmutableMap.of( + "redis", ImmutableMap.of("container_name", "redis") + ) + )); + }) + .hasMessageContaining("'container_name' property set for service 'redis'"); + } + + @Test + public void shouldIgnoreUnknownStructure() { + // Everything is a list + new ParsedDockerComposeFile(emptyMap()); + + // services is not a map but List + new ParsedDockerComposeFile(ImmutableMap.of( + "version", "2", + "services", emptyList() + )); + + // services is not a collection + new ParsedDockerComposeFile(ImmutableMap.of( + "version", "2", + "services", true + )); + + // no services while version is defined + new ParsedDockerComposeFile(ImmutableMap.of( + "version", "9000" + )); + } + + @Test + public void shouldObtainImageNamesV1() { + File file = new File("src/test/resources/docker-compose-imagename-parsing-v1.yml"); + ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); + assertEquals("all defined service names are found", Sets.newHashSet("redis", "mysql"), parsedFile.getServiceImageNames()); + } + + @Test + public void shouldObtainImageNamesV2() { + File file = new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"); + ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); + assertEquals("all defined service names are found", Sets.newHashSet("redis", "mysql"), parsedFile.getServiceImageNames()); + } +} diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java index c48cff1ff14..b8e26ffd3f1 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java @@ -1,29 +1,20 @@ package org.testcontainers.junit; import org.junit.Test; -import org.junit.runner.Description; import org.rnorth.visibleassertions.VisibleAssertions; -import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.DockerComposeContainer; import java.io.File; -/** - * Created by rnorth on 08/08/2015. - */ public class DockerComposeErrorHandlingTest { - @Test public void simpleTest() { - - DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/invalid-compose.yml")) - .withExposedService("something", 123); - VisibleAssertions.assertThrows("starting with an invalid docker-compose file throws an exception", - ContainerLaunchException.class, + IllegalArgumentException.class, () -> { - environment.starting(Description.createTestDescription(Object.class, "name")); + DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/invalid-compose.yml")) + .withExposedService("something", 123); }); } } diff --git a/core/src/test/resources/compose-test.yml b/core/src/test/resources/compose-test.yml index 2e54e9f30b1..7436db7d211 100644 --- a/core/src/test/resources/compose-test.yml +++ b/core/src/test/resources/compose-test.yml @@ -3,4 +3,4 @@ redis: db: image: orchardup/mysql environment: - MYSQL_DATABASE: wordpress \ No newline at end of file + MYSQL_DATABASE: wordpress diff --git a/core/src/test/resources/docker-compose-base.yml b/core/src/test/resources/docker-compose-base.yml index c2dda256277..585d3dead39 100644 --- a/core/src/test/resources/docker-compose-base.yml +++ b/core/src/test/resources/docker-compose-base.yml @@ -1,6 +1,6 @@ -version: '2' +version: '2.1' services: alpine: build: compose-dockerfile environment: - bar: base \ No newline at end of file + bar: base diff --git a/core/src/test/resources/docker-compose-imagename-parsing-v1.yml b/core/src/test/resources/docker-compose-imagename-parsing-v1.yml new file mode 100644 index 00000000000..c3ae53fa3a8 --- /dev/null +++ b/core/src/test/resources/docker-compose-imagename-parsing-v1.yml @@ -0,0 +1,6 @@ +redis: + image: redis +mysql: + image: mysql +custom: + build: . diff --git a/core/src/test/resources/docker-compose-imagename-parsing-v2.yml b/core/src/test/resources/docker-compose-imagename-parsing-v2.yml new file mode 100644 index 00000000000..71ca8409f27 --- /dev/null +++ b/core/src/test/resources/docker-compose-imagename-parsing-v2.yml @@ -0,0 +1,10 @@ +version: "2.1" +services: + redis: + image: redis + mysql: + image: mysql + custom: + build: . +networks: + custom_network: {} diff --git a/core/src/test/resources/docker-compose-non-default-override.yml b/core/src/test/resources/docker-compose-non-default-override.yml index fa7acb70dfd..19f80a31c83 100644 --- a/core/src/test/resources/docker-compose-non-default-override.yml +++ b/core/src/test/resources/docker-compose-non-default-override.yml @@ -1,5 +1,5 @@ -version: '2' +version: '2.1' services: alpine: environment: - bar: overwritten \ No newline at end of file + bar: overwritten diff --git a/core/src/test/resources/local-compose-test.yml b/core/src/test/resources/local-compose-test.yml index 8d4f20e6924..b5f61be041b 100644 --- a/core/src/test/resources/local-compose-test.yml +++ b/core/src/test/resources/local-compose-test.yml @@ -1,4 +1,4 @@ -version: '2' +version: '2.1' services: redis: image: redis-local:latest diff --git a/core/src/test/resources/v2-compose-test-passthrough.yml b/core/src/test/resources/v2-compose-test-passthrough.yml index b52f2d28b0e..f96aff26f75 100644 --- a/core/src/test/resources/v2-compose-test-passthrough.yml +++ b/core/src/test/resources/v2-compose-test-passthrough.yml @@ -1,4 +1,4 @@ -version: '2' +version: '2.1' services: alpine: build: compose-dockerfile diff --git a/core/src/test/resources/v2-compose-test-with-network.yml b/core/src/test/resources/v2-compose-test-with-network.yml index 82b54a85823..89301c7918a 100644 --- a/core/src/test/resources/v2-compose-test-with-network.yml +++ b/core/src/test/resources/v2-compose-test-with-network.yml @@ -1,4 +1,4 @@ -version: '2' +version: '2.1' services: redis: image: redis diff --git a/core/src/test/resources/v2-compose-test.yml b/core/src/test/resources/v2-compose-test.yml index d439945d236..a9090c55671 100644 --- a/core/src/test/resources/v2-compose-test.yml +++ b/core/src/test/resources/v2-compose-test.yml @@ -1,4 +1,4 @@ -version: '2' +version: '2.1' services: redis: image: redis diff --git a/modules/junit-jupiter/src/test/resources/docker-compose.yml b/modules/junit-jupiter/src/test/resources/docker-compose.yml index ec1015f106a..810c7c178b5 100644 --- a/modules/junit-jupiter/src/test/resources/docker-compose.yml +++ b/modules/junit-jupiter/src/test/resources/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2' +version: '2.1' services: whoami: image: emilevauge/whoami diff --git a/modules/spock/src/test/resources/docker-compose.yml b/modules/spock/src/test/resources/docker-compose.yml index ec1015f106a..810c7c178b5 100644 --- a/modules/spock/src/test/resources/docker-compose.yml +++ b/modules/spock/src/test/resources/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2' +version: '2.1' services: whoami: image: emilevauge/whoami From 8fb199ff32386f5f83961a60471ef10e7a379a72 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 27 Nov 2019 09:38:05 +0100 Subject: [PATCH 0398/4969] Mock TestcontainersConfiguration in ReusabilityUnitTests (#2080) --- .../utility/TestcontainersConfiguration.java | 11 +++++- .../containers/ReusabilityUnitTests.java | 39 +++++++++++-------- .../MockTestcontainersConfigurationRule.java | 36 +++++++++++++++++ 3 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 1387dc6b9cd..64ee03efb06 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -1,5 +1,6 @@ package org.testcontainers.utility; +import com.google.common.annotations.VisibleForTesting; import lombok.*; import lombok.extern.slf4j.Slf4j; import org.testcontainers.UnstableAPI; @@ -9,6 +10,7 @@ import java.net.URL; import java.util.Objects; import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; /** @@ -24,7 +26,14 @@ public class TestcontainersConfiguration { private static File ENVIRONMENT_CONFIG_FILE = new File(System.getProperty("user.home"), "." + PROPERTIES_FILE_NAME); @Getter(lazy = true) - private static final TestcontainersConfiguration instance = loadConfiguration(); + private static final TestcontainersConfiguration instance = loadConfiguration();; + + @SuppressWarnings({"ConstantConditions", "unchecked", "rawtypes"}) + @VisibleForTesting + static AtomicReference getInstanceField() { + // Lazy Getter from Lombok changes the field's type to AtomicReference + return (AtomicReference) (Object) instance; + } @Getter(AccessLevel.NONE) private final Properties environmentProperties; diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 2d0f7a8133a..3f7c7d75b45 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -11,7 +11,7 @@ import com.github.dockerjava.core.command.StartContainerCmdImpl; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; -import org.junit.Assume; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; @@ -23,6 +23,7 @@ import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; +import org.testcontainers.utility.MockTestcontainersConfigurationRule; import org.testcontainers.utility.TestcontainersConfiguration; import java.util.ArrayList; @@ -128,9 +129,8 @@ protected void containerIsStarted(InspectContainerResponse containerInfo, boolea @Test public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { - // TODO mock TestcontainersConfiguration - Assume.assumeFalse("does not support reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); - AtomicReference commandRef = new AtomicReference<>(); + Mockito.doReturn(false).when(TestcontainersConfiguration.getInstance()).environmentSupportsReuse(); + String containerId = randomContainerId(); when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); when(client.listContainersCmd()).then(listContainersAnswer()); @@ -147,8 +147,7 @@ public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { @Test public void shouldCallHookIfReused() { - // TODO mock TestcontainersConfiguration - Assume.assumeTrue("supports reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); + Mockito.doReturn(true).when(TestcontainersConfiguration.getInstance()).environmentSupportsReuse(); String containerId = randomContainerId(); when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); String existingContainerId = randomContainerId(); @@ -200,8 +199,7 @@ public void shouldStartIfListReturnsEmpty() { @Test public void shouldReuseIfListReturnsID() { - // TODO mock TestcontainersConfiguration - Assume.assumeTrue("supports reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); + Mockito.doReturn(true).when(TestcontainersConfiguration.getInstance()).environmentSupportsReuse(); String containerId = randomContainerId(); when(client.createContainerCmd(any())).then(createContainerAnswer(containerId)); String existingContainerId = randomContainerId(); @@ -216,8 +214,7 @@ public void shouldReuseIfListReturnsID() { @Test public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { - // TODO mock TestcontainersConfiguration - Assume.assumeFalse("does not support reuse", TestcontainersConfiguration.getInstance().environmentSupportsReuse()); + Mockito.doReturn(false).when(TestcontainersConfiguration.getInstance()).environmentSupportsReuse(); AtomicReference commandRef = new AtomicReference<>(); String containerId = randomContainerId(); when(client.createContainerCmd(any())).then(createContainerAnswer(containerId, commandRef::set)); @@ -236,7 +233,10 @@ public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { } @FieldDefaults(makeFinal = true) - static abstract class AbstractReusabilityTest { + public static abstract class AbstractReusabilityTest { + + @Rule + public MockTestcontainersConfigurationRule configurationMock = new MockTestcontainersConfigurationRule(); protected DockerClient client = Mockito.mock(DockerClient.class); @@ -244,11 +244,18 @@ protected > T makeReusable(T container) { container.dockerClient = client; container.withNetworkMode("none"); // to disable the port forwarding container.withStartupCheckStrategy(new StartupCheckStrategy() { - @Override - public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { - return StartupStatus.SUCCESSFUL; - } - }); + + @Override + public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { + // Skip DockerClient rate limiter + return true; + } + + @Override + public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { + return StartupStatus.SUCCESSFUL; + } + }); container.waitingFor(new AbstractWaitStrategy() { @Override protected void waitUntilReady() { diff --git a/core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java b/core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java new file mode 100644 index 00000000000..4d156fd752e --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java @@ -0,0 +1,36 @@ +package org.testcontainers.utility; + +import org.jetbrains.annotations.NotNull; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.mockito.Mockito; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * This {@link TestRule} applies a spy on {@link TestcontainersConfiguration} + * for testing features that depend on the global configuration. + */ +public class MockTestcontainersConfigurationRule implements TestRule { + + static AtomicReference REF = TestcontainersConfiguration.getInstanceField(); + + @NotNull + @Override + public Statement apply(@NotNull Statement base, @NotNull Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + TestcontainersConfiguration previous = REF.get(); + REF.set(Mockito.spy(previous)); + + try { + base.evaluate(); + } finally { + REF.set(previous); + } + } + }; + } +} From 17d86c94dae3ac21c4c8c1949b72fe7a770eb3a9 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 27 Nov 2019 16:56:15 +0100 Subject: [PATCH 0399/4969] Image pull policy (#2024) See #1345 by @dmarkhas Fixes #1324 --- .../testcontainers/DockerClientFactory.java | 4 + .../{containers => }/LazyDockerClient.java | 5 +- .../testcontainers/containers/Container.java | 7 + .../containers/GenericContainer.java | 31 +-- .../AuditLoggingDockerClient.java | 4 + .../images/AbstractImagePullPolicy.java | 49 +++++ .../images/AgeBasedPullPolicy.java | 28 +++ .../images/AlwaysPullPolicy.java | 20 ++ .../images/DefaultPullPolicy.java | 18 ++ .../org/testcontainers/images/ImageData.java | 29 +++ .../images/ImagePullPolicy.java | 9 + .../images/LocalImagesCache.java | 89 +++++++++ .../org/testcontainers/images/PullPolicy.java | 38 ++++ .../images/RemoteDockerImage.java | 80 ++++---- .../images/AgeBasedPullPolicyTest.java | 30 +++ .../images/ImagePullPolicyTest.java | 178 ++++++++++++++++++ .../junit/NonExistentImagePullTest.java | 2 +- docs/features/advanced_options.md | 16 ++ 18 files changed, 575 insertions(+), 62 deletions(-) rename core/src/main/java/org/testcontainers/{containers => }/LazyDockerClient.java (75%) create mode 100644 core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java create mode 100644 core/src/main/java/org/testcontainers/images/AgeBasedPullPolicy.java create mode 100644 core/src/main/java/org/testcontainers/images/AlwaysPullPolicy.java create mode 100644 core/src/main/java/org/testcontainers/images/DefaultPullPolicy.java create mode 100644 core/src/main/java/org/testcontainers/images/ImageData.java create mode 100644 core/src/main/java/org/testcontainers/images/ImagePullPolicy.java create mode 100644 core/src/main/java/org/testcontainers/images/LocalImagesCache.java create mode 100644 core/src/main/java/org/testcontainers/images/PullPolicy.java create mode 100644 core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java create mode 100644 core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 928b4cad291..54f44dbed3c 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -81,6 +81,10 @@ private DockerClientFactory() { } + public static DockerClient lazyClient() { + return LazyDockerClient.INSTANCE; + } + /** * Obtain an instance of the DockerClientFactory. * diff --git a/core/src/main/java/org/testcontainers/containers/LazyDockerClient.java b/core/src/main/java/org/testcontainers/LazyDockerClient.java similarity index 75% rename from core/src/main/java/org/testcontainers/containers/LazyDockerClient.java rename to core/src/main/java/org/testcontainers/LazyDockerClient.java index b1341b52755..49ebf9330a7 100644 --- a/core/src/main/java/org/testcontainers/containers/LazyDockerClient.java +++ b/core/src/main/java/org/testcontainers/LazyDockerClient.java @@ -1,9 +1,10 @@ -package org.testcontainers.containers; +package org.testcontainers; import com.github.dockerjava.api.DockerClient; +import lombok.ToString; import lombok.experimental.Delegate; -import org.testcontainers.DockerClientFactory; +@ToString enum LazyDockerClient implements DockerClient { INSTANCE; diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index ca327149ab5..ef27a95a463 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -8,6 +8,7 @@ import lombok.NonNull; import lombok.Value; import org.testcontainers.DockerClientFactory; +import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.traits.LinkableContainer; @@ -283,6 +284,12 @@ default SELF withEnv(String key, Function, String> mapper) { */ SELF withNetworkAliases(String... aliases); + /** + * Set the image pull policy of the container + * @return + */ + SELF withImagePullPolicy(ImagePullPolicy policy); + /** * Map a resource (file or directory) on the classpath to a path inside the container. * This will only work if you are running your tests outside a Docker container. diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 47d08b57528..94ce6f64518 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -41,6 +41,7 @@ import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.UnstableAPI; +import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.startupcheck.IsRunningStartupCheckStrategy; import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy; @@ -139,7 +140,7 @@ public class GenericContainer> )); @NonNull - private Future image; + private RemoteDockerImage image; @NonNull private Map env = new HashMap<>(); @@ -185,10 +186,10 @@ public class GenericContainer> /** * Unique instance of DockerClient for use by this container object. - * We use {@link LazyDockerClient} here to avoid eager client creation + * We use {@link DockerClientFactory#lazyClient()} here to avoid eager client creation */ @Setter(AccessLevel.NONE) - protected DockerClient dockerClient = LazyDockerClient.INSTANCE; + protected DockerClient dockerClient = DockerClientFactory.lazyClient(); /* * Info about the Docker server; lazily fetched. @@ -250,7 +251,11 @@ public GenericContainer(@NonNull final String dockerImageName) { } public GenericContainer(@NonNull final Future image) { - this.image = image; + setImage(image); + } + + public void setImage(Future image) { + this.image = new RemoteDockerImage(image); } /** @@ -297,11 +302,11 @@ protected void doStart() { Instant startedAt = Instant.now(); logger().debug("Starting container: {}", getDockerImageName()); - logger().debug("Trying to start container: {}", image.get()); + logger().debug("Trying to start container: {}", getDockerImageName()); AtomicInteger attempt = new AtomicInteger(0); Unreliables.retryUntilSuccess(startupAttempts, () -> { - logger().debug("Trying to start container: {} (attempt {}/{})", image.get(), attempt.incrementAndGet(), startupAttempts); + logger().debug("Trying to start container: {} (attempt {}/{})", getDockerImageName(), attempt.incrementAndGet(), startupAttempts); tryStart(startedAt); return true; }); @@ -331,7 +336,7 @@ protected boolean canBeReused() { private void tryStart(Instant startedAt) { try { - String dockerImageName = image.get(); + String dockerImageName = getDockerImageName(); logger().debug("Starting container: {}", dockerImageName); logger().info("Creating container for image: {}", dockerImageName); @@ -530,7 +535,7 @@ public void stop() { String imageName; try { - imageName = image.get(); + imageName = getDockerImageName(); } catch (Exception e) { imageName = ""; } @@ -571,7 +576,6 @@ protected Path createVolumeDirectory(boolean temporary) { } protected void configure() { - } @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) @@ -1107,6 +1111,12 @@ public SELF withNetworkAliases(String... aliases) { return self(); } + @Override + public SELF withImagePullPolicy(ImagePullPolicy imagePullPolicy) { + this.image = this.image.withImagePullPolicy(imagePullPolicy); + return self(); + } + /** * {@inheritDoc} */ @@ -1199,9 +1209,6 @@ public String getIpAddress() { @Override public void setDockerImageName(@NonNull String dockerImageName) { this.image = new RemoteDockerImage(dockerImageName); - - // Mimic old behavior where we resolve image once it's set - getDockerImageName(); } /** diff --git a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java index 4250b884a74..f982945f9d4 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; import java.util.function.BiConsumer; @@ -99,6 +100,9 @@ private , R> T wrappedCommand(Class clazz, successConsumer.accept(cmd, r); return r; } catch (Exception e) { + if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) { + e = (Exception) e.getCause(); + } failureConsumer.accept(cmd, e); throw e; } diff --git a/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java b/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java new file mode 100644 index 00000000000..11c621eb08b --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java @@ -0,0 +1,49 @@ +package org.testcontainers.images; + +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.DockerLoggerFactory; + +@Slf4j +public abstract class AbstractImagePullPolicy implements ImagePullPolicy { + + private static final LocalImagesCache LOCAL_IMAGES_CACHE = LocalImagesCache.INSTANCE; + + @Override + public boolean shouldPull(DockerImageName imageName) { + Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); + + // Does our cache already know the image? + ImageData cachedImageData = LOCAL_IMAGES_CACHE.get(imageName); + if (cachedImageData != null) { + logger.trace("{} is already in image name cache", imageName); + } else { + logger.debug("{} is not in image name cache, updating...", imageName); + // Was not in cache, inspecting... + cachedImageData = LOCAL_IMAGES_CACHE.refreshCache(imageName).orElse(null); + + if (cachedImageData == null) { + log.debug("Not available locally, should pull image: {}", imageName); + return true; + } + } + + if (shouldPullCached(imageName, cachedImageData)) { + log.debug("Should pull locally available image: {}", imageName); + return true; + } else { + log.debug("Using locally available and not pulling image: {}", imageName); + return false; + } + + } + + /** + * Implement this method to decide whether a locally available image should be pulled + * (e.g. to always pull images, or to pull them after some duration of time) + * + * @return {@code true} to update the locally available image, {@code false} to use local instead + */ + abstract protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData); +} diff --git a/core/src/main/java/org/testcontainers/images/AgeBasedPullPolicy.java b/core/src/main/java/org/testcontainers/images/AgeBasedPullPolicy.java new file mode 100644 index 00000000000..39028d6c52b --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/AgeBasedPullPolicy.java @@ -0,0 +1,28 @@ +package org.testcontainers.images; + +import lombok.Value; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.utility.DockerImageName; + +import java.time.Duration; +import java.time.Instant; + +/** + * An ImagePullPolicy which pulls the image from a remote repository only if its created date is older than maxAge + */ +@Slf4j +@Value +class AgeBasedPullPolicy extends AbstractImagePullPolicy { + + Duration maxAge; + + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + Duration imageAge = Duration.between(localImageData.getCreatedAt(), Instant.now()); + boolean result = imageAge.compareTo(maxAge) > 0; + if (result) { + log.trace("Should pull image: {}", imageName); + } + return result; + } +} diff --git a/core/src/main/java/org/testcontainers/images/AlwaysPullPolicy.java b/core/src/main/java/org/testcontainers/images/AlwaysPullPolicy.java new file mode 100644 index 00000000000..92f94f67124 --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/AlwaysPullPolicy.java @@ -0,0 +1,20 @@ +package org.testcontainers.images; + +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.utility.DockerImageName; + +/*** + * An ImagePullPolicy which pulls the image even if it exists locally. + * Useful for obtaining the latest version of an image with a static tag, i.e. 'latest' + */ +@Slf4j +@ToString +class AlwaysPullPolicy implements ImagePullPolicy { + + @Override + public boolean shouldPull(DockerImageName imageName) { + log.trace("Unconditionally pulling an image: {}", imageName); + return true; + } +} diff --git a/core/src/main/java/org/testcontainers/images/DefaultPullPolicy.java b/core/src/main/java/org/testcontainers/images/DefaultPullPolicy.java new file mode 100644 index 00000000000..40984b2940e --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/DefaultPullPolicy.java @@ -0,0 +1,18 @@ +package org.testcontainers.images; + +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.utility.DockerImageName; + +/** + * The default imagePullPolicy, which pulls the image from a remote repository only if it does not exist locally + */ +@Slf4j +@ToString +class DefaultPullPolicy extends AbstractImagePullPolicy { + + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + return false; + } +} diff --git a/core/src/main/java/org/testcontainers/images/ImageData.java b/core/src/main/java/org/testcontainers/images/ImageData.java new file mode 100644 index 00000000000..bef0c56c245 --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/ImageData.java @@ -0,0 +1,29 @@ +package org.testcontainers.images; + +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.model.Image; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; + +import java.time.Instant; + +@Value +@Builder +class ImageData { + + @NonNull + Instant createdAt; + + static ImageData from(InspectImageResponse inspectImageResponse) { + return ImageData.builder() + .createdAt(Instant.parse(inspectImageResponse.getCreated())) + .build(); + } + + static ImageData from(Image image) { + return ImageData.builder() + .createdAt(Instant.ofEpochMilli(image.getCreated())) + .build(); + } +} diff --git a/core/src/main/java/org/testcontainers/images/ImagePullPolicy.java b/core/src/main/java/org/testcontainers/images/ImagePullPolicy.java new file mode 100644 index 00000000000..e821e511795 --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/ImagePullPolicy.java @@ -0,0 +1,9 @@ +package org.testcontainers.images; + +import org.testcontainers.utility.DockerImageName; + +public interface ImagePullPolicy { + + boolean shouldPull(DockerImageName imageName); + +} diff --git a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java new file mode 100644 index 00000000000..29bc8ef1408 --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java @@ -0,0 +1,89 @@ +package org.testcontainers.images; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Image; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.utility.DockerImageName; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Slf4j +enum LocalImagesCache { + INSTANCE; + + private final AtomicBoolean initialized = new AtomicBoolean(false); + + @VisibleForTesting + final Map cache = new ConcurrentHashMap<>(); + + DockerClient dockerClient = DockerClientFactory.lazyClient(); + + public ImageData get(DockerImageName imageName) { + maybeInitCache(); + return cache.get(imageName); + } + + public Optional refreshCache(DockerImageName imageName) { + if (!maybeInitCache()) { + // Cache may be stale, trying inspectImageCmd... + + InspectImageResponse response = null; + try { + response = dockerClient.inspectImageCmd(imageName.toString()).exec(); + } catch (NotFoundException e) { + log.trace("Image {} not found", imageName, e); + } + if (response != null) { + ImageData imageData = ImageData.from(response); + cache.put(imageName, imageData); + return Optional.of(imageData); + } else { + cache.remove(imageName); + return Optional.empty(); + } + } + + return Optional.ofNullable(cache.get(imageName)); + } + + private synchronized boolean maybeInitCache() { + if (!initialized.compareAndSet(false, true)) { + return false; + } + + if (Boolean.parseBoolean(System.getProperty("useFilter"))) { + return false; + } + + populateFromList(dockerClient.listImagesCmd().exec()); + + return true; + } + + private void populateFromList(List images) { + for (Image image : images) { + String[] repoTags = image.getRepoTags(); + if (repoTags == null) { + log.debug("repoTags is null, skipping image: {}", image); + continue; + } + + cache.putAll( + Stream.of(repoTags).collect(Collectors.toMap( + DockerImageName::new, + it -> ImageData.from(image) + )) + ); + } + } +} diff --git a/core/src/main/java/org/testcontainers/images/PullPolicy.java b/core/src/main/java/org/testcontainers/images/PullPolicy.java new file mode 100644 index 00000000000..3dc2e452b8d --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/PullPolicy.java @@ -0,0 +1,38 @@ +package org.testcontainers.images; + +import java.time.Duration; + +import lombok.experimental.UtilityClass; + +/** + * Convenience class with logic for building common {@link ImagePullPolicy} instances. + * + */ +@UtilityClass +public class PullPolicy { + + /** + * Convenience method for returning the {@link DefaultPullPolicy} default image pull policy + * @return {@link ImagePullPolicy} + */ + public static ImagePullPolicy defaultPolicy() { + return new DefaultPullPolicy(); + } + + /** + * Convenience method for returning the {@link AlwaysPullPolicy} alwaysPull image pull policy + * @return {@link ImagePullPolicy} + */ + public static ImagePullPolicy alwaysPull() { + return new AlwaysPullPolicy(); + } + + /** + * Convenience method for returning an {@link AgeBasedPullPolicy} Age based image pull policy, + * @return {@link ImagePullPolicy} + */ + public static ImagePullPolicy ageBased(Duration maxAge) { + return new AgeBasedPullPolicy(maxAge); + } + +} diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index 257bacc9961..4975f536384 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -1,13 +1,14 @@ package org.testcontainers.images; import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.command.ListImagesCmd; import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.exception.InternalServerErrorException; -import com.github.dockerjava.api.model.Image; -import com.github.dockerjava.core.command.PullImageResultCallback; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.NonNull; +import lombok.SneakyThrows; import lombok.ToString; +import lombok.experimental.Wither; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.ContainerFetchException; @@ -17,63 +18,48 @@ import java.time.Duration; import java.time.Instant; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; @ToString +@AllArgsConstructor(access = AccessLevel.PACKAGE) public class RemoteDockerImage extends LazyFuture { - /** - * @deprecated this field will become private in a later release - */ - @Deprecated - public static final Set AVAILABLE_IMAGE_NAME_CACHE = new HashSet<>(); private static final Duration PULL_RETRY_TIME_LIMIT = Duration.ofMinutes(2); - private DockerImageName imageName; + private Future imageNameFuture; + + @Wither + private ImagePullPolicy imagePullPolicy = PullPolicy.defaultPolicy(); + + private DockerClient dockerClient = DockerClientFactory.lazyClient(); public RemoteDockerImage(String dockerImageName) { - imageName = new DockerImageName(dockerImageName); + this.imageNameFuture = CompletableFuture.completedFuture(new DockerImageName(dockerImageName)); } public RemoteDockerImage(@NonNull String repository, @NonNull String tag) { - imageName = new DockerImageName(repository, tag); + this.imageNameFuture = CompletableFuture.completedFuture(new DockerImageName(repository, tag)); + } + + public RemoteDockerImage(@NonNull Future imageFuture) { + this.imageNameFuture = new LazyFuture() { + @Override + @SneakyThrows({InterruptedException.class, ExecutionException.class}) + protected DockerImageName resolve() { + return new DockerImageName(imageFuture.get()); + } + }; } @Override + @SneakyThrows({InterruptedException.class, ExecutionException.class}) protected final String resolve() { + final DockerImageName imageName = imageNameFuture.get(); Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); - - DockerClient dockerClient = DockerClientFactory.instance().client(); try { - // Does our cache already know the image? - if (AVAILABLE_IMAGE_NAME_CACHE.contains(imageName)) { - logger.trace("{} is already in image name cache", imageName); - return imageName.toString(); - } - - // Update the cache - ListImagesCmd listImagesCmd = dockerClient.listImagesCmd(); - - if (Boolean.parseBoolean(System.getProperty("useFilter"))) { - listImagesCmd = listImagesCmd.withImageNameFilter(imageName.toString()); - } - - List updatedImages = listImagesCmd.exec(); - updatedImages.stream() - .map(Image::getRepoTags) - .filter(Objects::nonNull) - .flatMap(Stream::of) - .map(DockerImageName::new) - .collect(Collectors.toCollection(() -> AVAILABLE_IMAGE_NAME_CACHE)); - - // And now? - if (AVAILABLE_IMAGE_NAME_CACHE.contains(imageName)) { - logger.trace("{} is in image name cache following listing of images", imageName); + if (!imagePullPolicy.shouldPull(imageName)) { return imageName.toString(); } @@ -85,13 +71,13 @@ protected final String resolve() { while (Instant.now().isBefore(lastRetryAllowed)) { try { - final PullImageResultCallback callback = new TimeLimitedLoggedPullImageResultCallback(logger); dockerClient .pullImageCmd(imageName.getUnversionedPart()) .withTag(imageName.getVersionPart()) - .exec(callback); - callback.awaitCompletion(); - AVAILABLE_IMAGE_NAME_CACHE.add(imageName); + .exec(new TimeLimitedLoggedPullImageResultCallback(logger)) + .awaitCompletion(); + + LocalImagesCache.INSTANCE.refreshCache(imageName); return imageName.toString(); } catch (InterruptedException | InternalServerErrorException e) { diff --git a/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java new file mode 100644 index 00000000000..20b52798d40 --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java @@ -0,0 +1,30 @@ +package org.testcontainers.images; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.UUID; + +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + +public class AgeBasedPullPolicyTest { + + final DockerImageName imageName = new DockerImageName(UUID.randomUUID().toString()); + + @Test + public void shouldPull() { + ImageData imageData = ImageData.builder() + .createdAt(Instant.now().minus(2, ChronoUnit.HOURS)) + .build(); + + AgeBasedPullPolicy oneHour = new AgeBasedPullPolicy(Duration.of(1L, ChronoUnit.HOURS)); + assertTrue(oneHour.shouldPullCached(imageName, imageData)); + + AgeBasedPullPolicy fiveHours = new AgeBasedPullPolicy(Duration.of(5L, ChronoUnit.HOURS)); + assertFalse(fiveHours.shouldPullCached(imageName, imageData)); + } +} diff --git a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java new file mode 100644 index 00000000000..59b7486c75e --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java @@ -0,0 +1,178 @@ +package org.testcontainers.images; + +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.core.command.PullImageResultCallback; +import com.github.dockerjava.core.command.PushImageResultCallback; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.mockito.Mockito; +import org.rnorth.visibleassertions.VisibleAssertions; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.utility.DockerImageName; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class ImagePullPolicyTest { + + @ClassRule + public static GenericContainer registry = new GenericContainer<>("registry:2") + .withExposedPorts(5000); + + private static String imageName; + + @BeforeClass + public static void beforeClass() throws Exception { + String testRegistryAddress = registry.getContainerIpAddress() + ":" + registry.getFirstMappedPort(); + String testImageName = testRegistryAddress + "/image-pull-policy-test"; + String tag = UUID.randomUUID().toString(); + imageName = testImageName + ":" + tag; + + DockerClient client = DockerClientFactory.instance().client(); + String dummySourceImage = "hello-world:latest"; + client.pullImageCmd(dummySourceImage).exec(new PullImageResultCallback()).awaitCompletion(); + + String dummyImageId = client.inspectImageCmd(dummySourceImage).exec().getId(); + + // push the image to the registry + client.tagImageCmd(dummyImageId, testImageName, tag).exec(); + + client.pushImageCmd(imageName) + .exec(new PushImageResultCallback()) + .awaitCompletion(1, TimeUnit.MINUTES); + } + + @AfterClass + public static void afterClass() { + try { + DockerClientFactory.instance().client().removeImageCmd(imageName).withForce(true).exec(); + } catch (NotFoundException ignored) { + } + } + + @Before + public void setUp() { + // Clean up local cache + try { + DockerClientFactory.instance().client().removeImageCmd(imageName).withForce(true).exec(); + } catch (NotFoundException ignored) { + } + + LocalImagesCache.INSTANCE.cache.remove(new DockerImageName(imageName)); + } + + @Test + public void pullsByDefault() { + try ( + GenericContainer container = new GenericContainer<>(imageName) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + } + } + + @Test + public void shouldAlwaysPull() { + try ( + GenericContainer container = new GenericContainer<>(imageName) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + } + + DockerClientFactory.instance().client().removeImageCmd(imageName).withForce(true).exec(); + + try ( + GenericContainer container = new GenericContainer<>(imageName) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + expectToFailWithNotFoundException(container); + } + + try ( + // built_in_image_pull_policy { + GenericContainer container = new GenericContainer<>(imageName) + .withImagePullPolicy(PullPolicy.alwaysPull()) + // } + ) { + container.withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + container.start(); + } + } + + @Test + public void shouldSupportCustomPolicies() { + try ( + // custom_image_pull_policy { + GenericContainer container = new GenericContainer<>(imageName) + .withImagePullPolicy(new AbstractImagePullPolicy() { + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + return System.getenv("ALWAYS_PULL_IMAGE") != null; + } + }) + // } + ) { + container.withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + container.start(); + } + } + + @Test + public void shouldCheckPolicy() { + ImagePullPolicy policy = Mockito.spy(new AbstractImagePullPolicy() { + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + return false; + } + }); + try ( + GenericContainer container = new GenericContainer<>(imageName) + .withImagePullPolicy(policy) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + + Mockito.verify(policy).shouldPull(any()); + } + } + + @Test + public void shouldNotForcePulling() { + try ( + GenericContainer container = new GenericContainer<>(imageName) + .withImagePullPolicy(__ -> false) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + expectToFailWithNotFoundException(container); + } + } + + private void expectToFailWithNotFoundException(GenericContainer container) { + try { + container.start(); + fail("Should fail"); + } catch (ContainerLaunchException e) { + Throwable throwable = e; + while (throwable.getCause() != null) { + throwable = throwable.getCause(); + if (throwable.getCause() instanceof NotFoundException) { + VisibleAssertions.pass("Caused by NotFoundException"); + return; + } + } + VisibleAssertions.fail("Caused by NotFoundException"); + } + } + +} diff --git a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java index 22c7b4e9d9c..d842829b4b6 100644 --- a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java +++ b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java @@ -16,7 +16,7 @@ public void pullingNonExistentImageFailsGracefully() { assertThrows("Pulling a nonexistent container will cause an exception to be thrown", ContainerFetchException.class, () -> { - return new GenericContainer("richnorth/nonexistent:latest"); + new GenericContainer("richnorth/nonexistent:latest").getDockerImageName(); }); } } diff --git a/docs/features/advanced_options.md b/docs/features/advanced_options.md index 385cdc3a4c8..bedb7aee6b8 100644 --- a/docs/features/advanced_options.md +++ b/docs/features/advanced_options.md @@ -14,6 +14,22 @@ Additionally, multiple labels may be applied together from a map: [Adding multiple labels](../examples/src/test/java/generic/ContainerLabelTest.java) inside_block:multiple_labels +## Image Pull Policy + +By default, the container image is retrieved from the local Docker images cache. +This works well when running against a specific version, but for images with a static tag (i.e. 'latest') this may lead to a newer version not being pulled. + +It is possible to specify an Image Pull Policy to determine at runtime whether an image should be pulled or not: + + +[Setting image pull policy](../../core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java) inside_block:built_in_image_pull_policy + + +... or providing a function: + + +[Custom image pull policy](../../core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java) inside_block:custom_image_pull_policy + ## Customizing the container From 22a5e92fc26d27023bcbde8da3750451250bef58 Mon Sep 17 00:00:00 2001 From: Erhun Baycelik Date: Wed, 27 Nov 2019 17:59:42 +0100 Subject: [PATCH 0400/4969] Update Who Is Using Testcontainers (#2105) As a Transferwise engineer I want to list our company in this list. --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 8f95ad5399a..c26ed164067 100644 --- a/docs/index.md +++ b/docs/index.md @@ -77,6 +77,7 @@ You can also [check the latest version available on Maven Central](https://searc * [JHipster](https://www.jhipster.tech/) - Couchbase and Cassandra integration testing * [wescale](https://www.wescale.com) - Integration testing against HTTP service mocks and various data stores * [Marquez](https://marquezproject.github.io/marquez) - PostgreSQL integration testing +* [Transferwise](https://transferwise.com/) - Integration testing for different RDBMS, kafka and micro services ## License From 4f6f2c7cdf65f16952806ac91758ba0e3cf7e8d8 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 27 Nov 2019 19:08:04 +0100 Subject: [PATCH 0401/4969] Restore Flaky on couchbase tests (#2106) * Restore `@Flaky` in Couchbase tests (partially revert #2081) * Manually start/stop container, do not reuse environment/cluster --- .../couchbase/AbstractCouchbaseTest.java | 21 ++++++++++------ .../couchbase/CouchbaseContainer.java | 11 +++++++-- .../couchbase/BaseCouchbaseContainerTest.java | 24 +++++++++++++++++++ .../couchbase/Couchbase4_6Test.java | 7 +++--- .../couchbase/Couchbase5_1Test.java | 7 +++--- .../couchbase/Couchbase5_5Test.java | 7 +++--- .../couchbase/CouchbaseCommunity5_1Test.java | 7 +++--- 7 files changed, 63 insertions(+), 21 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java index e1aec0ba424..7fd99ca9fbc 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java @@ -10,6 +10,8 @@ import com.couchbase.client.java.query.consistency.ScanConsistency; import org.junit.After; +import java.util.concurrent.TimeUnit; + /** * Basic class that can be used for couchbase tests. It will clear the database after every test. */ @@ -19,16 +21,21 @@ public abstract class AbstractCouchbaseTest { public static final String DEFAULT_PASSWORD = "password"; - private Bucket bucket; + Bucket bucket; @After public void clear() { - if (getCouchbaseContainer().isIndex() && getCouchbaseContainer().isQuery() && getCouchbaseContainer().isPrimaryIndex()) { - getBucket().query( - N1qlQuery.simple(String.format("DELETE FROM `%s`", getBucket().name()), - N1qlParams.build().consistency(ScanConsistency.STATEMENT_PLUS))); - } else { - getBucket().bucketManager().flush(); + try { + if (getCouchbaseContainer().isIndex() && getCouchbaseContainer().isQuery() && getCouchbaseContainer().isPrimaryIndex()) { + getBucket().query( + N1qlQuery.simple(String.format("DELETE FROM `%s`", getBucket().name()), + N1qlParams.build().consistency(ScanConsistency.STATEMENT_PLUS))); + } else { + getBucket().bucketManager().flush(); + } + } finally { + bucket.close(60, TimeUnit.SECONDS); + bucket = null; } } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 9e7ace2af04..19583d5a0e4 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -47,6 +47,7 @@ import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -199,9 +200,15 @@ public List getBoundPortNumbers() { } @Override + @SuppressWarnings({"unchecked", "ConstantConditions"}) public void stop() { - stopCluster(); - Stream.of(super::stop, proxy::stop).parallel().forEach(Runnable::run); + try { + stopCluster(); + ((AtomicReference) (Object) couchbaseEnvironment).set(null); + ((AtomicReference) (Object) couchbaseCluster).set(null); + } finally { + Stream.of(super::stop, proxy::stop).parallel().forEach(Runnable::run); + } } private void stopCluster() { diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java index 845d9bfaf5e..6deba2c4c5e 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java @@ -9,7 +9,13 @@ import com.couchbase.client.java.view.View; import com.google.common.collect.Lists; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.runner.Description; +import org.testcontainers.containers.FailureDetectingExternalResource; +import org.testcontainers.testsupport.Flaky; +import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; import java.util.List; @@ -25,7 +31,23 @@ public abstract class BaseCouchbaseContainerTest extends AbstractCouchbaseTest { private static final String DOCUMENT = "{\"name\":\"toto\"}"; + @Rule + public RuleChain ruleChain = RuleChain.emptyRuleChain() + .around(new FlakyTestJUnit4RetryRule()) + .around(new FailureDetectingExternalResource() { + @Override + protected void starting(Description description) { + getCouchbaseContainer().start(); + } + + @Override + protected void failed(Throwable e, Description description) { + getCouchbaseContainer().stop(); + } + }); + @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldInsertDocument() { RawJsonDocument expected = RawJsonDocument.create(ID, DOCUMENT); getBucket().upsert(expected); @@ -34,6 +56,7 @@ public void shouldInsertDocument() { } @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldExecuteN1ql() { getBucket().query(N1qlQuery.simple("INSERT INTO " + TEST_BUCKET + " (KEY, VALUE) VALUES ('" + ID + "', " + DOCUMENT + ")")); @@ -46,6 +69,7 @@ public void shouldExecuteN1ql() { } @Test + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") public void shouldCreateView() { View view = DefaultView.create(VIEW_NAME, VIEW_FUNCTION); DesignDocument document = DesignDocument.create(VIEW_NAME, Lists.newArrayList(view)); diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java index 7781d705d41..c43d3c981ba 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java @@ -1,10 +1,11 @@ package org.testcontainers.couchbase; -import org.junit.ClassRule; +import org.junit.Rule; public class Couchbase4_6Test extends BaseCouchbaseContainerTest { - @ClassRule - public static CouchbaseContainer container = initCouchbaseContainer("couchbase/server:4.6.5"); + + @Rule + public CouchbaseContainer container = initCouchbaseContainer("couchbase/server:4.6.5"); @Override public CouchbaseContainer getCouchbaseContainer() { diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java index 8334088fdb3..2c3dbf3c901 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java @@ -1,10 +1,11 @@ package org.testcontainers.couchbase; -import org.junit.ClassRule; +import org.junit.Rule; public class Couchbase5_1Test extends BaseCouchbaseContainerTest { - @ClassRule - public static CouchbaseContainer container = initCouchbaseContainer("couchbase/server:5.1.1"); + + @Rule + public CouchbaseContainer container = initCouchbaseContainer("couchbase/server:5.1.1"); @Override public CouchbaseContainer getCouchbaseContainer() { diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java index 40a44235f20..47bc020ef03 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java @@ -1,10 +1,11 @@ package org.testcontainers.couchbase; -import org.junit.ClassRule; +import org.junit.Rule; public class Couchbase5_5Test extends BaseCouchbaseContainerTest { - @ClassRule - public static CouchbaseContainer container = initCouchbaseContainer("couchbase/server:5.5.1"); + + @Rule + public CouchbaseContainer container = initCouchbaseContainer("couchbase/server:5.5.1"); @Override public CouchbaseContainer getCouchbaseContainer() { diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java index 74298c990cf..30be62bc2bd 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java @@ -6,10 +6,12 @@ import com.couchbase.client.java.cluster.UserRole; import com.couchbase.client.java.cluster.UserSettings; +import org.junit.Rule; public class CouchbaseCommunity5_1Test extends BaseCouchbaseContainerTest { - @ClassRule - public static CouchbaseContainer container = initCouchbaseContainer(); + + @Rule + public CouchbaseContainer container = initCouchbaseContainer(); private static CouchbaseContainer initCouchbaseContainer() { CouchbaseContainer couchbaseContainer = new CouchbaseContainer("couchbase/server:community-5.1.1"); @@ -20,7 +22,6 @@ private static CouchbaseContainer initCouchbaseContainer() { .roles(Collections.singletonList(new UserRole("admin"))); couchbaseContainer.withNewBucket(getDefaultBucketSettings(), communityAdminUserSettings); - couchbaseContainer.start(); return couchbaseContainer; } From 23235833edfb1ae6c6c1147309aad4c067394728 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 27 Nov 2019 20:07:03 +0000 Subject: [PATCH 0402/4969] =?UTF-8?q?Break=20up=20quickstart=20example=20p?= =?UTF-8?q?rojects=20and=20introduce=20JUnit=205=20refe=E2=80=A6=20(#2097)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Break up quickstart example projects and introduce JUnit 5 refe… (#1416) * Break up quickstart example projects and introduce JUnit 5 reference * Use for dependency declarations Dependabot needs to be able to discover those and propose a change. * Relocate Spock example code Co-authored-by: Benjamin Muschko --- .../{ => junit4/generic}/build.gradle | 2 - .../test/java/generic/CmdModifierTest.java | 0 .../src/test/java/generic/CommandsTest.java | 0 .../java/generic/ContainerCreationTest.java | 0 .../test/java/generic/ContainerLabelTest.java | 0 .../src/test/java/generic/ExecTest.java | 0 .../java/generic/HostPortExposedTest.java | 0 .../generic/MultiplePortsExposedTest.java | 0 .../test/java/generic/WaitStrategiesTest.java | 0 docs/examples/junit4/redis/build.gradle | 8 ++ .../java/quickstart/RedisBackedCache.java | 0 .../quickstart/RedisBackedCacheIntTest.java | 0 .../RedisBackedCacheIntTestStep0.java | 0 .../src/test/resources/logback-test.xml | 0 docs/examples/junit5/redis/build.gradle | 11 ++ .../java/quickstart/RedisBackedCache.java | 0 .../quickstart/RedisBackedCacheIntTest.java | 42 +++++++ .../RedisBackedCacheIntTestStep0.java | 27 +++++ .../redis/src/test/resources/logback-test.xml | 27 +++++ .../examples/spock/redis}/build.gradle | 6 +- .../java/quickstart/RedisBackedCache.java | 22 ++++ .../quickstart/RedisBackedCacheIntTest.groovy | 0 .../RedisBackedCacheIntTestStep0.groovy | 0 .../src/test/resources/logback-test.xml | 0 docs/features/advanced_options.md | 8 +- docs/features/commands.md | 6 +- docs/features/creating_container.md | 4 +- docs/features/networking.md | 14 +-- docs/features/startup_and_waits.md | 14 +-- docs/quickstart/junit_4_quickstart.md | 8 +- docs/quickstart/junit_5_quickstart.md | 110 ++++++++++++++++++ docs/quickstart/spock_quickstart.md | 8 +- mkdocs.yml | 1 + settings.gradle | 7 +- 34 files changed, 285 insertions(+), 40 deletions(-) rename docs/examples/{ => junit4/generic}/build.gradle (81%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/CmdModifierTest.java (100%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/CommandsTest.java (100%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/ContainerCreationTest.java (100%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/ContainerLabelTest.java (100%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/ExecTest.java (100%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/HostPortExposedTest.java (100%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/MultiplePortsExposedTest.java (100%) rename docs/examples/{ => junit4/generic}/src/test/java/generic/WaitStrategiesTest.java (100%) create mode 100644 docs/examples/junit4/redis/build.gradle rename docs/examples/{ => junit4/redis}/src/main/java/quickstart/RedisBackedCache.java (100%) rename docs/examples/{ => junit4/redis}/src/test/java/quickstart/RedisBackedCacheIntTest.java (100%) rename docs/examples/{ => junit4/redis}/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java (100%) rename docs/examples/{ => junit4/redis}/src/test/resources/logback-test.xml (100%) create mode 100644 docs/examples/junit5/redis/build.gradle rename {examples/spock => docs/examples/junit5/redis}/src/main/java/quickstart/RedisBackedCache.java (100%) create mode 100644 docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java create mode 100644 docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java create mode 100644 docs/examples/junit5/redis/src/test/resources/logback-test.xml rename {examples/spock => docs/examples/spock/redis}/build.gradle (74%) create mode 100644 docs/examples/spock/redis/src/main/java/quickstart/RedisBackedCache.java rename {examples/spock => docs/examples/spock/redis}/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy (100%) rename {examples/spock => docs/examples/spock/redis}/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy (100%) rename {examples/spock => docs/examples/spock/redis}/src/test/resources/logback-test.xml (100%) create mode 100644 docs/quickstart/junit_5_quickstart.md diff --git a/docs/examples/build.gradle b/docs/examples/junit4/generic/build.gradle similarity index 81% rename from docs/examples/build.gradle rename to docs/examples/junit4/generic/build.gradle index e5247a6e9d8..97902d5d9ca 100644 --- a/docs/examples/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -1,8 +1,6 @@ description = "Examples for docs" dependencies { - compile "io.lettuce:lettuce-core:5.1.1.RELEASE" - testCompile "junit:junit:4.12" testCompile project(":testcontainers") testCompile project(":selenium") diff --git a/docs/examples/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java similarity index 100% rename from docs/examples/src/test/java/generic/CmdModifierTest.java rename to docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java diff --git a/docs/examples/src/test/java/generic/CommandsTest.java b/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java similarity index 100% rename from docs/examples/src/test/java/generic/CommandsTest.java rename to docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java diff --git a/docs/examples/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java similarity index 100% rename from docs/examples/src/test/java/generic/ContainerCreationTest.java rename to docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java diff --git a/docs/examples/src/test/java/generic/ContainerLabelTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java similarity index 100% rename from docs/examples/src/test/java/generic/ContainerLabelTest.java rename to docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java diff --git a/docs/examples/src/test/java/generic/ExecTest.java b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java similarity index 100% rename from docs/examples/src/test/java/generic/ExecTest.java rename to docs/examples/junit4/generic/src/test/java/generic/ExecTest.java diff --git a/docs/examples/src/test/java/generic/HostPortExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java similarity index 100% rename from docs/examples/src/test/java/generic/HostPortExposedTest.java rename to docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java diff --git a/docs/examples/src/test/java/generic/MultiplePortsExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java similarity index 100% rename from docs/examples/src/test/java/generic/MultiplePortsExposedTest.java rename to docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java diff --git a/docs/examples/src/test/java/generic/WaitStrategiesTest.java b/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java similarity index 100% rename from docs/examples/src/test/java/generic/WaitStrategiesTest.java rename to docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java diff --git a/docs/examples/junit4/redis/build.gradle b/docs/examples/junit4/redis/build.gradle new file mode 100644 index 00000000000..76d32e5b4d0 --- /dev/null +++ b/docs/examples/junit4/redis/build.gradle @@ -0,0 +1,8 @@ +description = "Examples for docs" + +dependencies { + compile "io.lettuce:lettuce-core:5.1.1.RELEASE" + + testCompile "junit:junit:4.12" + testCompile project(":testcontainers") +} diff --git a/docs/examples/src/main/java/quickstart/RedisBackedCache.java b/docs/examples/junit4/redis/src/main/java/quickstart/RedisBackedCache.java similarity index 100% rename from docs/examples/src/main/java/quickstart/RedisBackedCache.java rename to docs/examples/junit4/redis/src/main/java/quickstart/RedisBackedCache.java diff --git a/docs/examples/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java similarity index 100% rename from docs/examples/src/test/java/quickstart/RedisBackedCacheIntTest.java rename to docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java diff --git a/docs/examples/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java similarity index 100% rename from docs/examples/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java rename to docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java diff --git a/docs/examples/src/test/resources/logback-test.xml b/docs/examples/junit4/redis/src/test/resources/logback-test.xml similarity index 100% rename from docs/examples/src/test/resources/logback-test.xml rename to docs/examples/junit4/redis/src/test/resources/logback-test.xml diff --git a/docs/examples/junit5/redis/build.gradle b/docs/examples/junit5/redis/build.gradle new file mode 100644 index 00000000000..56442b66af3 --- /dev/null +++ b/docs/examples/junit5/redis/build.gradle @@ -0,0 +1,11 @@ +description = "Examples for docs" + +dependencies { + compile "io.lettuce:lettuce-core:5.1.1.RELEASE" + + testCompile "org.junit.jupiter:junit-jupiter-api:5.4.2" + testCompile "org.junit.jupiter:junit-jupiter-params:5.4.2" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.2" + testCompile project(":testcontainers") + testCompile project(":junit-jupiter") +} diff --git a/examples/spock/src/main/java/quickstart/RedisBackedCache.java b/docs/examples/junit5/redis/src/main/java/quickstart/RedisBackedCache.java similarity index 100% rename from examples/spock/src/main/java/quickstart/RedisBackedCache.java rename to docs/examples/junit5/redis/src/main/java/quickstart/RedisBackedCache.java diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java new file mode 100644 index 00000000000..7c3968a724e --- /dev/null +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -0,0 +1,42 @@ +package quickstart; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +// class { +@Testcontainers +public class RedisBackedCacheIntTest { + + private RedisBackedCache underTest; + + // container { + @Container + public GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") + .withExposedPorts(6379); + // } + + + @BeforeEach + public void setUp() { + String address = redis.getContainerIpAddress(); + Integer port = redis.getFirstMappedPort(); + + // Now we have an address and port for Redis, no matter where it is running + underTest = new RedisBackedCache(address, port); + } + + @Test + public void testSimplePutAndGet() { + underTest.put("test", "example"); + + String retrieved = underTest.get("test"); + assertEquals("example", retrieved); + } +} +// } diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java new file mode 100644 index 00000000000..c81a185a188 --- /dev/null +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java @@ -0,0 +1,27 @@ +package quickstart; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Disabled("This test class is deliberately invalid, as it relies on a non-existent local Redis") +public class RedisBackedCacheIntTestStep0 { + private RedisBackedCache underTest; + + @BeforeEach + public void setUp() { + // Assume that we have Redis running locally? + underTest = new RedisBackedCache("localhost", 6379); + } + + @Test + public void testSimplePutAndGet() { + underTest.put("test", "example"); + + String retrieved = underTest.get("test"); + assertEquals("example", retrieved); + } +} diff --git a/docs/examples/junit5/redis/src/test/resources/logback-test.xml b/docs/examples/junit5/redis/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..49da0be9709 --- /dev/null +++ b/docs/examples/junit5/redis/src/test/resources/logback-test.xml @@ -0,0 +1,27 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + + + + + + + + + PROFILER + DENY + + diff --git a/examples/spock/build.gradle b/docs/examples/spock/redis/build.gradle similarity index 74% rename from examples/spock/build.gradle rename to docs/examples/spock/redis/build.gradle index 486107f9b21..398a6d3fa1c 100644 --- a/examples/spock/build.gradle +++ b/docs/examples/spock/redis/build.gradle @@ -3,13 +3,9 @@ plugins { id 'groovy' } -repositories { - jcenter() -} - dependencies { compile "io.lettuce:lettuce-core:5.2.0.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' - testImplementation 'org.testcontainers:spock' + testImplementation project(":spock") testImplementation 'ch.qos.logback:logback-classic:1.2.3' } diff --git a/docs/examples/spock/redis/src/main/java/quickstart/RedisBackedCache.java b/docs/examples/spock/redis/src/main/java/quickstart/RedisBackedCache.java new file mode 100644 index 00000000000..1123858ca17 --- /dev/null +++ b/docs/examples/spock/redis/src/main/java/quickstart/RedisBackedCache.java @@ -0,0 +1,22 @@ +package quickstart; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; + +public class RedisBackedCache { + + private final StatefulRedisConnection connection; + + public RedisBackedCache(String hostname, Integer port) { + RedisClient client = RedisClient.create(String.format("redis://%s:%d/0", hostname, port)); + connection = client.connect(); + } + + public String get(String key) { + return connection.sync().get(key); + } + + public void put(String key, String value) { + connection.sync().set(key, value); + } +} diff --git a/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy similarity index 100% rename from examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy rename to docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy diff --git a/examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy similarity index 100% rename from examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy rename to docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy diff --git a/examples/spock/src/test/resources/logback-test.xml b/docs/examples/spock/redis/src/test/resources/logback-test.xml similarity index 100% rename from examples/spock/src/test/resources/logback-test.xml rename to docs/examples/spock/redis/src/test/resources/logback-test.xml diff --git a/docs/features/advanced_options.md b/docs/features/advanced_options.md index bedb7aee6b8..a774dbddc06 100644 --- a/docs/features/advanced_options.md +++ b/docs/features/advanced_options.md @@ -5,13 +5,13 @@ To add a custom label to the container, use `withLabel`: -[Adding a single label](../examples/src/test/java/generic/ContainerLabelTest.java) inside_block:single_label +[Adding a single label](../examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java) inside_block:single_label Additionally, multiple labels may be applied together from a map: -[Adding multiple labels](../examples/src/test/java/generic/ContainerLabelTest.java) inside_block:multiple_labels +[Adding multiple labels](../examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java) inside_block:multiple_labels ## Image Pull Policy @@ -38,13 +38,13 @@ It is possible to use the [`docker-java`](https://github.com/docker-java/docker- For example, this can be used to change the container hostname: -[Using modifier to change hostname](../examples/src/test/java/generic/CmdModifierTest.java) inside_block:hostname +[Using modifier to change hostname](../examples/junit4/generic/src/test/java/generic/CmdModifierTest.java) inside_block:hostname ... or modify container memory (see [this](https://fabiokung.com/2014/03/13/memory-inside-linux-containers/) if it does not appear to work): -[Using modifier to change memory limits](../examples/src/test/java/generic/CmdModifierTest.java) inside_block:memory +[Using modifier to change memory limits](../examples/junit4/generic/src/test/java/generic/CmdModifierTest.java) inside_block:memory !!! note diff --git a/docs/features/commands.md b/docs/features/commands.md index 197871ebe02..40bcce5d1ab 100644 --- a/docs/features/commands.md +++ b/docs/features/commands.md @@ -5,7 +5,7 @@ By default the container will execute whatever command is specified in the image's Dockerfile. To override this, and specify a different command, use `withCommand`. For example: -[Specifying a startup command](../examples/src/test/java/generic/CommandsTest.java) inside_block:startupCommand +[Specifying a startup command](../examples/junit4/generic/src/test/java/generic/CommandsTest.java) inside_block:startupCommand ## Executing a command @@ -13,13 +13,13 @@ By default the container will execute whatever command is specified in the image Your test can execute a command inside a running container, similar to a `docker exec` call: -[Executing a command inside a running container](../examples/src/test/java/generic/ExecTest.java) inside_block:standaloneExec +[Executing a command inside a running container](../examples/junit4/generic/src/test/java/generic/ExecTest.java) inside_block:standaloneExec This can be useful for software that has a command line administration tool. You can also get the output (stdout/stderr) and exit code from the command - for example: -[Executing a command inside a running container and reading the result](../examples/src/test/java/generic/ExecTest.java) inside_block:execReadingStdout +[Executing a command inside a running container and reading the result](../examples/junit4/generic/src/test/java/generic/ExecTest.java) inside_block:execReadingStdout ## Environment variables diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index 16413924197..e92f20e71cd 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -20,13 +20,13 @@ new GenericContainer("jboss/wildfly:9.0.1.Final") A generic container rule can be used with any public docker image; for example: -[Creating a Redis container (JUnit 4)](../examples/src/test/java/generic/ContainerCreationTest.java) inside_block:simple +[Creating a Redis container (JUnit 4)](../examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java) inside_block:simple Further options may be specified: -[Creating a container with more options (JUnit 4)](../examples/src/test/java/generic/ContainerCreationTest.java) inside_block:withOptions +[Creating a container with more options (JUnit 4)](../examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java) inside_block:withOptions These containers, as `@ClassRule`s, will be started before any tests in the class run, and will be destroyed after all diff --git a/docs/features/networking.md b/docs/features/networking.md index 75dd924d6bc..5de0c9dfa96 100644 --- a/docs/features/networking.md +++ b/docs/features/networking.md @@ -8,7 +8,7 @@ For example, you may be testing a class that needs to connect to a backend or da Generally, each required port needs to be explicitly exposed. For example, we can specify one or more ports as follows: -[Exposing ports](../examples/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:rule +[Exposing ports](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:rule Note that this exposed port number is from the *perspective of the container*. @@ -20,7 +20,7 @@ Because there is this layer of indirection, it is necessary to ask Testcontainer This can be done using the `getMappedPort` method, which takes the original (container) port as an argument: -[Retrieving actual ports at runtime](../examples/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchPortsByNumber +[Retrieving actual ports at runtime](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchPortsByNumber !!! warning @@ -30,7 +30,7 @@ This can be done using the `getMappedPort` method, which takes the original (con There is also a `getFirstMappedPort` method for convenience, for the fairly common scenario of a container that only exposes one port: -[Retrieving the first mapped port](../examples/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchFirstMappedPort +[Retrieving the first mapped port](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchFirstMappedPort ## Getting the container IP address @@ -41,13 +41,13 @@ However, in some CI environments they may instead be reachable on a different ho As such, Testcontainers provides a convenience method to obtain an IP address on which the container should be reachable from the host machine. -[Getting the container IP address](../examples/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getContainerIpAddressOnly +[Getting the container IP address](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getContainerIpAddressOnly It is normally advisable to use `getContainerIpAddress` and `getMappedPort` together when constructing addresses - for example: -[Getting the container IP address and mapped port](../examples/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getContainerIpAddressAndMappedPort +[Getting the container IP address and mapped port](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getContainerIpAddressAndMappedPort ## Exposing host ports to the container @@ -61,7 +61,7 @@ In this example, assume that `localServerPort` is a port on our test host machin We need to tell Testcontainers to prepare to expose this port to containers: -[Exposing the host port](../examples/src/test/java/generic/HostPortExposedTest.java) inside_block:exposePort +[Exposing the host port](../examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java) inside_block:exposePort !!! warning @@ -73,7 +73,7 @@ From a container's perspective, the hostname will be `host.testcontainers.intern For example, here we construct an HTTP URL for our local web application and tell a Selenium container to get a page from it: -[Accessing the exposed host port from a container](../examples/src/test/java/generic/HostPortExposedTest.java) inside_block:useHostExposedPort +[Accessing the exposed host port from a container](../examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java) inside_block:useHostExposedPort diff --git a/docs/features/startup_and_waits.md b/docs/features/startup_and_waits.md index a7e277b9892..e1d30457e5c 100644 --- a/docs/features/startup_and_waits.md +++ b/docs/features/startup_and_waits.md @@ -14,7 +14,7 @@ Ordinarily Testcontainers will wait for up to 60 seconds for the container's fir This simple measure provides a basic check whether a container is ready for use. -[Waiting for the first exposed port to start listening](../examples/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForNetworkListening +[Waiting for the first exposed port to start listening](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForNetworkListening If the default 60s timeout is not sufficient, it can be altered with the `withStartupTimeout()` method. @@ -28,24 +28,24 @@ You can choose to wait for an HTTP(S) endpoint to return a particular status cod #### Waiting for 200 OK -[](../examples/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForSimpleHttp +[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForSimpleHttp Variations on the HTTP wait strategy are supported, including: #### Waiting for multiple possible status codes -[](../examples/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithMultipleStatusCodes +[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithMultipleStatusCodes #### Waiting for a status code that matches a predicate -[Waiting for a status code that matches a predicate](../examples/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithStatusCodePredicate +[Waiting for a status code that matches a predicate](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithStatusCodePredicate #### Using TLS -[](../examples/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithTls +[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithTls ### Healthcheck Wait strategy examples @@ -53,7 +53,7 @@ Variations on the HTTP wait strategy are supported, including: If the used image supports Docker's [Healthcheck](https://docs.docker.com/engine/reference/builder/#healthcheck) feature, you can directly leverage the `healthy` state of the container as your wait condition: -[](../examples/src/test/java/generic/WaitStrategiesTest.java) inside_block:healthcheckWait +[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:healthcheckWait ### Log output Wait Strategy @@ -62,7 +62,7 @@ In some situations a container's log output is a simple way to determine if it i For example, we can wait for a `Ready' message in the container's logs as follows: -[](../examples/src/test/java/generic/WaitStrategiesTest.java) inside_block:logMessageWait +[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:logMessageWait ### Other Wait Strategies diff --git a/docs/quickstart/junit_4_quickstart.md b/docs/quickstart/junit_4_quickstart.md index 93ca7e9a024..86cd720942b 100644 --- a/docs/quickstart/junit_4_quickstart.md +++ b/docs/quickstart/junit_4_quickstart.md @@ -8,7 +8,7 @@ In our imaginary program, there is a `RedisBackedCache` class which stores data You can see an example test that could have been written for it (without using Testcontainers): -[Pre-Testcontainers test code](../examples/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java) block:RedisBackedCacheIntTestStep0 +[Pre-Testcontainers test code](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java) block:RedisBackedCacheIntTestStep0 Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability. @@ -39,7 +39,7 @@ testCompile "org.testcontainers:testcontainers:{{latest_version}}" Simply add the following to the body of our test class: -[JUnit 4 Rule](../examples/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:rule +[JUnit 4 Rule](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:rule The `@Rule` annotation tells JUnit to notify this field about various events in the test lifecycle. @@ -61,7 +61,7 @@ Testcontainers uses *randomized ports* for each container it starts, but makes i We can do this in our test `setUp` method, to set up our component under test: -[Obtaining a mapped port](../examples/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:setUp +[Obtaining a mapped port](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:setUp !!! tip @@ -77,6 +77,6 @@ That's it! Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers: -[RedisBackedCacheIntTest](../examples/src/test/java/quickstart/RedisBackedCacheIntTest.java) block:RedisBackedCacheIntTest +[RedisBackedCacheIntTest](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) block:RedisBackedCacheIntTest diff --git a/docs/quickstart/junit_5_quickstart.md b/docs/quickstart/junit_5_quickstart.md new file mode 100644 index 00000000000..5a07af24731 --- /dev/null +++ b/docs/quickstart/junit_5_quickstart.md @@ -0,0 +1,110 @@ +# JUnit 5 Quickstart + +It's easy to add Testcontainers to your project - let's walk through a quick example to see how. + +Let's imagine we have a simple program that has a dependency on Redis, and we want to add some tests for it. +In our imaginary program, there is a `RedisBackedCache` class which stores data in Redis. + +You can see an example test that could have been written for it (without using Testcontainers): + + +[Pre-Testcontainers test code](../examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java) block:RedisBackedCacheIntTestStep0 + + +Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability. +This may work if we were sure that every developer and CI machine had Redis installed, but would fail otherwise. +We might also have problems if we attempted to run tests in parallel, such as state bleeding between tests, or port clashes. + +Let's start from here, and see how to improve the test with Testcontainers: + +## 1. Add Testcontainers as a test-scoped dependency + +First, add Testcontainers as a dependency as follows: + +```groovy tab='Gradle' +def junitJupiterVersion = '5.4.2' +testCompile "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion" +testCompile "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion" +testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion" +testCompile "org.testcontainers:testcontainers:{{latest_version}}" +``` + +```xml tab='Maven' + + org.junit.jupiter + junit-jupiter-api + 5.4.2 + test + + + org.junit.jupiter + junit-jupiter-params + 5.4.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.4.2 + test + + + org.testcontainers + testcontainers + {{latest_version}} + test + + + org.testcontainers + junit-jupiter + {{latest_version}} + test + +``` + +## 2. Get Testcontainers to run a Redis container during our tests + +First, you'll need to annotate the test class with `@Testcontainers`. Furthermore, add the following to the body of our test class: + + +[JUnit 5 Rule](../examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:container + + +The `@Container` annotation tells JUnit to notify this field about various events in the test lifecycle. +In this case, our rule object is a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port. + +If we run our test as-is, then regardless of the actual test outcome, we'll see logs showing us that Testcontainers: + +* was activated before our test method ran +* discovered and quickly tested our local Docker setup +* pulled the image if necessary +* started a new container and waited for it to be ready +* shut down and deleted the container after the test + +## 3. Make sure our code can talk to the container + +Before Testcontainers, we might have hardcoded an address like `localhost:6379` into our tests. + +Testcontainers uses *randomized ports* for each container it starts, but makes it easy to obtain the actual port at runtime. +We can do this in our test `setUp` method, to set up our component under test: + + +[Obtaining a mapped port](../examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:setUp + + +!!! tip + Notice that we also ask Testcontainers for the container's actual address with `redis.getContainerIpAddress();`, + rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may + not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use + `getContainerIpAddress()` instead. + +## 4. Run the tests! + +That's it! + +Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers: + + +[RedisBackedCacheIntTest](../examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:class + + diff --git a/docs/quickstart/spock_quickstart.md b/docs/quickstart/spock_quickstart.md index 921956c875a..902f1a78c09 100644 --- a/docs/quickstart/spock_quickstart.md +++ b/docs/quickstart/spock_quickstart.md @@ -8,7 +8,7 @@ In our imaginary program, there is a `RedisBackedCache` class which stores data You can see an example test that could have been written for it (without using Testcontainers): -[Pre-Testcontainers test code](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy) block:RedisBackedCacheIntTestStep0 +[Pre-Testcontainers test code](../examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy) block:RedisBackedCacheIntTestStep0 Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability. @@ -46,7 +46,7 @@ class RedisBackedCacheIntTest extends Specification { And add the following field to the body of our test class: -[Spock Testcontainers init](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) inside_block:init +[Spock Testcontainers init](../examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) inside_block:init This tells Spock to start a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port. @@ -67,7 +67,7 @@ Testcontainers uses *randomized ports* for each container it starts, but makes i We can do this in our test `setup` method, to set up our component under test: -[Obtaining a mapped port](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) inside_block:setup +[Obtaining a mapped port](../examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) inside_block:setup !!! tip @@ -83,5 +83,5 @@ That's it! Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers: -[RedisBackedCacheIntTest](../../examples/spock/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) block:complete +[RedisBackedCacheIntTest](../examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy) block:complete diff --git a/mkdocs.yml b/mkdocs.yml index 5c78e884662..eaec3ae13a1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,6 +25,7 @@ nav: - Home: index.md - Quickstart: - quickstart/junit_4_quickstart.md + - quickstart/junit_5_quickstart.md - quickstart/spock_quickstart.md - Features: - features/creating_container.md diff --git a/settings.gradle b/settings.gradle index e8fb1efe910..7e01821a058 100644 --- a/settings.gradle +++ b/settings.gradle @@ -45,7 +45,10 @@ file('modules').eachDir { dir -> project(":${dir.name}").projectDir = dir } -include "docs-examples" -project(":docs-examples").projectDir = file("docs/examples") +include ':docs:examples:junit4:generic' +include ':docs:examples:junit4:redis' +include ':docs:examples:junit5:redis' +include ':docs:examples:spock:redis' + include 'test-support' From 6b158463141e70ce7b9cf05c0998401fd6660adb Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 27 Nov 2019 20:08:23 +0000 Subject: [PATCH 0403/4969] Switch to publishing non-delomboked sources (#1788) * Fixes #762, #1966: Switch to publishing non-delomboked sources Delomboked sources are available under the 'sources-delomboked' classifier * Remove publication of delomboked sources JAR --- build.gradle | 12 +++++------- gradle/publishing.gradle | 1 + 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 7bbf71af9f9..67b3a3a6635 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,11 @@ subprojects { compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' + repositories { + jcenter() + mavenCentral() + } + lombok { version = '1.18.8' } @@ -36,18 +41,11 @@ subprojects { project.sourceSets.main.java.srcDirs.find { it.exists() } } - repositories { - jcenter() - mavenCentral() - } - // specific modules should be excluded from publication if ( ! ["test-support", "jdbc-test", "docs-examples"].contains(it.name) ) { apply from: "$rootDir/gradle/publishing.gradle" apply from: "$rootDir/gradle/bintray.gradle" - project.tasks.sourceJar.from(delombok) - publishing { publications { mavenJava(MavenPublication) { publication -> diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 14c385144ba..3acdeb10c88 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -2,6 +2,7 @@ apply plugin: 'maven-publish' task sourceJar(type: Jar) { classifier = 'sources' + from sourceSets.main.allJava } task javadocJar(type: Jar, dependsOn: javadoc) { From 7b38847bc2de5ab7bc112ac1a89d63dff135af45 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2019 20:10:49 +0000 Subject: [PATCH 0404/4969] =?UTF-8?q?Bump=20aws-java-sdk-s3=20from=201.11.?= =?UTF-8?q?680=20to=201.11.683=20in=20/modules/loca=E2=80=A6=20(#2103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.680 to 1.11.683. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.680...1.11.683) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 770294621aa..819419c57ee 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.680' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.636' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' } From 96c8e051ba5630603cb772d4e5774e811b3ec936 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2019 20:11:09 +0000 Subject: [PATCH 0405/4969] Bump mariadb-java-client from 2.5.1 to 2.5.2 in /modules/mariadb (#2098) Bumps [mariadb-java-client](https://github.com/MariaDB/mariadb-connector-j) from 2.5.1 to 2.5.2. - [Release notes](https://github.com/MariaDB/mariadb-connector-j/releases) - [Changelog](https://github.com/MariaDB/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/MariaDB/mariadb-connector-j/compare/2.5.1...2.5.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 87462ce158d..541d3967680 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.1' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.2' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.29' From 3880dd4a0c0c347cd47aaf612597893f2ca9f6c6 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 27 Nov 2019 21:11:27 +0100 Subject: [PATCH 0406/4969] Rework KafkaContainer (do not run a sub-process) (#2078) * Rework KafkaContainer (do not run a sub-process) * revert unrelated change * Escape environment variables * Start ZK before Kafka --- .../containers/KafkaContainer.java | 33 +++++++++++++------ .../containers/KafkaContainerTest.java | 7 ++-- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 4b5e66a7bf5..60037acfd45 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -4,9 +4,13 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.core.command.ExecStartResultCallback; import lombok.SneakyThrows; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.TestcontainersConfiguration; +import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * This container wraps Confluent Kafka and Zookeeper (optionally) @@ -14,6 +18,8 @@ */ public class KafkaContainer extends GenericContainer { + private static final String STARTER_SCRIPT = "/testcontainers_start.sh"; + public static final int KAFKA_PORT = 9093; public static final int ZOOKEEPER_PORT = 2181; @@ -97,7 +103,7 @@ public String getBootstrapServers() { @Override protected void doStart() { - withCommand("sleep infinity"); + withCommand("sh", "-c", "while [ ! -f " + STARTER_SCRIPT + " ]; do sleep 0.1; done; " + STARTER_SCRIPT); if (externalZookeeperConnect == null) { addExposedPort(ZOOKEEPER_PORT); @@ -124,17 +130,24 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole zookeeperConnect = startZookeeper(); } - String internalIp = containerInfo.getNetworkSettings().getIpAddress(); - - ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(getContainerId()) - .withCmd("sh", "-c", "" + - "export KAFKA_ZOOKEEPER_CONNECT=" + zookeeperConnect + "\n" + - "export KAFKA_ADVERTISED_LISTENERS=" + getBootstrapServers() + "," + String.format("BROKER://%s:9092", internalIp) + "\n" + - "/etc/confluent/docker/run" + String command = "#!/bin/bash \n"; + command += "export KAFKA_ZOOKEEPER_CONNECT='" + zookeeperConnect + "'\n"; + command += "export KAFKA_ADVERTISED_LISTENERS='" + Stream + .concat( + Stream.of(getBootstrapServers()), + containerInfo.getNetworkSettings().getNetworks().values().stream() + .map(it -> "BROKER://" + it.getIpAddress() + ":9092") ) - .exec(); + .collect(Collectors.joining(",")) + "'\n"; - dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ExecStartResultCallback()).awaitStarted(10, TimeUnit.SECONDS); + command += ". /etc/confluent/docker/bash-config \n"; + command += "/etc/confluent/docker/configure \n"; + command += "/etc/confluent/docker/launch \n"; + + copyFileToContainer( + Transferable.of(command.getBytes(StandardCharsets.UTF_8), 700), + STARTER_SCRIPT + ); } @SneakyThrows(InterruptedException.class) diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 0b29ee0e6ef..add8b2b171d 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -16,7 +16,6 @@ import java.util.Arrays; import java.util.UUID; import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @@ -46,7 +45,8 @@ public void testExternalZookeeperWithKafkaNetwork() throws Exception { .withNetworkAliases("zookeeper") .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); ) { - Stream.of(kafka, zookeeper).parallel().forEach(GenericContainer::start); + zookeeper.start(); + kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); } @@ -66,7 +66,8 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { .withNetworkAliases("zookeeper") .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); ) { - Stream.of(kafka, zookeeper).parallel().forEach(GenericContainer::start); + zookeeper.start(); + kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); } From 3cb33792328e49b5ab8d78f747a256d65593dd64 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 27 Nov 2019 21:48:04 +0100 Subject: [PATCH 0407/4969] Hash copied files (#2055) * Fix session label when reuse is not supported but requested * Hash copied files * restore import * add file mode to the checksum * Mock TestcontainersConfiguration * checksum folders too --- .../containers/GenericContainer.java | 46 +++- .../testcontainers/utility/MountableFile.java | 7 +- .../containers/ReusabilityUnitTests.java | 228 +++++++++++++++++- 3 files changed, 272 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 94ce6f64518..0062612c10d 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -29,6 +29,7 @@ import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -75,6 +76,7 @@ import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; import java.nio.charset.Charset; +import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.time.Instant; @@ -87,6 +89,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -96,6 +99,8 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import java.util.zip.Adler32; +import java.util.zip.Checksum; import static com.google.common.collect.Lists.newArrayList; import static org.testcontainers.utility.CommandLine.runShellCommand; @@ -116,6 +121,8 @@ public class GenericContainer> static final String HASH_LABEL = "org.testcontainers.hash"; + static final String COPIED_FILES_HASH_LABEL = "org.testcontainers.copied_files.hash"; + /* * Default settings */ @@ -353,6 +360,11 @@ private void tryStart(Instant startedAt) { } if (TestcontainersConfiguration.getInstance().environmentSupportsReuse()) { + createCommand.getLabels().put( + COPIED_FILES_HASH_LABEL, + Long.toHexString(hashCopiedFiles().getValue()) + ); + String hash = hash(createCommand); containerId = findContainerForReuse(hash).orElse(null); @@ -381,7 +393,7 @@ private void tryStart(Instant startedAt) { if (!reused) { containerId = createCommand.exec().getId(); - // TODO add to the hash + // TODO use single "copy" invocation (and calculate an hash of the resulting tar archive) copyToFileContainerPathMap.forEach(this::copyFileToContainer); } @@ -474,6 +486,36 @@ private void tryStart(Instant startedAt) { } } + @VisibleForTesting + Checksum hashCopiedFiles() { + Checksum checksum = new Adler32(); + copyToFileContainerPathMap.entrySet().stream().sorted(Entry.comparingByValue()).forEach(entry -> { + byte[] pathBytes = entry.getValue().getBytes(); + // Add path to the hash + checksum.update(pathBytes, 0, pathBytes.length); + + File file = new File(entry.getKey().getResolvedPath()); + checksumFile(file, checksum); + }); + return checksum; + } + + @VisibleForTesting + @SneakyThrows(IOException.class) + void checksumFile(File file, Checksum checksum) { + Path path = file.toPath(); + checksum.update(MountableFile.getUnixFileMode(path)); + if (file.isDirectory()) { + try (Stream stream = Files.walk(path)) { + stream.filter(it -> it != path).forEach(it -> { + checksumFile(it.toFile(), checksum); + }); + } + } else { + FileUtils.checksum(file, checksum); + } + } + @UnstableAPI @SneakyThrows(JsonProcessingException.class) final String hash(CreateContainerCmd createCommand) { @@ -708,7 +750,7 @@ private void applyConfiguration(CreateContainerCmd createCommand) { Set allLinks = new HashSet<>(); Set allLinkedContainerNetworks = new HashSet<>(); - for (Map.Entry linkEntries : linkedContainers.entrySet()) { + for (Entry linkEntries : linkedContainers.entrySet()) { String alias = linkEntries.getKey(); LinkableContainer linkableContainer = linkEntries.getValue(); diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 56d5bda3ffa..37312116734 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -9,6 +9,7 @@ import org.apache.commons.lang.SystemUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.DockerClientFactory; +import org.testcontainers.UnstableAPI; import org.testcontainers.images.builder.Transferable; import java.io.File; @@ -361,9 +362,13 @@ private int getUnixFileMode(final String pathAsString) { if (this.forcedFileMode != null) { return this.getModeValue(path); } + return getUnixFileMode(path); + } + @UnstableAPI + public static int getUnixFileMode(final Path path) { try { - return (int) Files.getAttribute(path, "unix:mode"); + return (int) Files.readAttributes(path, "unix:mode").get("mode"); } catch (IOException | UnsupportedOperationException e) { // fallback for non-posix environments int mode = DEFAULT_FILE_MODE; diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 3f7c7d75b45..096f202b3d7 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -9,6 +9,7 @@ import com.github.dockerjava.core.command.InspectContainerCmdImpl; import com.github.dockerjava.core.command.ListContainersCmdImpl; import com.github.dockerjava.core.command.StartContainerCmdImpl; +import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.junit.Rule; @@ -24,11 +25,20 @@ import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; import org.testcontainers.utility.MockTestcontainersConfigurationRule; +import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.TestcontainersConfiguration; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; @@ -182,7 +192,12 @@ public void shouldNotCallHookIfNotReused() { @FieldDefaults(makeFinal = true) public static class HashTest extends AbstractReusabilityTest { - protected GenericContainer container = makeReusable(new GenericContainer<>(IMAGE_FUTURE)); + protected GenericContainer container = makeReusable(new GenericContainer(IMAGE_FUTURE) { + @Override + public void copyFileToContainer(MountableFile mountableFile, String containerPath) { + // NOOP + } + }); @Test public void shouldStartIfListReturnsEmpty() { @@ -230,6 +245,208 @@ public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { .containsKeys(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL); }); } + + @Test + public void shouldSetCopiedFilesHashLabel() { + Mockito.doReturn(true).when(TestcontainersConfiguration.getInstance()).environmentSupportsReuse(); + AtomicReference commandRef = new AtomicReference<>(); + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId, commandRef::set)); + when(client.listContainersCmd()).then(listContainersAnswer()); + when(client.startContainerCmd(containerId)).then(startContainerAnswer()); + when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); + + container.start(); + + assertThat(commandRef).isNotNull(); + assertThat(commandRef.get().getLabels()) + .containsKeys(GenericContainer.COPIED_FILES_HASH_LABEL); + } + + @Test + public void shouldHashCopiedFiles() { + Mockito.doReturn(true).when(TestcontainersConfiguration.getInstance()).environmentSupportsReuse(); + AtomicReference commandRef = new AtomicReference<>(); + String containerId = randomContainerId(); + when(client.createContainerCmd(any())).then(createContainerAnswer(containerId, commandRef::set)); + when(client.listContainersCmd()).then(listContainersAnswer()); + when(client.startContainerCmd(containerId)).then(startContainerAnswer()); + when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); + + container.start(); + + assertThat(commandRef).isNotNull(); + + Map labels = commandRef.get().getLabels(); + assertThat(labels).containsKeys(GenericContainer.COPIED_FILES_HASH_LABEL); + + String oldHash = labels.get(GenericContainer.COPIED_FILES_HASH_LABEL); + + // Simulate stop + container.containerId = null; + + container.withCopyFileToContainer( + MountableFile.forClasspathResource("test_copy_to_container.txt"), + "/foo/bar" + ); + container.start(); + + assertThat(commandRef.get().getLabels()).hasEntrySatisfying(GenericContainer.COPIED_FILES_HASH_LABEL, newHash -> { + assertThat(newHash).as("new hash").isNotEqualTo(oldHash); + }); + } + } + + @RunWith(BlockJUnit4ClassRunner.class) + @FieldDefaults(makeFinal = true) + public static class CopyFilesHashTest { + GenericContainer container = new GenericContainer(IMAGE_FUTURE); + + @Test + public void empty() { + assertThat(container.hashCopiedFiles()).isNotNull(); + } + + @Test + public void oneFile() { + long emptyHash = container.hashCopiedFiles().getValue(); + + container.withCopyFileToContainer( + MountableFile.forClasspathResource("test_copy_to_container.txt"), + "/foo/bar" + ); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(emptyHash); + } + + @Test + public void differentPath() { + MountableFile mountableFile = MountableFile.forClasspathResource("test_copy_to_container.txt"); + container.withCopyFileToContainer(mountableFile, "/foo/bar"); + + long hash1 = container.hashCopiedFiles().getValue(); + + container.getCopyToFileContainerPathMap().clear(); + + container.withCopyFileToContainer(mountableFile, "/foo/baz"); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); + } + + @Test + public void detectsChangesInFile() throws Exception { + Path path = File.createTempFile("reusable_test", ".txt").toPath(); + MountableFile mountableFile = MountableFile.forHostPath(path); + container.withCopyFileToContainer(mountableFile, "/foo/bar"); + + long hash1 = container.hashCopiedFiles().getValue(); + + Files.write(path, UUID.randomUUID().toString().getBytes()); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); + } + + @Test + public void multipleFiles() { + container.withCopyFileToContainer( + MountableFile.forClasspathResource("test_copy_to_container.txt"), + "/foo/bar" + ); + long hash1 = container.hashCopiedFiles().getValue(); + + container.withCopyFileToContainer( + MountableFile.forClasspathResource("mappable-resource/test-resource.txt"), + "/foo/baz" + ); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); + } + + @Test + public void folder() throws Exception { + long emptyHash = container.hashCopiedFiles().getValue(); + + Path tempDirectory = Files.createTempDirectory("reusable_test"); + MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); + container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(emptyHash); + } + + @Test + public void changesInFolder() throws Exception { + Path tempDirectory = Files.createTempDirectory("reusable_test"); + MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); + assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); + container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + + long hash1 = container.hashCopiedFiles().getValue(); + + Path fileInFolder = Files.createFile( + // Create file in the sub-folder + Files.createDirectory(tempDirectory.resolve("sub")).resolve("test.txt") + ); + assertThat(fileInFolder).exists(); + Files.write(fileInFolder, UUID.randomUUID().toString().getBytes()); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); + } + + @Test + public void folderAndFile() throws Exception { + Path tempDirectory = Files.createTempDirectory("reusable_test"); + MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); + assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); + container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + + long hash1 = container.hashCopiedFiles().getValue(); + + container.withCopyFileToContainer( + MountableFile.forClasspathResource("test_copy_to_container.txt"), + "/foo/baz" + ); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); + } + + @Test + public void filePermissions() throws Exception { + Path path = File.createTempFile("reusable_test", ".txt").toPath(); + MountableFile mountableFile = MountableFile.forHostPath(path); + container.withCopyFileToContainer(mountableFile, "/foo/bar"); + + long hash1 = container.hashCopiedFiles().getValue(); + + Set filePermissions = new HashSet<>(Files.getPosixFilePermissions(path)); + assertThat(filePermissions).doesNotContain(PosixFilePermission.OWNER_EXECUTE); + filePermissions.add(PosixFilePermission.OWNER_EXECUTE); + Files.setPosixFilePermissions(path, filePermissions); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); + } + + @Test + public void folderPermissions() throws Exception { + Path tempDirectory = Files.createTempDirectory("reusable_test"); + MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); + assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); + Path subDir = Files.createDirectory( + tempDirectory.resolve("sub"), + PosixFilePermissions.asFileAttribute( + Sets.newHashSet(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE) + ) + ); + container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + + long hash1 = container.hashCopiedFiles().getValue(); + + Set permissions = new HashSet<>(Files.getPosixFilePermissions(subDir)); + assertThat(permissions).doesNotContain(PosixFilePermission.OWNER_EXECUTE); + permissions.add(PosixFilePermission.OWNER_EXECUTE); + Files.setPosixFilePermissions(subDir, permissions); + + assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); + } } @FieldDefaults(makeFinal = true) @@ -257,11 +474,11 @@ public StartupStatus checkStartupState(DockerClient dockerClient, String contain } }); container.waitingFor(new AbstractWaitStrategy() { - @Override - protected void waitUntilReady() { + @Override + protected void waitUntilReady() { - } - }); + } + }); container.withReuse(true); return container; } @@ -317,6 +534,5 @@ protected Answer inspectContainerAnswer() { return new InspectContainerCmdImpl(exec, invocation.getArgument(0)); }; } - } } From af0a6803666cfbeb15fd1db0b50243c658969860 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 28 Nov 2019 09:14:13 +0100 Subject: [PATCH 0408/4969] Use `File#setExecutable` --- .../containers/ReusabilityUnitTests.java | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 096f202b3d7..5ecee409ead 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -9,7 +9,6 @@ import com.github.dockerjava.core.command.InspectContainerCmdImpl; import com.github.dockerjava.core.command.ListContainersCmdImpl; import com.github.dockerjava.core.command.StartContainerCmdImpl; -import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.junit.Rule; @@ -31,14 +30,10 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; @@ -417,10 +412,8 @@ public void filePermissions() throws Exception { long hash1 = container.hashCopiedFiles().getValue(); - Set filePermissions = new HashSet<>(Files.getPosixFilePermissions(path)); - assertThat(filePermissions).doesNotContain(PosixFilePermission.OWNER_EXECUTE); - filePermissions.add(PosixFilePermission.OWNER_EXECUTE); - Files.setPosixFilePermissions(path, filePermissions); + assertThat(path.toFile().canExecute()).isFalse(); + path.toFile().setExecutable(true); assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); } @@ -430,20 +423,13 @@ public void folderPermissions() throws Exception { Path tempDirectory = Files.createTempDirectory("reusable_test"); MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); - Path subDir = Files.createDirectory( - tempDirectory.resolve("sub"), - PosixFilePermissions.asFileAttribute( - Sets.newHashSet(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE) - ) - ); + Path subDir = Files.createDirectory(tempDirectory.resolve("sub")); + subDir.toFile().setExecutable(false); container.withCopyFileToContainer(mountableFile, "/foo/bar/"); long hash1 = container.hashCopiedFiles().getValue(); - Set permissions = new HashSet<>(Files.getPosixFilePermissions(subDir)); - assertThat(permissions).doesNotContain(PosixFilePermission.OWNER_EXECUTE); - permissions.add(PosixFilePermission.OWNER_EXECUTE); - Files.setPosixFilePermissions(subDir, permissions); + subDir.toFile().setExecutable(true); assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); } From f9ed1416a279ad2aa3c119f682621e2f931785bb Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 28 Nov 2019 09:29:36 +0100 Subject: [PATCH 0409/4969] Use `setWritable` for folder, `setExecutable(false)` in `filePermissions` --- .../org/testcontainers/containers/ReusabilityUnitTests.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 5ecee409ead..3414ae1a412 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -407,6 +407,7 @@ public void folderAndFile() throws Exception { @Test public void filePermissions() throws Exception { Path path = File.createTempFile("reusable_test", ".txt").toPath(); + path.toFile().setExecutable(false); MountableFile mountableFile = MountableFile.forHostPath(path); container.withCopyFileToContainer(mountableFile, "/foo/bar"); @@ -424,12 +425,12 @@ public void folderPermissions() throws Exception { MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); Path subDir = Files.createDirectory(tempDirectory.resolve("sub")); - subDir.toFile().setExecutable(false); + subDir.toFile().setWritable(false); container.withCopyFileToContainer(mountableFile, "/foo/bar/"); long hash1 = container.hashCopiedFiles().getValue(); - subDir.toFile().setExecutable(true); + subDir.toFile().setWritable(true); assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); } From 3826190f2ac57117bd6b36d807f7006076de5f5a Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 28 Nov 2019 09:41:17 +0100 Subject: [PATCH 0410/4969] assume file permissions --- .../org/testcontainers/containers/ReusabilityUnitTests.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 3414ae1a412..35c4a88e68a 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -42,6 +42,7 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assumptions.assumeThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -413,7 +414,7 @@ public void filePermissions() throws Exception { long hash1 = container.hashCopiedFiles().getValue(); - assertThat(path.toFile().canExecute()).isFalse(); + assumeThat(path.toFile().canExecute()).isFalse(); path.toFile().setExecutable(true); assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); @@ -423,7 +424,7 @@ public void filePermissions() throws Exception { public void folderPermissions() throws Exception { Path tempDirectory = Files.createTempDirectory("reusable_test"); MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); - assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); + assumeThat(new File(mountableFile.getResolvedPath())).isDirectory(); Path subDir = Files.createDirectory(tempDirectory.resolve("sub")); subDir.toFile().setWritable(false); container.withCopyFileToContainer(mountableFile, "/foo/bar/"); From d44debdaf173571be35928b2d5d22c713a68925e Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 28 Nov 2019 10:46:44 +0100 Subject: [PATCH 0411/4969] fix the assumptions --- .../org/testcontainers/containers/ReusabilityUnitTests.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 35c4a88e68a..b2d4d327ba2 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -424,14 +424,16 @@ public void filePermissions() throws Exception { public void folderPermissions() throws Exception { Path tempDirectory = Files.createTempDirectory("reusable_test"); MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); - assumeThat(new File(mountableFile.getResolvedPath())).isDirectory(); + assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); Path subDir = Files.createDirectory(tempDirectory.resolve("sub")); subDir.toFile().setWritable(false); + assumeThat(subDir.toFile().canWrite()).isFalse(); container.withCopyFileToContainer(mountableFile, "/foo/bar/"); long hash1 = container.hashCopiedFiles().getValue(); subDir.toFile().setWritable(true); + assumeThat(subDir.toFile()).canWrite(); assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); } From cd7fce7e85b06d75eb675f9cbb8f5ffb615e043e Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 28 Nov 2019 13:30:42 +0100 Subject: [PATCH 0412/4969] Add GHA for Release Drafter (#2109) Currently we have Release Drafter integrated as a GitHub App. If we change it to GHA (GitHub Actions), we will be able to re-trigger it and overall have better control of it (e.g. version) --- .github/workflows/release-drafter.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000000..6f4e849bd5b --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,14 @@ +name: Release Drafter + +on: + push: + branches: + - master + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v5.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 50ff2c514e460290af4ac5c5da89f97f001d9e80 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 28 Nov 2019 18:04:41 +0000 Subject: [PATCH 0413/4969] Basic GitHub Action for release (#1991) * Basic GitHub Action for release * Update following review * Update .github/workflows/gradle.yml Co-Authored-By: Sergei Egorov * Remove explicit check stage (release runs without testing - should be manually verified that master branch is stable) * Add simple shell check for whether master branch is passing CI checks * Strip quotes * Update .github/workflows/gradle-release.yml Co-Authored-By: Sergei Egorov --- .github/workflows/gradle-release.yml | 22 ++++++++++++++++++++++ .travis.yml | 11 ----------- 2 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/gradle-release.yml diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml new file mode 100644 index 00000000000..ca823536fcb --- /dev/null +++ b/.github/workflows/gradle-release.yml @@ -0,0 +1,22 @@ +name: Gradle Release + +on: + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Verify CI check status + run: [ $(curl -s https://api.github.com/repos/testcontainers/testcontainers-java/commits/$GITHUB_SHA/status | jq -r '.state') == 'success' ] + - name: Release with Gradle + run: ./gradlew -Pversion=$GITHUB_REF release --scan --no-daemon -i + env: + BINTRAY_USER: ${{ secrets.BINTRAY_USER }} + BINTRAY_API_KEY: ${{ secrets.BINTRAY_API_KEY }} diff --git a/.travis.yml b/.travis.yml index eda26dc69af..6e07925db3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,14 +58,3 @@ jobs: openjdk:8-jdk-alpine \ ./gradlew --no-daemon testcontainers:test --tests '*GenericContainerRuleTest' --scan -i - - stage: deploy - sudo: false - services: [] - install: skip - script: skip - deploy: - provider: script - script: ./gradlew -Pversion=$TRAVIS_TAG release --scan --no-daemon -i - on: - tags: true - branch: master From 8ed2cfadf1fa0ddc3f806f701c1c5e747e3a2356 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 28 Nov 2019 20:51:14 +0000 Subject: [PATCH 0414/4969] Escape verify command --- .github/workflows/gradle-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml index ca823536fcb..f8feb0cccde 100644 --- a/.github/workflows/gradle-release.yml +++ b/.github/workflows/gradle-release.yml @@ -14,7 +14,7 @@ jobs: with: java-version: 1.8 - name: Verify CI check status - run: [ $(curl -s https://api.github.com/repos/testcontainers/testcontainers-java/commits/$GITHUB_SHA/status | jq -r '.state') == 'success' ] + run: "[ $(curl -s https://api.github.com/repos/testcontainers/testcontainers-java/commits/$GITHUB_SHA/status | jq -r '.state') == 'success' ]" - name: Release with Gradle run: ./gradlew -Pversion=$GITHUB_REF release --scan --no-daemon -i env: From 7336e4a3b44c4def9967da775e739d52374e9e40 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 Nov 2019 09:48:20 +0100 Subject: [PATCH 0415/4969] Extract the CI status check into a script (#2113) --- .github/workflows/gradle-release.yml | 2 +- .github/workflows/scripts/check_ci_status.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100755 .github/workflows/scripts/check_ci_status.sh diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml index f8feb0cccde..a1bce2d9278 100644 --- a/.github/workflows/gradle-release.yml +++ b/.github/workflows/gradle-release.yml @@ -14,7 +14,7 @@ jobs: with: java-version: 1.8 - name: Verify CI check status - run: "[ $(curl -s https://api.github.com/repos/testcontainers/testcontainers-java/commits/$GITHUB_SHA/status | jq -r '.state') == 'success' ]" + run: .github/workflows/scripts/check_ci_status.sh - name: Release with Gradle run: ./gradlew -Pversion=$GITHUB_REF release --scan --no-daemon -i env: diff --git a/.github/workflows/scripts/check_ci_status.sh b/.github/workflows/scripts/check_ci_status.sh new file mode 100755 index 00000000000..ee2719cbb49 --- /dev/null +++ b/.github/workflows/scripts/check_ci_status.sh @@ -0,0 +1,3 @@ +#/bin/bash + +[ $(curl -s https://api.github.com/repos/testcontainers/testcontainers-java/commits/$1/status | jq -r '.state') == 'success' ] From ad58df04eea922d0e3e4126fb2a45483c5d9ebba Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 Nov 2019 10:30:57 +0100 Subject: [PATCH 0416/4969] add missing argument --- .github/workflows/gradle-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml index a1bce2d9278..8c261064d33 100644 --- a/.github/workflows/gradle-release.yml +++ b/.github/workflows/gradle-release.yml @@ -14,7 +14,7 @@ jobs: with: java-version: 1.8 - name: Verify CI check status - run: .github/workflows/scripts/check_ci_status.sh + run: .github/workflows/scripts/check_ci_status.sh $GITHUB_SHA - name: Release with Gradle run: ./gradlew -Pversion=$GITHUB_REF release --scan --no-daemon -i env: From 7f9ff7951d89c8a2ac50fdef867f6d3f345a53b7 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 Nov 2019 10:40:26 +0100 Subject: [PATCH 0417/4969] future proof check_ci_status.sh --- .github/workflows/scripts/check_ci_status.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/scripts/check_ci_status.sh b/.github/workflows/scripts/check_ci_status.sh index ee2719cbb49..bc5c0b138a2 100755 --- a/.github/workflows/scripts/check_ci_status.sh +++ b/.github/workflows/scripts/check_ci_status.sh @@ -1,3 +1,13 @@ #/bin/bash +set -o errexit +set -o nounset +set -o pipefail +set -o xtrace -[ $(curl -s https://api.github.com/repos/testcontainers/testcontainers-java/commits/$1/status | jq -r '.state') == 'success' ] +if [ -z $1 ] ; then + echo "First parameter (commit SHA) is required!" && exit 1; +fi + +STATUS=$(curl -s https://api.github.com/repos/testcontainers/testcontainers-java/commits/$1/status | jq -r '.state') + +[ "$STATUS" == 'success' ] From 5c4ccedb03589a8fd6484440d75695d7e765b5b1 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 Nov 2019 11:42:09 +0100 Subject: [PATCH 0418/4969] Update gradle-release.yml strip `/ref/tags/` from `$GITHUB_REF` temporary remove the master check --- .github/workflows/gradle-release.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml index 8c261064d33..1391561284e 100644 --- a/.github/workflows/gradle-release.yml +++ b/.github/workflows/gradle-release.yml @@ -13,10 +13,8 @@ jobs: uses: actions/setup-java@v1 with: java-version: 1.8 - - name: Verify CI check status - run: .github/workflows/scripts/check_ci_status.sh $GITHUB_SHA - name: Release with Gradle - run: ./gradlew -Pversion=$GITHUB_REF release --scan --no-daemon -i + run: ./gradlew -Pversion=${GITHUB_REF##*/} release --scan --no-daemon -i env: BINTRAY_USER: ${{ secrets.BINTRAY_USER }} BINTRAY_API_KEY: ${{ secrets.BINTRAY_API_KEY }} From 31519e3c1f1a65f6e47eebb27f0b97521535a5ea Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 Nov 2019 11:59:47 +0100 Subject: [PATCH 0419/4969] Exclude `:docs:` from publication and BOM --- bom/build.gradle | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/build.gradle b/bom/build.gradle index 32805571109..1a1b3c2d9f5 100644 --- a/bom/build.gradle +++ b/bom/build.gradle @@ -9,7 +9,7 @@ publishing { pom.withXml { def dependencyManagementNode = asNode().appendNode('dependencyManagement').appendNode('dependencies') - rootProject.subprojects.findAll { it != project }.each { subProject -> + rootProject.subprojects.findAll { it != project && !it.path.startsWith(":docs:") && it != project(":docs") }.each { subProject -> dependencyManagementNode.appendNode('dependency').with { appendNode('groupId', subProject.group) appendNode('artifactId',subProject.name) diff --git a/build.gradle b/build.gradle index 67b3a3a6635..bac06d64052 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ subprojects { } // specific modules should be excluded from publication - if ( ! ["test-support", "jdbc-test", "docs-examples"].contains(it.name) ) { + if ( ! ["test-support", "jdbc-test"].contains(it.name) && !it.path.startsWith(":docs:") && it != project(":docs") ) { apply from: "$rootDir/gradle/publishing.gradle" apply from: "$rootDir/gradle/bintray.gradle" From d23e2d58f2db7b8ffee15fa741b181f63e4a44ad Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 Nov 2019 14:05:23 +0100 Subject: [PATCH 0420/4969] Update gradle-release.yml restore the CI check --- .github/workflows/gradle-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml index 1391561284e..3034ce9cdfb 100644 --- a/.github/workflows/gradle-release.yml +++ b/.github/workflows/gradle-release.yml @@ -13,6 +13,8 @@ jobs: uses: actions/setup-java@v1 with: java-version: 1.8 + - name: Verify CI check status + run: .github/workflows/scripts/check_ci_status.sh $GITHUB_SHA - name: Release with Gradle run: ./gradlew -Pversion=${GITHUB_REF##*/} release --scan --no-daemon -i env: From d3650665ebfd9a6db11231d217f6b5898a13d382 Mon Sep 17 00:00:00 2001 From: Vincent Massol Date: Fri, 29 Nov 2019 17:47:23 +0100 Subject: [PATCH 0421/4969] Add XWiki to "Who is using Testcontainers" (#2117) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index c26ed164067..9caecd2261e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -78,6 +78,7 @@ You can also [check the latest version available on Maven Central](https://searc * [wescale](https://www.wescale.com) - Integration testing against HTTP service mocks and various data stores * [Marquez](https://marquezproject.github.io/marquez) - PostgreSQL integration testing * [Transferwise](https://transferwise.com/) - Integration testing for different RDBMS, kafka and micro services +* [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) ## License From 9c320eeb221a036ef3779f2e2a9bffd13c1cf8e9 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 1 Dec 2019 16:11:04 +0100 Subject: [PATCH 0422/4969] Add `x-amz-acl` header to allow public reads of the cache files --- settings.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/settings.gradle b/settings.gradle index 7e01821a058..e2ddf080972 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,6 +30,9 @@ buildCache { bucket = 'testcontainers' path = 'cache' push = isMasterBuild + headers = [ + 'x-amz-acl': 'public-read' + ] } } From bfb44a0067cf4ac7ea21b2ae3fb569fb790b831d Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 1 Dec 2019 22:45:46 +0100 Subject: [PATCH 0423/4969] include only published projects into BOM (#2118) --- bom/build.gradle | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bom/build.gradle b/bom/build.gradle index 1a1b3c2d9f5..6826879ce18 100644 --- a/bom/build.gradle +++ b/bom/build.gradle @@ -9,11 +9,14 @@ publishing { pom.withXml { def dependencyManagementNode = asNode().appendNode('dependencyManagement').appendNode('dependencies') - rootProject.subprojects.findAll { it != project && !it.path.startsWith(":docs:") && it != project(":docs") }.each { subProject -> - dependencyManagementNode.appendNode('dependency').with { - appendNode('groupId', subProject.group) - appendNode('artifactId',subProject.name) - appendNode('version', subProject.version) + def bomProject = project + rootProject.subprojects.each { subProject -> + if (subProject != bomProject && subProject.plugins.findPlugin("maven-publish")) { + dependencyManagementNode.appendNode('dependency').with { + appendNode('groupId', subProject.group) + appendNode('artifactId',subProject.name) + appendNode('version', subProject.version) + } } } } From 650e5b0a854d400982d0df1a187d4bbec4850caf Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 1 Dec 2019 22:59:43 +0100 Subject: [PATCH 0424/4969] Push to the build cache from AZP too --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index e2ddf080972..e5432e08061 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,7 +17,7 @@ buildscript { apply plugin: 'ch.myniva.s3-build-cache' -ext.isMasterBuild = System.getenv("CIRCLE_BRANCH") == "master" +ext.isMasterBuild = (System.getenv("CIRCLE_BRANCH") ?: System.getenv("BUILD_SOURCEBRANCHNAME")) == "master" buildCache { local { From ef96100721f32b8e435cdbde444cb0454acda4f5 Mon Sep 17 00:00:00 2001 From: Tristan Tarrant Date: Mon, 2 Dec 2019 14:12:02 +0100 Subject: [PATCH 0425/4969] Add Infinispan to "Who is (#2136) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 9caecd2261e..1ab42e286c7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -66,6 +66,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Streamlio](https://streaml.io/) - Integration and Chaos Testing of our fast data platform based on Apache Puslar, Apache Bookeeper and Apache Heron. * [Spring Session](https://projects.spring.io/spring-session/) - Redis, PostgreSQL, MySQL and MariaDB integration testing * [Apache Camel](https://camel.apache.org) - Testing Camel against native services such as Consul, Etcd and so on +* [Infinispan](https://infinispan.org) - Testing the Infinispan Server as well as integration tests with databases, LDAP and KeyCloak * [Instana](https://www.instana.com) - Testing agents and stream processing backends * [eBay Marketing](https://www.ebay.com) - Testing for MySQL, Cassandra, Redis, Couchbase, Kafka, etc. * [Skyscanner](https://www.skyscanner.net/) - Integration testing against HTTP service mocks and various data stores From 18c2e2244e675b97362cffa1d1e11e10f9d3792e Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 3 Dec 2019 09:11:08 +0100 Subject: [PATCH 0426/4969] GHA-based in-docker testing (#2121) * GHA-based in-docker testing * Add missing triggers * Damn it, YAML! * simplify * use `:test` instead of `:check` * fix volume mappings * set workdir * Force run's working directory * *correctly* force run's working directory :D * use `cd` * try to mount `/home/runner/` * try `working-directory` again * try `cd` again * try `github.repository` * debug * try another volume mounting * debug * use `docker run` * remove TTY * add regular tests * fix syntax * temporary remove `include` * remove "normal" tests for now * test on `push` only when pushed to `master` * auto-format with IDEA --- .editorconfig | 6 +++- .github/workflows/ci.yml | 21 ++++++++++++++ .travis.yml | 60 ---------------------------------------- 3 files changed, 26 insertions(+), 61 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.editorconfig b/.editorconfig index 4d023ed18d5..b4910e47661 100644 --- a/.editorconfig +++ b/.editorconfig @@ -21,4 +21,8 @@ indent_size = 4 # Never use star imports ij_java_names_count_to_use_import_on_demand = 99 ij_java_class_count_to_use_import_on_demand = 99 -ij_java_layout_static_imports_separately = true \ No newline at end of file +ij_java_layout_static_imports_separately = true + +[*.{yml, yaml}] +indent_size = 2 +ij_yaml_keep_indents_on_empty_lines = false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..7013e66bea6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: + pull_request: {} + push: { branches: [ master ] } + +jobs: + in-docker_test: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + - name: Build with Gradle + run: | + docker run -i --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v "$HOME:$HOME" \ + -v "$PWD:$PWD" \ + -w "$PWD" \ + openjdk:8-jdk-alpine \ + ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6e07925db3f..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -if: branch = master OR tag is present - -language: java -jdk: - - openjdk8 - -sudo: required -services: - - docker - -# Fix for https://travis-ci.community/t/problematic-docker-compose-version-1-23-1/5362/3 -before_install: - - sudo rm /usr/local/bin/docker-compose - - curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-Linux-x86_64 > docker-compose - - chmod +x docker-compose - - sudo mv docker-compose /usr/local/bin - -install: - - ./gradlew build -x check --scan --no-daemon - -jobs: - include: - - stage: test - env: [ NAME=core ] - script: ./gradlew testcontainers:check javadoc --scan --no-daemon -i - - - stage: test - env: [ NAME=core ] - jdk: openjdk11 - script: ./gradlew testcontainers:check --scan --no-daemon -i - - - stage: test - env: [ NAME=core ] - jdk: openjdk12 - script: ./gradlew testcontainers:check --scan --no-daemon -i - - - env: [ NAME=selenium ] - script: ./gradlew selenium:check --scan --no-daemon -i - - - env: [ NAME=modules ] - script: ./gradlew check -x testcontainers:check -x selenium:check -x jdbc-test:check --scan --no-daemon -i - - - env: [ NAME=jdbc ] - script: ./gradlew jdbc-test:check --scan --no-daemon -i - - - env: [ NAME=examples ] - script: cd examples && ./gradlew check --no-daemon -i - - # Run Docker-in-Docker tests inside Alpine - - env: [ NAME="docker-in-alpine-docker" ] - script: - - | - DOCKER_HOST=unix:///var/run/docker.sock DOCKER_TLS_VERIFY= docker run -t --rm \ - -v "$HOME/.gradle":/root/.gradle/ \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v "$(pwd)":"$(pwd)" \ - -w "$(pwd)" \ - openjdk:8-jdk-alpine \ - ./gradlew --no-daemon testcontainers:test --tests '*GenericContainerRuleTest' --scan -i - From 796c08a8c6f421adec2c91e9a2fa93b4d448aeb3 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 3 Dec 2019 11:22:43 +0100 Subject: [PATCH 0427/4969] fix `DockerClientFactory#dockerHostIpAddress` (#2119) * fix `DockerClientFactory#dockerHostIpAddress` * Remove conflicting `DockerClientFactoryTest#dockerClient` test --- .../testcontainers/DockerClientFactory.java | 134 +++++++++--------- .../DockerClientFactoryTest.java | 11 +- .../DockerClientConfigUtilsTest.java | 10 +- 3 files changed, 86 insertions(+), 69 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 54f44dbed3c..0ca7d41a209 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -62,8 +62,12 @@ public class DockerClientFactory { private static DockerClientFactory instance; // Cached client configuration - private DockerClientProviderStrategy strategy; - private boolean initialized = false; + @VisibleForTesting + DockerClientProviderStrategy strategy; + + @VisibleForTesting + DockerClient dockerClient; + private String activeApiVersion; private String activeExecutionDriver; @@ -74,10 +78,8 @@ public class DockerClientFactory { System.setProperty("org.testcontainers.shaded.io.netty.packagePrefix", "org.testcontainers.shaded."); } - /** - * Private constructor - */ - private DockerClientFactory() { + @VisibleForTesting + DockerClientFactory() { } @@ -98,6 +100,19 @@ public synchronized static DockerClientFactory instance() { return instance; } + @Synchronized + private DockerClientProviderStrategy getOrInitializeStrategy() { + if (strategy != null) { + return strategy; + } + + List configurationStrategies = new ArrayList<>(); + ServiceLoader.load(DockerClientProviderStrategy.class).forEach(configurationStrategies::add); + + strategy = DockerClientProviderStrategy.getFirstValidStrategy(configurationStrategies); + return strategy; + } + /** * * @return a new initialized Docker client @@ -105,63 +120,57 @@ public synchronized static DockerClientFactory instance() { @Synchronized public DockerClient client() { - if (strategy != null) { - return strategy.getClient(); + if (dockerClient != null) { + return dockerClient; } - List configurationStrategies = new ArrayList(); - ServiceLoader.load(DockerClientProviderStrategy.class).forEach( cs -> configurationStrategies.add( cs ) ); - - strategy = DockerClientProviderStrategy.getFirstValidStrategy(configurationStrategies); + final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); String hostIpAddress = strategy.getDockerHostIpAddress(); log.info("Docker host IP address is {}", hostIpAddress); - DockerClient client = strategy.getClient(); - - if (!initialized) { - Info dockerInfo = client.infoCmd().exec(); - Version version = client.versionCmd().exec(); - activeApiVersion = version.getApiVersion(); - activeExecutionDriver = dockerInfo.getExecutionDriver(); - log.info("Connected to docker: \n" + - " Server Version: " + dockerInfo.getServerVersion() + "\n" + - " API Version: " + activeApiVersion + "\n" + - " Operating System: " + dockerInfo.getOperatingSystem() + "\n" + - " Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB"); - - String ryukContainerId = null; - boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); - if (useRyuk) { - ryukContainerId = ResourceReaper.start(hostIpAddress, client); - log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit"); - } + final DockerClient client = strategy.getClient(); + + Info dockerInfo = client.infoCmd().exec(); + Version version = client.versionCmd().exec(); + activeApiVersion = version.getApiVersion(); + activeExecutionDriver = dockerInfo.getExecutionDriver(); + log.info("Connected to docker: \n" + + " Server Version: " + dockerInfo.getServerVersion() + "\n" + + " API Version: " + activeApiVersion + "\n" + + " Operating System: " + dockerInfo.getOperatingSystem() + "\n" + + " Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB"); + + String ryukContainerId = null; + boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); + if (useRyuk) { + ryukContainerId = ResourceReaper.start(hostIpAddress, client); + log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit"); + } - boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks(); - if (checksEnabled) { - VisibleAssertions.info("Checking the system..."); - checkDockerVersion(version.getVersion()); - if (ryukContainerId != null) { - checkDiskSpace(client, ryukContainerId); - } else { - runInsideDocker( - client, - createContainerCmd -> { - createContainerCmd.withName("testcontainers-checks-" + SESSION_ID); - createContainerCmd.getHostConfig().withAutoRemove(true); - createContainerCmd.withCmd("tail", "-f", "/dev/null"); - }, - (__, containerId) -> { - checkDiskSpace(client, containerId); - return ""; - } - ); - } + boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks(); + if (checksEnabled) { + VisibleAssertions.info("Checking the system..."); + checkDockerVersion(version.getVersion()); + if (ryukContainerId != null) { + checkDiskSpace(client, ryukContainerId); + } else { + runInsideDocker( + client, + createContainerCmd -> { + createContainerCmd.withName("testcontainers-checks-" + SESSION_ID); + createContainerCmd.getHostConfig().withAutoRemove(true); + createContainerCmd.withCmd("tail", "-f", "/dev/null"); + }, + (__, containerId) -> { + checkDiskSpace(client, containerId); + return ""; + } + ); } - - initialized = true; } - return client; + dockerClient = client; + return dockerClient; } private void checkDockerVersion(String dockerVersion) { @@ -237,15 +246,12 @@ public void checkAndPullImage(DockerClient client, String image) { * @return the IP address of the host running Docker */ public String dockerHostIpAddress() { - return strategy.getDockerHostIpAddress(); + return getOrInitializeStrategy().getDockerHostIpAddress(); } public T runInsideDocker(Consumer createContainerCmdConsumer, BiFunction block) { - if (strategy == null) { - client(); - } // We can't use client() here because it might create an infinite loop - return runInsideDocker(strategy.getClient(), createContainerCmdConsumer, block); + return runInsideDocker(getOrInitializeStrategy().getClient(), createContainerCmdConsumer, block); } private T runInsideDocker(DockerClient client, Consumer createContainerCmdConsumer, BiFunction block) { @@ -293,9 +299,7 @@ DiskSpaceUsage parseAvailableDiskSpace(String dfOutput) { * @return the docker API version of the daemon that we have connected to */ public String getActiveApiVersion() { - if (!initialized) { - client(); - } + client(); return activeApiVersion; } @@ -303,9 +307,7 @@ public String getActiveApiVersion() { * @return the docker execution driver of the daemon that we have connected to */ public String getActiveExecutionDriver() { - if (!initialized) { - client(); - } + client(); return activeExecutionDriver; } @@ -314,7 +316,7 @@ public String getActiveExecutionDriver() { * @return whether or not the currently active strategy is of the provided type */ public boolean isUsing(Class providerStrategyClass) { - return providerStrategyClass.isAssignableFrom(this.strategy.getClass()); + return strategy != null && providerStrategyClass.isAssignableFrom(this.strategy.getClass()); } private static class NotEnoughDiskSpaceException extends RuntimeException { diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index e13c3875f31..19a591be919 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -7,6 +7,8 @@ import org.testcontainers.dockerclient.LogToStringContainerCallback; import org.testcontainers.utility.TestcontainersConfiguration; +import static org.assertj.core.api.Assertions.assertThat; + /** * Test for {@link DockerClientFactory}. */ @@ -43,4 +45,11 @@ public void shouldHandleBigDiskSize() throws Exception { VisibleAssertions.assertEquals("Available MB is correct", 2982480572L / 1024L, usage.availableMB.orElse(0L)); VisibleAssertions.assertEquals("Available percentage is correct", 31, usage.usedPercent.orElse(0)); } -} \ No newline at end of file + + @Test + public void dockerHostIpAddress() { + DockerClientFactory instance = new DockerClientFactory(); + instance.strategy = null; + assertThat(instance.dockerHostIpAddress()).isNotNull(); + } +} diff --git a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java index e4e29550b9c..2e88982a7a8 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java @@ -6,6 +6,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; public class DockerClientConfigUtilsTest { @@ -33,7 +34,7 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() { String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); assertEquals("12.23.34.45", actual); } - + @Test public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() { DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder() @@ -43,11 +44,16 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() { String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); assertEquals("12.23.34.45", actual); } - + @Test @Ignore public void getDockerHostIpAddressShouldReturnNullWhenUnsupportedUriScheme() { DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("gopher://12.23.34.45").build(); String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); assertNull(actual); } + + @Test(timeout = 5_000) + public void getDefaultGateway() { + assertNotNull(DockerClientConfigUtils.getDefaultGateway()); + } } From 82876e489f19796229d96bb116ab7d2415c96cdb Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 3 Dec 2019 13:24:38 +0000 Subject: [PATCH 0428/4969] Use Python 3.7 for netlify doc generation (#2143) --- .envrc | 2 +- runtime.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.envrc b/.envrc index 3e6a147e52b..dad2eb2cfc6 100644 --- a/.envrc +++ b/.envrc @@ -1 +1 @@ -use python 3.6.0 +use python 3.7.5 diff --git a/runtime.txt b/runtime.txt index d70c8f8d89f..475ba515c04 100644 --- a/runtime.txt +++ b/runtime.txt @@ -1 +1 @@ -3.6 +3.7 From 77189eff82a5a033ae116c38a6e29a43cea985bf Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 5 Dec 2019 18:33:26 +0200 Subject: [PATCH 0429/4969] Set AWS credentials for the build cache in AZP (#2138) --- azure-pipelines.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d6efa593dcb..4b060c5fcea 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,6 +3,9 @@ jobs: steps: - task: Gradle@2 displayName: Build & test + env: + AWS_ACCESS_KEY_ID: $(aws.accessKeyId) + AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' @@ -14,6 +17,9 @@ jobs: steps: - task: Gradle@2 displayName: Build & test + env: + AWS_ACCESS_KEY_ID: $(aws.accessKeyId) + AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' @@ -25,6 +31,9 @@ jobs: steps: - task: Gradle@2 displayName: Build & test + env: + AWS_ACCESS_KEY_ID: $(aws.accessKeyId) + AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' From 3f6c38be0c3b2a228be69db61607d9991a03b998 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2019 20:49:39 +0000 Subject: [PATCH 0430/4969] Bump java-client from 2.7.10 to 2.7.11 in /modules/couchbase (#2150) Bumps [java-client](https://github.com/couchbase/couchbase-java-client) from 2.7.10 to 2.7.11. - [Release notes](https://github.com/couchbase/couchbase-java-client/releases) - [Commits](https://github.com/couchbase/couchbase-java-client/compare/2.7.10...2.7.11) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 7642bb2fc5b..27074f1bff7 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.10' + compile 'com.couchbase.client:java-client:2.7.11' testCompile project(':test-support') } From 3f6d62601961cf400fa6bc597fc99ea25be5356a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2019 21:25:16 +0000 Subject: [PATCH 0431/4969] Bump mockito-core from 3.1.0 to 3.2.0 in /modules/junit-jupiter (#2131) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index f6f23aa8959..b5c974ecd89 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.1' testCompile 'redis.clients:jedis:3.1.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' - testCompile ('org.mockito:mockito-core:3.1.0') { + testCompile ('org.mockito:mockito-core:3.2.0') { exclude(module: 'hamcrest-core') } From 0adacdef409e76f79e3e3dc2ee988b44541bf33f Mon Sep 17 00:00:00 2001 From: Andrew Guibert Date: Thu, 5 Dec 2019 15:31:17 -0600 Subject: [PATCH 0432/4969] Truncate mode bits for z/OS file permissions (#2023) --- .../org/testcontainers/utility/MountableFile.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 37312116734..22939b0e1fd 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.compress.archivers.tar.TarConstants; import org.apache.commons.lang.SystemUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.DockerClientFactory; @@ -368,7 +369,15 @@ private int getUnixFileMode(final String pathAsString) { @UnstableAPI public static int getUnixFileMode(final Path path) { try { - return (int) Files.readAttributes(path, "unix:mode").get("mode"); + int unixMode = (int) Files.readAttributes(path, "unix:mode").get("mode"); + // Truncate mode bits for z/OS + if ("OS/390".equals(SystemUtils.OS_NAME) || + "z/OS".equals(SystemUtils.OS_NAME) || + "zOS".equals(SystemUtils.OS_NAME) ) { + unixMode &= TarConstants.MAXID; + unixMode |= Files.isDirectory(path) ? 040000 : 0100000; + } + return unixMode; } catch (IOException | UnsupportedOperationException e) { // fallback for non-posix environments int mode = DEFAULT_FILE_MODE; From bb0554b626dd29031ee01efc14f21972a0015fba Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 6 Dec 2019 11:35:33 +0200 Subject: [PATCH 0433/4969] do not implicitly connect to Kafka network (#2139) Apparently, there is a bug(?) in Docker that sometimes(!) re-assigns random ports when container is connect to network. It means that we cannot lazily connect KafkaContainer to network in case it wasn't set. --- .../org/testcontainers/containers/KafkaContainer.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 60037acfd45..b0ce047f5d4 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -39,6 +39,7 @@ public KafkaContainer() { public KafkaContainer(String confluentPlatformVersion) { super(TestcontainersConfiguration.getInstance().getKafkaImage() + ":" + confluentPlatformVersion); + super.withNetwork(Network.SHARED); withExposedPorts(KAFKA_PORT); // Use two listeners with different names, it will force Kafka to communicate with itself via internal @@ -70,16 +71,6 @@ public Network getNetwork() { "Consider using KafkaContainer#withNetwork", new Exception("Deprecated method") ); - Network network = Network.SHARED; - super.withNetwork(network); - - if (getContainerId() != null) { - dockerClient.connectToNetworkCmd() - .withContainerId(getContainerId()) - .withNetworkId(network.getId()) - .exec(); - } - return network; } return super.getNetwork(); } From 500fd7404c07712c1f8af2d5f6ba51a048b9f6da Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 6 Dec 2019 12:07:41 +0000 Subject: [PATCH 0434/4969] Improve Docker Compose error messaging (#2154) Co-Authored-By: Richard North Co-authored-by: Matthias Hahn Co-authored-by: null <38075918+HaMatthias@users.noreply.github.com> --- .../containers/DockerComposeContainer.java | 10 +++++++++- .../testcontainers/junit/DockerComposeServiceTest.java | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 31d84284584..7dec6399b8f 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -385,7 +385,15 @@ public String getServiceHost(String serviceName, Integer servicePort) { * @return a port that can be used for accessing the service container. */ public Integer getServicePort(String serviceName, Integer servicePort) { - return ambassadorContainer.getMappedPort(ambassadorPortMappings.get(getServiceInstanceName(serviceName)).get(servicePort)); + Map portMap = ambassadorPortMappings.get(getServiceInstanceName(serviceName)); + + if (portMap == null) { + throw new IllegalArgumentException("Could not get a port for '" + serviceName + "'. " + + "Testcontainers does not have an exposed port configured for '" + serviceName + "'. "+ + "To fix, please ensure that the service '" + serviceName + "' has ports exposed using .withExposedService(...)"); + } else { + return ambassadorContainer.getMappedPort(portMap.get(servicePort)); + } } public SELF withScaledService(String serviceBaseName, int numInstances) { diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java index c0360050d27..ec8c50d42ab 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java @@ -21,7 +21,7 @@ protected DockerComposeContainer getEnvironment() { return environment; } - @Test(expected = NullPointerException.class) + @Test(expected = IllegalArgumentException.class) public void testDbIsNotStarting() { environment.getServicePort("db_1", 10001); } From b51789896d404bee9f439099e5cbb4d79f62ef99 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2019 12:48:08 +0000 Subject: [PATCH 0435/4969] Bump vibur-dbcp from 22.2 to 25.0 in /modules/mariadb (#2128) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 541d3967680..a881b63cb99 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.29' - testCompile 'org.vibur:vibur-dbcp:22.2' + testCompile 'org.vibur:vibur-dbcp:25.0' } From 968a56e45e2700700926cf4fe4128be6cab933e7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2019 13:07:42 +0000 Subject: [PATCH 0436/4969] Bump mockito-core from 3.1.0 to 3.2.0 in /core (#2129) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9da3288d0c3..461c5696347 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -109,7 +109,7 @@ dependencies { testCompile 'redis.clients:jedis:3.1.0' testCompile 'com.rabbitmq:amqp-client:5.7.3' testCompile 'org.mongodb:mongo-java-driver:3.11.2' - testCompile ('org.mockito:mockito-core:3.1.0') { + testCompile ('org.mockito:mockito-core:3.2.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From b03d77fb4a4f75b95b674b53b41725e09cd61fda Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2019 13:36:08 +0000 Subject: [PATCH 0437/4969] Bump vibur-dbcp from 22.2 to 25.0 in /modules/mysql (#2130) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 2a71e8f9d04..d9961293d86 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.29' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.vibur:vibur-dbcp:22.2' + testCompile 'org.vibur:vibur-dbcp:25.0' } From 35fd71d57b6b0ea862f19e7eb43001f1fb219098 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2019 14:02:47 +0000 Subject: [PATCH 0438/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#2142) --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 11c8b57f07a..9e7ac832916 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.4.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.5.0" testCompile "org.elasticsearch.client:transport:6.7.1" } From 9a45baa2f8d9e7fedb17fb2378b5da012bfb7103 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 7 Dec 2019 21:32:10 +0700 Subject: [PATCH 0439/4969] Refactor deprecated Mockito API usages (#2039) --- .../containers/FailureDetectingExternalResourceTest.java | 2 +- .../testcontainers/utility/AuthenticatedImagePullTest.java | 4 ++-- .../org/testcontainers/dynamodb/DynaliteContainerTest.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java b/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java index 47d594c4c02..15a9eba7d17 100644 --- a/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java +++ b/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java @@ -3,7 +3,7 @@ import org.junit.Test; import org.junit.runner.Description; import org.junit.runners.model.Statement; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 19b933d174c..78b54798cd1 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -16,8 +16,8 @@ import java.util.concurrent.TimeUnit; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; diff --git a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java index 2d414aecb3b..524d3f6c34c 100644 --- a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java +++ b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java @@ -37,7 +37,7 @@ private void runTest(AmazonDynamoDB client) { "Name", ScalarAttributeType.S)) .withKeySchema(new KeySchemaElement("Name", KeyType.HASH)) .withProvisionedThroughput(new ProvisionedThroughput( - new Long(10), new Long(10))) + 10L, 10L)) .withTableName("foo"); @@ -49,4 +49,4 @@ private void runTest(AmazonDynamoDB client) { assertEquals("the table has the right name", "foo", tableDescription.getTableName()); assertEquals("the name has the right primary key", "Name", tableDescription.getKeySchema().get(0).getAttributeName()); } -} \ No newline at end of file +} From 2af09196b55cd36d18cf64970c8a2504dd629f84 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:55:56 +0100 Subject: [PATCH 0440/4969] Bump amqp-client from 5.7.3 to 5.8.0 in /core (#2173) Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.7.3 to 5.8.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.7.3...v5.8.0) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 461c5696347..dcb4165d08d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -107,7 +107,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.1.0' - testCompile 'com.rabbitmq:amqp-client:5.7.3' + testCompile 'com.rabbitmq:amqp-client:5.8.0' testCompile 'org.mongodb:mongo-java-driver:3.11.2' testCompile ('org.mockito:mockito-core:3.2.0') { exclude(module: 'hamcrest-core') From 309aad0662c748819f82101087f78082fd2806eb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:56:41 +0100 Subject: [PATCH 0441/4969] Bump tomcat-jdbc from 9.0.29 to 9.0.30 in /modules/mysql (#2174) Bumps tomcat-jdbc from 9.0.29 to 9.0.30. Signed-off-by: dependabot-preview[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index d9961293d86..0b70ea3af6a 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.18' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.29' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.30' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' } From 666781cef6ea70de7eff236fe5e9ef9ce2a4e4d9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:57:14 +0100 Subject: [PATCH 0442/4969] Bump tomcat-jdbc from 9.0.29 to 9.0.30 in /modules/mariadb (#2172) Bumps tomcat-jdbc from 9.0.29 to 9.0.30. Signed-off-by: dependabot-preview[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index a881b63cb99..041b0a146da 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.2' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.29' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.30' testCompile 'org.vibur:vibur-dbcp:25.0' } From b4fe1eddc48b23488eb5d1c6c65071169913424a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:57:51 +0100 Subject: [PATCH 0443/4969] Bump mongo-java-driver from 3.11.2 to 3.12.0 in /core (#2168) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.11.2 to 3.12.0. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.11.2...r3.12.0) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index dcb4165d08d..618c31c7176 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,7 +108,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.1.0' testCompile 'com.rabbitmq:amqp-client:5.8.0' - testCompile 'org.mongodb:mongo-java-driver:3.11.2' + testCompile 'org.mongodb:mongo-java-driver:3.12.0' testCompile ('org.mockito:mockito-core:3.2.0') { exclude(module: 'hamcrest-core') } From ae6d150eaf95cec56cb94fe7d1cdc33b9c9f111e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:58:48 +0100 Subject: [PATCH 0444/4969] Bump postgresql from 42.2.8 to 42.2.9 in /modules/junit-jupiter (#2160) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.8 to 42.2.9. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.8...REL42.2.9) Signed-off-by: dependabot-preview[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index b5c974ecd89..8ff335251a3 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } - testRuntime 'org.postgresql:postgresql:42.2.8' + testRuntime 'org.postgresql:postgresql:42.2.9' testRuntime 'mysql:mysql-connector-java:8.0.18' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.2' } From 98a201aa91344484d2c8cb4290361cc9b9c512a2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 16:00:30 +0100 Subject: [PATCH 0445/4969] Bump postgresql from 42.2.8 to 42.2.9 in /modules/postgresql (#2159) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.8 to 42.2.9. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.8...REL42.2.9) Signed-off-by: dependabot-preview[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index c070ce9ba13..a4bf697a3ad 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { compile project(':jdbc') - testCompile 'org.postgresql:postgresql:42.2.8' + testCompile 'org.postgresql:postgresql:42.2.9' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' } From 0ba7a0e5644f7a23fc90f5988fde46ad5d6748ec Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 16:42:21 +0100 Subject: [PATCH 0446/4969] Bump postgresql from 42.2.8 to 42.2.9 in /examples (#2162) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.8 to 42.2.9. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.8...REL42.2.9) Signed-off-by: dependabot-preview[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index eb10aed7159..dc9f7158e29 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.29' implementation 'com.squareup.okhttp3:okhttp:3.14.4' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.8' + testImplementation 'org.postgresql:postgresql:42.2.9' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From 9a8ada41c564cff615df98031ab7c0ccfa40101d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 16:43:11 +0100 Subject: [PATCH 0447/4969] Bump postgresql from 42.2.8 to 42.2.9 in /modules/spock (#2158) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.8 to 42.2.9. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.8...REL42.2.9) Signed-off-by: dependabot-preview[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index d84e8776af3..2974784d466 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -13,6 +13,6 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.1' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' - testRuntime 'org.postgresql:postgresql:42.2.8' + testRuntime 'org.postgresql:postgresql:42.2.9' testRuntime 'mysql:mysql-connector-java:8.0.18' } From 9bd7a61f5b847596c595ea75e69fe9faea486b2f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2019 16:51:25 +0100 Subject: [PATCH 0448/4969] Bump org.springframework.boot in /examples (#2161) Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.2.1.RELEASE to 2.2.2.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.1.RELEASE...v2.2.2.RELEASE) Signed-off-by: dependabot-preview[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 5386234dccb..5b6d71934b9 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.1.RELEASE' + id 'org.springframework.boot' version '2.2.2.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 2a67123fa03..bea11bf0909 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.1.RELEASE' + id 'org.springframework.boot' version '2.2.2.RELEASE' } apply plugin: 'io.spring.dependency-management' From e0cfea8f5848508b3e108259865942b9719142bb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 14 Dec 2019 13:20:49 +0100 Subject: [PATCH 0449/4969] Bump influxdb-java from 2.16 to 2.17 in /modules/influxdb (#2157) Bumps [influxdb-java](https://github.com/influxdata/influxdb-java) from 2.16 to 2.17. - [Release notes](https://github.com/influxdata/influxdb-java/releases) - [Changelog](https://github.com/influxdata/influxdb-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-java/compare/influxdb-java-2.16...influxdb-java-2.17) Signed-off-by: dependabot-preview[bot] --- modules/influxdb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index 186174c242f..d349e06da12 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { compile project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.16' - testCompile 'org.influxdb:influxdb-java:2.15' + compileOnly 'org.influxdb:influxdb-java:2.17' + testCompile 'org.influxdb:influxdb-java:2.17' } From dbffb52b426a2021484ff2abc765080288c29e8c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 14 Dec 2019 12:37:23 +0000 Subject: [PATCH 0450/4969] Bump testng from 7.0.0 to 7.1.0 in /examples (#2164) --- examples/redis-backed-cache-testng/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 8b133f0cc1b..98d0f4e06aa 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' - testImplementation 'org.testng:testng:7.0.0' + testImplementation 'org.testng:testng:7.1.0' } test { From d6889e289bad8a3d7bdfd59c1fe4ac02111e7516 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 14 Dec 2019 13:39:28 +0100 Subject: [PATCH 0451/4969] Add GitHub action to automatically update docs version (#2122) * Add GitHub action to automatically update docs version * Fix syntax error * Update update-docs-version.yml * Update update-docs-version.yml * Use ad-m/github-push-action * Updates following review --- .github/workflows/update-docs-version.yml | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/update-docs-version.yml diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml new file mode 100644 index 00000000000..ad8773db2db --- /dev/null +++ b/.github/workflows/update-docs-version.yml @@ -0,0 +1,27 @@ +name: Update docs version + +on: + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + - name: Checkout master + run: git checkout master + - name: Update latest_version property in mkdocs.yml + run: | + sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml + git diff + - name: Commit changes + run: | + git config user.email "nobody@testcontainers.org" + git config user.name "GitHub Action - Update docs version" + git add mkdocs.yml + git commit -m "Update documentation version to ${GITHUB_REF##*/}" -m "skip-checks: true" || echo "not changed" + - name: Push changes + uses: ad-m/github-push-action@68af9897f2b021035ca3952bf354bbb4675c1762 # v0.5.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} From 6e1d211f9be44e564d47fddedad809215813d7e0 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 14 Dec 2019 14:52:59 +0100 Subject: [PATCH 0452/4969] Fix framing in OkHttp transport (#2155) we were skipping first 8 bytes in case of a RAW stream --- .../okhttp/OkHttpInvocationBuilder.java | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java index c7f679eb22b..cada10328ec 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java @@ -35,6 +35,8 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.Objects; import java.util.function.Consumer; @@ -362,23 +364,34 @@ public void accept(BufferedSource source) { try { while (!source.exhausted()) { // See https://docs.docker.com/engine/api/v1.37/#operation/ContainerAttach - if(!source.request(HEADER_SIZE)) { + // [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT} + + if (!source.request(HEADER_SIZE)) { return; } - StreamType streamType = streamType(source.readByte()); - source.skip(3); - int payloadSize = source.readInt(); + byte[] bytes = source.readByteArray(HEADER_SIZE); + + StreamType streamType = streamType(bytes[0]); - if (streamType != StreamType.RAW) { - if (!source.request(payloadSize)) { - return; + if (streamType == StreamType.RAW) { + resultCallback.onNext(new Frame(StreamType.RAW, bytes)); + byte[] buffer = new byte[1024]; + while (!source.exhausted()) { + int readBytes = source.read(buffer); + if (readBytes != -1) { + resultCallback.onNext(new Frame(StreamType.RAW, Arrays.copyOf(buffer, readBytes))); + } } - byte[] payload = source.readByteArray(payloadSize); + return; + } - resultCallback.onNext(new Frame(streamType, payload)); - } else { - resultCallback.onNext(new Frame(streamType, source.readByteArray())); + int payloadSize = ByteBuffer.wrap(bytes, 4, 4).getInt(); + if (!source.request(payloadSize)) { + return; } + byte[] payload = source.readByteArray(payloadSize); + + resultCallback.onNext(new Frame(streamType, payload)); } } catch (Exception e) { resultCallback.onError(e); From 464cba86b6aa0e17dceec13f7bee3fcd5baaf7f1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2019 17:29:58 +0000 Subject: [PATCH 0453/4969] Bump jedis from 3.1.0 to 3.2.0 in /examples (#2184) --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 98d0f4e06aa..12e78729a28 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.29' - implementation 'redis.clients:jedis:3.1.0' + implementation 'redis.clients:jedis:3.2.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index a95000e8d71..664a0fac876 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.29' - implementation 'redis.clients:jedis:3.1.0' + implementation 'redis.clients:jedis:3.2.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 6cb2e6d77c5..3b4af328379 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.1.0' + implementation 'redis.clients:jedis:3.2.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.29' From e6f92c695025e9f243f8f94572143f33eceebf5d Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 16 Dec 2019 18:31:26 +0100 Subject: [PATCH 0454/4969] Remove duplicated DockerImageNameTest test case (#2040) --- .../java/org/testcontainers/utility/DockerImageNameTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index 37d2472949f..54488773652 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -16,7 +16,7 @@ public static class ValidNames { @Parameterized.Parameters(name = "{0}") public static String[] getNames() { - return new String[]{"myname:latest", + return new String[]{ "myname:latest", "repo/my-name:1.0", "registry.foo.com:1234/my-name:1.0", From 95ae65170d11461b5dbd75aee202ce2c70b9a930 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 08:58:38 +0000 Subject: [PATCH 0455/4969] Bump kafka-clients from 2.3.1 to 2.4.0 in /modules/kafka (#2182) Bumps kafka-clients from 2.3.1 to 2.4.0. Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index d9d7c20ca4a..d064e46c1dc 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.3.1' + testCompile 'org.apache.kafka:kafka-clients:2.4.0' testCompile 'org.assertj:assertj-core:3.14.0' testCompile 'com.google.guava:guava:23.0' } From 4170e72e3e2d32064a71af117026356cb92a3139 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 08:58:47 +0000 Subject: [PATCH 0456/4969] Bump jedis from 3.1.0 to 3.2.0 in /modules/junit-jupiter (#2181) Bumps [jedis](https://github.com/xetorthio/jedis) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/xetorthio/jedis/releases) - [Commits](https://github.com/xetorthio/jedis/compare/jedis-3.1.0...jedis-3.2.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 8ff335251a3..6cae8d48a67 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.1' - testCompile 'redis.clients:jedis:3.1.0' + testCompile 'redis.clients:jedis:3.2.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testCompile ('org.mockito:mockito-core:3.2.0') { exclude(module: 'hamcrest-core') From 6958fb2c9af5ab953787086d5ddc110e326d4a00 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 08:58:58 +0000 Subject: [PATCH 0457/4969] Bump jedis from 3.1.0 to 3.2.0 in /core (#2183) Bumps [jedis](https://github.com/xetorthio/jedis) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/xetorthio/jedis/releases) - [Commits](https://github.com/xetorthio/jedis/compare/jedis-3.1.0...jedis-3.2.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 618c31c7176..8517033e51b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -106,7 +106,7 @@ dependencies { } testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testCompile 'redis.clients:jedis:3.1.0' + testCompile 'redis.clients:jedis:3.2.0' testCompile 'com.rabbitmq:amqp-client:5.8.0' testCompile 'org.mongodb:mongo-java-driver:3.12.0' testCompile ('org.mockito:mockito-core:3.2.0') { From 639cacde7e0bb825da1ace99c7b70ca0d8233802 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 09:29:52 +0000 Subject: [PATCH 0458/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#2197) --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 9e7ac832916..2201efff48a 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.5.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.5.1" testCompile "org.elasticsearch.client:transport:6.7.1" } From b0d1c9be21ee0bd9255920ef7b7299807053df7c Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 19 Dec 2019 10:48:33 +0100 Subject: [PATCH 0459/4969] Use `inspectNetworkCmd` to get the gateway's IP (#2151) --- .../dockerclient/DockerClientConfigUtils.java | 6 ++- .../DockerClientProviderStrategy.java | 39 ++++++++++++++++++- .../DockerClientConfigUtilsTest.java | 38 ++++++------------ 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java index bfeabc63f8a..d88dc76331f 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java @@ -43,8 +43,10 @@ public class DockerClientConfigUtils { .map(StringUtils::trimToEmpty) .filter(StringUtils::isNotBlank); - - + /** + * Use {@link DockerClientFactory#dockerHostIpAddress()} + */ + @Deprecated public static String getDockerHostIpAddress(DockerClientConfig config) { switch (config.getDockerHost().getScheme()) { case "http": diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 7101b23b21a..aa607964ae5 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -1,8 +1,10 @@ package org.testcontainers.dockerclient; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Network; import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.core.DockerClientConfig; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; @@ -17,6 +19,7 @@ import org.testcontainers.dockerclient.transport.okhttp.OkHttpDockerCmdExecFactory; import org.testcontainers.utility.TestcontainersConfiguration; +import java.net.URI; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -33,6 +36,8 @@ public abstract class DockerClientProviderStrategy { protected DockerClient client; protected DockerClientConfig config; + private String dockerHostIpAddress; + private static final RateLimiter PING_RATE_LIMITER = RateLimiterBuilder.newBuilder() .withRate(2, TimeUnit.SECONDS) .withConstantThroughput() @@ -188,8 +193,38 @@ protected void ping(DockerClient client, int timeoutInSeconds) { } } - public String getDockerHostIpAddress() { - return DockerClientConfigUtils.getDockerHostIpAddress(this.config); + public synchronized String getDockerHostIpAddress() { + if (dockerHostIpAddress == null) { + dockerHostIpAddress = resolveDockerHostIpAddress(client, config.getDockerHost()); + } + return dockerHostIpAddress; + } + + @VisibleForTesting + static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost) { + switch (dockerHost.getScheme()) { + case "http": + case "https": + case "tcp": + return dockerHost.getHost(); + case "unix": + case "npipe": + if (DockerClientConfigUtils.IN_A_CONTAINER) { + return client.inspectNetworkCmd() + .withNetworkId("bridge") + .exec() + .getIpam() + .getConfig() + .stream() + .filter(it -> it.getGateway() != null) + .findAny() + .map(Network.Ipam.Config::getGateway) + .orElse("localhost"); + } + return "localhost"; + default: + return null; + } } protected void checkOSType() { diff --git a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java index 2e88982a7a8..353d6ea94e7 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java @@ -1,9 +1,10 @@ package org.testcontainers.dockerclient; -import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.DockerClientConfig; -import org.junit.Ignore; +import com.github.dockerjava.api.DockerClient; import org.junit.Test; +import org.testcontainers.DockerClientFactory; + +import java.net.URI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -11,44 +12,29 @@ public class DockerClientConfigUtilsTest { + DockerClient client = DockerClientFactory.lazyClient(); + @Test public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() { - DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost("unix:///var/run/docker.sock") - .withDockerTlsVerify(false) // TODO - check wrt. https://github.com/docker-java/docker-java/issues/588 - .build(); - String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("unix:///var/run/docker.sock")); assertEquals("localhost", actual); } - @Test @Ignore - public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpUri() { - DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("http://12.23.34.45").build(); - String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); - assertEquals("12.23.34.45", actual); - } - - @Test @Ignore + @Test public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() { - DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("https://12.23.34.45").build(); - String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("http://12.23.34.45")); assertEquals("12.23.34.45", actual); } @Test public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() { - DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost("tcp://12.23.34.45") - .withDockerTlsVerify(false) // TODO - check wrt. https://github.com/docker-java/docker-java/issues/588 - .build(); - String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("tcp://12.23.34.45")); assertEquals("12.23.34.45", actual); } - @Test @Ignore + @Test public void getDockerHostIpAddressShouldReturnNullWhenUnsupportedUriScheme() { - DockerClientConfig configuration = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("gopher://12.23.34.45").build(); - String actual = DockerClientConfigUtils.getDockerHostIpAddress(configuration); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("gopher://12.23.34.45")); assertNull(actual); } From e9b2783a3fcbd6e73f168a4d55c1b7acd229511b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 10:25:37 +0000 Subject: [PATCH 0460/4969] Bump mockito-core from 3.2.0 to 3.2.4 in /modules/junit-jupiter (#2189) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.2.0 to 3.2.4. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.2.0...v3.2.4) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 6cae8d48a67..18cc5ddfe96 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.1' testCompile 'redis.clients:jedis:3.2.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' - testCompile ('org.mockito:mockito-core:3.2.0') { + testCompile ('org.mockito:mockito-core:3.2.4') { exclude(module: 'hamcrest-core') } From 76d4668a40e2b2105fcc877158e520e93ca96137 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 10:47:47 +0000 Subject: [PATCH 0461/4969] Bump vault-java-driver from 5.0.0 to 5.1.0 in /modules/vault (#2187) Bumps [vault-java-driver](https://github.com/BetterCloud/vault-java-driver) from 5.0.0 to 5.1.0. - [Release notes](https://github.com/BetterCloud/vault-java-driver/releases) - [Commits](https://github.com/BetterCloud/vault-java-driver/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 55249f74fb0..0a68c9310e0 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Vault" dependencies { compile project(':testcontainers') - testCompile 'com.bettercloud:vault-java-driver:5.0.0' + testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.1.2' testCompile 'org.assertj:assertj-core:3.14.0' From 2065330f6690c02931f69e1f6ab7717e466e4e55 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 10:47:57 +0000 Subject: [PATCH 0462/4969] Bump slf4j-api from 1.7.29 to 1.7.30 in /core (#2188) Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.29 to 1.7.30. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.29...v_1.7.30) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 8517033e51b..585faedfaa2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -57,7 +57,7 @@ project.tasks.check.dependsOn(jarFileTest) dependencies { compile 'junit:junit:4.12' - compile 'org.slf4j:slf4j-api:1.7.29' + compile 'org.slf4j:slf4j-api:1.7.30' compile 'org.jetbrains:annotations:17.0.0' compile 'javax.annotation:javax.annotation-api:1.3.2' compile 'org.apache.commons:commons-compress:1.19' From 10114683dfe212c48f1301c96af929363b65dbd8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 10:48:24 +0000 Subject: [PATCH 0463/4969] Bump mockito-core from 3.2.0 to 3.2.4 in /core (#2186) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.2.0 to 3.2.4. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.2.0...v3.2.4) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 585faedfaa2..2d76c38c0de 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -109,7 +109,7 @@ dependencies { testCompile 'redis.clients:jedis:3.2.0' testCompile 'com.rabbitmq:amqp-client:5.8.0' testCompile 'org.mongodb:mongo-java-driver:3.12.0' - testCompile ('org.mockito:mockito-core:3.2.0') { + testCompile ('org.mockito:mockito-core:3.2.4') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From e7e05d29a3b733315a2b0e620741e942f3c56fc4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 10:48:54 +0000 Subject: [PATCH 0464/4969] Bump slf4j-api from 1.7.29 to 1.7.30 in /examples (#2190) Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.29 to 1.7.30. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.29...v_1.7.30) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index dc9f7158e29..dea159a89b5 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { jcenter() } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.29' + compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:3.14.4' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.9' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 12e78729a28..cf22e89c528 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.29' + compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'redis.clients:jedis:3.2.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 664a0fac876..b665b9a24a4 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.29' + compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'redis.clients:jedis:3.2.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 3b4af328379..b06d4e7cb30 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:3.2.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:1.7.29' + compileOnly 'org.slf4j:slf4j-api:1.7.30' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:testcontainers' From 08234f88a3c3f460db4684da683378d8bf4d026c Mon Sep 17 00:00:00 2001 From: William Delanoue Date: Mon, 23 Dec 2019 03:39:08 +0100 Subject: [PATCH 0465/4969] closes #1697: add vhost parameter for policies (#1701) --- .../containers/RabbitMQContainer.java | 9 +++++ .../containers/RabbitMQContainerTest.java | 35 +++++++++++-------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index ea25bf629e6..ede111ed2d8 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -263,6 +263,15 @@ public RabbitMQContainer withPolicy(String name, String pattern, Map definition) { + values.add(asList("rabbitmqadmin", "declare", "policy", + "--vhost=" + vhost, + "name=" + name, + "pattern=" + pattern, + "definition=" + toJson(definition))); + return self(); + } + public RabbitMQContainer withPolicy(String name, String pattern, Map definition, int priority, String applyTo) { values.add(asList("rabbitmqadmin", "declare", "policy", "name=" + name, diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index bdda594818f..5822e213a82 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -154,21 +154,22 @@ public void shouldStartTheWholeEnchilada() throws IOException, InterruptedExcept { try (RabbitMQContainer container = new RabbitMQContainer()) { container - .withVhost("vhost1") - .withVhostLimit("vhost1", "max-connections", 1) - .withVhost("vhost2", true) - .withExchange("direct-exchange", "direct") - .withExchange("topic-exchange", "topic") - .withQueue("queue1") - .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) - .withBinding("direct-exchange", "queue1") - .withUser("user1", "password1") - .withUser("user2", "password2", ImmutableSet.of("administrator")) - .withPermission("vhost1", "user1", ".*", ".*", ".*") - .withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues") - .withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct")) - .withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues") - .withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange"); + .withVhost("vhost1") + .withVhostLimit("vhost1", "max-connections", 1) + .withVhost("vhost2", true) + .withExchange("direct-exchange", "direct") + .withExchange("topic-exchange", "topic") + .withQueue("queue1") + .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) + .withBinding("direct-exchange", "queue1") + .withUser("user1", "password1") + .withUser("user2", "password2", ImmutableSet.of("administrator")) + .withPermission("vhost1", "user1", ".*", ".*", ".*") + .withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues") + .withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct")) + .withPolicy("vhost2", "ha-all", ".*", ImmutableMap.of("ha-mode", "all", "ha-sync-mode", "automatic")) + .withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues") + .withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange"); container.start(); @@ -192,6 +193,10 @@ public void shouldStartTheWholeEnchilada() throws IOException, InterruptedExcept .getStdout()) .contains("max length policy", "alternate exchange policy"); + assertThat(container.execInContainer("rabbitmqadmin", "list", "policies", "--vhost=vhost2") + .getStdout()) + .contains("ha-all", "ha-sync-mode"); + assertThat(container.execInContainer("rabbitmqadmin", "list", "operator_policies") .getStdout()) .contains("operator policy 1"); From 938c09a766f56fb09918abd7e352b9bdbedf1a4f Mon Sep 17 00:00:00 2001 From: Billy Yuan Date: Thu, 26 Dec 2019 21:08:59 +0800 Subject: [PATCH 0466/4969] Add Vert.x SQL Client to Userlist (#2211) Signed-off-by: Billy Yuan --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 1ab42e286c7..f214bf0f73f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -75,6 +75,7 @@ You can also [check the latest version available on Maven Central](https://searc * [Zalando SE](https://corporate.zalando.com/en) - Testing core business services * [Europace AG](https://tech.europace.de/) - Integration testing for databases and micro services * [Micronaut Data](https://github.com/micronaut-projects/micronaut-data/) - Testing of Micronaut Data JDBC, a database access toolkit +* [Vert.x SQL Client](https://github.com/eclipse-vertx/vertx-sql-client) - Testing with PostgreSQL, MySQL, MariaDB, SQL Server, etc. * [JHipster](https://www.jhipster.tech/) - Couchbase and Cassandra integration testing * [wescale](https://www.wescale.com) - Integration testing against HTTP service mocks and various data stores * [Marquez](https://marquezproject.github.io/marquez) - PostgreSQL integration testing From 2cfd34935b07480750a879362ab10e04c210365e Mon Sep 17 00:00:00 2001 From: sullis Date: Thu, 26 Dec 2019 05:27:09 -0800 Subject: [PATCH 0467/4969] GitHub Actions checkout v2 (#2212) --- .github/workflows/ci.yml | 3 +-- .github/workflows/gradle-release.yml | 4 ++-- .github/workflows/update-docs-version.yml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7013e66bea6..5618be1230d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: in-docker_test: runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Build with Gradle run: | docker run -i --rm \ @@ -18,4 +18,3 @@ jobs: -w "$PWD" \ openjdk:8-jdk-alpine \ ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' - diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml index 3034ce9cdfb..d35c0aa73f8 100644 --- a/.github/workflows/gradle-release.yml +++ b/.github/workflows/gradle-release.yml @@ -8,12 +8,12 @@ jobs: build: runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 - - name: Verify CI check status + - name: Verify CI check status run: .github/workflows/scripts/check_ci_status.sh $GITHUB_SHA - name: Release with Gradle run: ./gradlew -Pversion=${GITHUB_REF##*/} release --scan --no-daemon -i diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index ad8773db2db..7268f72f961 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -8,7 +8,7 @@ jobs: build: runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Checkout master run: git checkout master - name: Update latest_version property in mkdocs.yml From 13b3e6bc4294c7fa6dc2c897f59b2672dd6cfcdc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2019 22:33:21 +0900 Subject: [PATCH 0468/4969] Bump testng from 7.1.0 to 7.1.1 in /examples (#2200) Bumps [testng](https://github.com/cbeust/testng) from 7.1.0 to 7.1.1. - [Release notes](https://github.com/cbeust/testng/releases) - [Changelog](https://github.com/cbeust/testng/blob/master/CHANGES.txt) - [Commits](https://github.com/cbeust/testng/commits/7.1.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/redis-backed-cache-testng/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index cf22e89c528..efe713d5c0e 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' - testImplementation 'org.testng:testng:7.1.0' + testImplementation 'org.testng:testng:7.1.1' } test { From 4266fda1f35be31ca0a4a6101a2afae8fba09195 Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Fri, 27 Dec 2019 10:49:40 +0100 Subject: [PATCH 0469/4969] JDBC: Fix parsing empty connection parameters (#2207) --- .../main/java/org/testcontainers/jdbc/ConnectionUrl.java | 2 +- .../java/org/testcontainers/jdbc/ConnectionUrlTest.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java index 4c590474bf7..4f339b43fe5 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java @@ -228,7 +228,7 @@ public interface Patterns { Pattern TC_PARAM_MATCHING_PATTERN = Pattern.compile(TC_PARAM_NAME_PATTERN + "=([^\\?&]+)"); - Pattern QUERY_PARAM_MATCHING_PATTERN = Pattern.compile("([^\\?&=]+)=([^\\?&]+)"); + Pattern QUERY_PARAM_MATCHING_PATTERN = Pattern.compile("([^\\?&=]+)=([^\\?&]*)"); } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java index 53524eb32b2..312d5cf5146 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java @@ -49,6 +49,12 @@ public void testConnectionUrl2() { } + @Test + public void testEmptyQueryParameter() { + ConnectionUrl url = ConnectionUrl.newInstance("jdbc:tc:mysql://somehostname/databasename?key="); + assertEquals("'key' property value", "", url.getQueryParameters().get("key")); + } + @Test public void testTmpfsOption() { String urlString = "jdbc:tc:mysql://somehostname/databasename?TC_TMPFS=key:value,key1:value1"; From f8cd923403a0b7e9cfa9e021b5b0ea6b1ec8a687 Mon Sep 17 00:00:00 2001 From: "Roman S.A" Date: Fri, 27 Dec 2019 12:54:21 +0300 Subject: [PATCH 0470/4969] =?UTF-8?q?Mention=20`testcontainers-bom`=20in?= =?UTF-8?q?=20"Maven=20dependencies"=20section=20of=E2=80=A6=20(#2178)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Mention testcontainers-bom in the Maven dependencies section of the docs #2134 * Update docs/index.md Co-Authored-By: Richard North * Update docs/index.md Co-Authored-By: Richard North * Update docs/index.md Co-Authored-By: Richard North * Update docs/index.md Co-Authored-By: Richard North Co-authored-by: Richard North --- docs/index.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/index.md b/docs/index.md index f214bf0f73f..af2bf79f0c9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -46,6 +46,43 @@ testCompile "org.testcontainers:testcontainers:{{latest_version}}" You can also [check the latest version available on Maven Central](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.testcontainers%22). +### Managing versions for multiple Testcontainers dependencies + +To avoid specifying the version of each dependency, you can use a `BOM` or `Bill Of Materials`. + +Using Maven you can add the following to `dependencyManagement` section in your `pom.xml`: + +```xml tab='Maven' + + + + org.testcontainers + testcontainers-bom + {{latest_version}} + pom + import + + + +``` +and then use dependencies without specifying a version: + +```xml tab='Maven' + + org.testcontainers + mysql + test + +``` + +Using Gradle 5.0 or higher, you can add the following to the `dependencies` section in your `build.gradle`: + +```groovy tab='Gradle' +implementation platform('org.testcontainers:testcontainers-bom:{{latest_version}}') //import bom +testImplementation('org.testcontainers:mysql') //no version specified +``` + + [JitPack](jitpack_dependencies.md) builds are available for pre-release versions. !!! warning "Shaded dependencies" From 3d79c03aa793a89bb124b92982c54469ad384978 Mon Sep 17 00:00:00 2001 From: worldtiki Date: Fri, 27 Dec 2019 10:13:43 +0000 Subject: [PATCH 0471/4969] Add example for nginx module (#2027) --- docs/modules/nginx.md | 22 +++++++++ .../testcontainers/junit/SimpleNginxTest.java | 48 +++++++++++-------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/docs/modules/nginx.md b/docs/modules/nginx.md index 32d668e150a..d195b5451a2 100644 --- a/docs/modules/nginx.md +++ b/docs/modules/nginx.md @@ -1,5 +1,27 @@ # Nginx Module +Nginx is a web server, reverse proxy and mail proxy and http cache. + +## Usage example + +The following example shows how to start Nginx. + + +[Creating a Nginx container](../../modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java) inside_block:creatingContainer + + +How to add custom content to the Nginx server. + + +[Creating the static content to serve](../../modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java) inside_block:addCustomContent + + +And how to query the Nginx server for the custom content added. + + +[Creating the static content to serve](../../modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java) inside_block:getFromNginxServer + + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java index ad9026b6e4c..b41a0d8361e 100644 --- a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java +++ b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java @@ -8,52 +8,58 @@ import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import java.io.*; +import java.net.URL; import java.net.URLConnection; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.rnorth.visibleassertions.VisibleAssertions.info; - +import static org.hamcrest.CoreMatchers.containsString; +import static org.rnorth.visibleassertions.VisibleAssertions.*; /** * @author richardnorth */ public class SimpleNginxTest { - private static File contentFolder = new File(System.getProperty("user.home") + "/.tmp-test-container"); + private static String tmpDirectory = System.getProperty("user.home") + "/.tmp-test-container"; + // creatingContainer { @Rule public NginxContainer nginx = new NginxContainer<>() - .withCustomContent(contentFolder.toString()) + .withCustomContent(tmpDirectory) .waitingFor(new HttpWaitStrategy()); + // } @SuppressWarnings({"Duplicates", "ResultOfMethodCallIgnored"}) @BeforeClass - public static void setupContent() throws FileNotFoundException { + public static void setupContent() throws Exception { + // addCustomContent { + // Create a temporary dir + File contentFolder = new File(tmpDirectory); contentFolder.mkdir(); - contentFolder.setReadable(true, false); - contentFolder.setWritable(true, false); - contentFolder.setExecutable(true, false); - + contentFolder.deleteOnExit(); + // And "hello world" HTTP file File indexFile = new File(contentFolder, "index.html"); - indexFile.setReadable(true, false); - indexFile.setWritable(true, false); - indexFile.setExecutable(true, false); - + indexFile.deleteOnExit(); @Cleanup PrintStream printStream = new PrintStream(new FileOutputStream(indexFile)); - printStream.println("This worked"); + printStream.println("Hello World!"); + // } } @Test public void testSimple() throws Exception { + // getFromNginxServer { + URL baseUrl = nginx.getBaseUrl("http", 80); - info("Base URL is " + nginx.getBaseUrl("http", 80)); + assertThat("An HTTP GET from the Nginx server returns the index.html from the custom content directory", + responseFromNginx(baseUrl), + containsString("Hello World!") + ); + // } + } - URLConnection urlConnection = nginx.getBaseUrl("http", 80).openConnection(); + private static String responseFromNginx(URL baseUrl) throws IOException { + URLConnection urlConnection = baseUrl.openConnection(); @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - String line = reader.readLine(); - System.out.println(line); - - assertTrue("Using URLConnection, an HTTP GET from the nginx server returns the index.html from the custom content directory", line.contains("This worked")); + return reader.readLine(); } } From aa1c65b6efcc6d052fe71043d9985d69df70771f Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 2 Jan 2020 13:26:28 +0000 Subject: [PATCH 0472/4969] =?UTF-8?q?Remove=20stray=20'KB'=20suffix=20from?= =?UTF-8?q?=20docker=20build=20context=20size=20log=20mes=E2=80=A6=20(#221?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/testcontainers/images/builder/ImageFromDockerfile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 98d0dda5e5c..ded64439a64 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -123,7 +123,7 @@ public void onNext(BuildResponseItem item) { tarArchive.finish(); } - log.info("Transferred {} KB to Docker daemon", FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); + log.info("Transferred {} to Docker daemon", FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); if (bytesToDockerDaemon > FileUtils.ONE_MB * 50) // warn if >50MB sent to docker daemon log.warn("A large amount of data was sent to the Docker daemon ({}). Consider using a .dockerignore file for better performance.", FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); From f9646ec48f99327a48e27a89d51c13fef5f9343d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2020 15:54:07 +0000 Subject: [PATCH 0473/4969] Bump HikariCP from 3.4.1 to 3.4.2 in /modules/spock (#2236) Bumps [HikariCP](https://github.com/brettwooldridge/HikariCP) from 3.4.1 to 3.4.2. - [Release notes](https://github.com/brettwooldridge/HikariCP/releases) - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-3.4.1...HikariCP-3.4.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 2974784d466..465547f1d6e 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.1' + testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testRuntime 'org.postgresql:postgresql:42.2.9' From 46e95756e603df7054f0aec74e81c652a3c6a97e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2020 15:54:29 +0000 Subject: [PATCH 0474/4969] Bump HikariCP from 3.4.1 to 3.4.2 in /modules/junit-jupiter (#2235) Bumps [HikariCP](https://github.com/brettwooldridge/HikariCP) from 3.4.1 to 3.4.2. - [Release notes](https://github.com/brettwooldridge/HikariCP/releases) - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-3.4.1...HikariCP-3.4.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: Richard North --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 18cc5ddfe96..0ea792ec8b3 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.1' + testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'redis.clients:jedis:3.2.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testCompile ('org.mockito:mockito-core:3.2.4') { From 62ce00d167924cca453a8d989a224b2eca339d35 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2020 15:54:39 +0000 Subject: [PATCH 0475/4969] Bump mariadb-java-client from 2.5.2 to 2.5.3 in /modules/mariadb (#2233) Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.5.2 to 2.5.3. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.5.2...2.5.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 041b0a146da..fac747aa68e 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.2' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.3' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.30' From dab1a9481ec9ca43c298abd9de060e5ecad3e9ba Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2020 15:54:51 +0000 Subject: [PATCH 0476/4969] Bump okhttp from 3.14.4 to 3.14.5 in /examples (#2230) Bumps [okhttp](https://github.com/square/okhttp) from 3.14.4 to 3.14.5. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/docs/changelog_3x.md) - [Commits](https://github.com/square/okhttp/compare/parent-3.14.4...parent-3.14.5) Signed-off-by: dependabot-preview[bot] Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index dea159a89b5..3e603dec908 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:3.14.4' + implementation 'com.squareup.okhttp3:okhttp:3.14.5' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.9' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 6622578bed5e66bfb979b9bfeeb0e22321e21266 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Jan 2020 13:01:42 -0800 Subject: [PATCH 0477/4969] Move `execInContainer` and `copy*` to `ContainerState` (#2176) * Move `execInContainer` and `copy*` to `ContainerState` * fix backward compatibility * Fix javadoc --- .../testcontainers/containers/Container.java | 55 -------- .../containers/ContainerState.java | 129 +++++++++++++++++- .../containers/GenericContainer.java | 82 +---------- 3 files changed, 130 insertions(+), 136 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index ef27a95a463..631e2653ceb 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -420,61 +420,6 @@ default void followOutput(Consumer consumer, OutputFrame.OutputType @Deprecated Info fetchDockerDaemonInfo() throws IOException; - /** - * Run a command inside a running container, as though using "docker exec", and interpreting - * the output as UTF8. - *

- * @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, String...) - */ - ExecResult execInContainer(String... command) - throws UnsupportedOperationException, IOException, InterruptedException; - - /** - * Run a command inside a running container, as though using "docker exec". - *

- * @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, Charset, String...) - */ - ExecResult execInContainer(Charset outputCharset, String... command) - throws UnsupportedOperationException, IOException, InterruptedException; - - /** - * - * Copies a file or directory to the container. - * - * @param mountableFile file or directory which is copied into the container - * @param containerPath destination path inside the container - * @throws IOException if there's an issue communicating with Docker - * @throws InterruptedException if the thread waiting for the response is interrupted - */ - void copyFileToContainer(MountableFile mountableFile, String containerPath) throws IOException, InterruptedException; - - /** - * - * Copies a file to the container. - * - * @param transferable file which is copied into the container - * @param containerPath destination path inside the container - */ - void copyFileToContainer(Transferable transferable, String containerPath); - - /** - * Copies a file which resides inside the container to user defined directory - * - * @param containerPath path to file which is copied from container - * @param destinationPath destination path to which file is copied with file name - * @throws IOException if there's an issue communicating with Docker or receiving entry from TarArchiveInputStream - * @throws InterruptedException if the thread waiting for the response is interrupted - */ - void copyFileFromContainer(String containerPath, String destinationPath) throws IOException, InterruptedException; - - /** - * Streams a file which resides inside the container - * - * @param containerPath path to file which is copied from container - * @param function function that takes InputStream of the copied file - */ - T copyFileFromContainer(String containerPath, ThrowingFunction function); - List getPortBindings(); List getExtraHosts(); diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 2066fe72157..043bae1d52f 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -1,15 +1,33 @@ package org.testcontainers.containers; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Ports; import com.google.common.base.Preconditions; +import lombok.SneakyThrows; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.compress.utils.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.LogUtils; +import org.testcontainers.utility.MountableFile; +import org.testcontainers.utility.ThrowingFunction; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -170,10 +188,119 @@ default String getLogs(OutputFrame.OutputType... types) { /** * @return the id of the container */ - String getContainerId(); + default String getContainerId() { + return getContainerInfo().getId(); + } /** * @return the container info */ InspectContainerResponse getContainerInfo(); + + /** + * Run a command inside a running container, as though using "docker exec", and interpreting + * the output as UTF8. + *

+ * @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, String...) + */ + default Container.ExecResult execInContainer(String... command) throws UnsupportedOperationException, IOException, InterruptedException { + return execInContainer(StandardCharsets.UTF_8, command); + } + + /** + * Run a command inside a running container, as though using "docker exec". + *

+ * @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, Charset, String...) + */ + default Container.ExecResult execInContainer(Charset outputCharset, String... command) throws UnsupportedOperationException, IOException, InterruptedException { + return ExecInContainerPattern.execInContainer(getContainerInfo(), outputCharset, command); + } + + /** + * + * Copies a file or directory to the container. + * + * @param mountableFile file or directory which is copied into the container + * @param containerPath destination path inside the container + */ + default void copyFileToContainer(MountableFile mountableFile, String containerPath) { + File sourceFile = new File(mountableFile.getResolvedPath()); + + if (containerPath.endsWith("/") && sourceFile.isFile()) { + final Logger logger = LoggerFactory.getLogger(GenericContainer.class); + logger.warn("folder-like containerPath in copyFileToContainer is deprecated, please explicitly specify a file path"); + copyFileToContainer((Transferable) mountableFile, containerPath + sourceFile.getName()); + } else { + copyFileToContainer((Transferable) mountableFile, containerPath); + } + } + + /** + * + * Copies a file to the container. + * + * @param transferable file which is copied into the container + * @param containerPath destination path inside the container + */ + @SneakyThrows(IOException.class) + default void copyFileToContainer(Transferable transferable, String containerPath) { + if (!isCreated()) { + throw new IllegalStateException("copyFileToContainer can only be used with created / running container"); + } + + try ( + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(byteArrayOutputStream) + ) { + tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); + + transferable.transferTo(tarArchive, containerPath); + tarArchive.finish(); + + DockerClientFactory.instance().client() + .copyArchiveToContainerCmd(getContainerId()) + .withTarInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) + .withRemotePath("/") + .exec(); + } + } + + /** + * Copies a file which resides inside the container to user defined directory + * + * @param containerPath path to file which is copied from container + * @param destinationPath destination path to which file is copied with file name + * @throws IOException if there's an issue communicating with Docker or receiving entry from TarArchiveInputStream + * @throws InterruptedException if the thread waiting for the response is interrupted + */ + default void copyFileFromContainer(String containerPath, String destinationPath) throws IOException, InterruptedException { + copyFileFromContainer(containerPath, inputStream -> { + try(FileOutputStream output = new FileOutputStream(destinationPath)) { + IOUtils.copy(inputStream, output); + return null; + } + }); + } + + /** + * Streams a file which resides inside the container + * + * @param containerPath path to file which is copied from container + * @param function function that takes InputStream of the copied file + */ + @SneakyThrows + default T copyFileFromContainer(String containerPath, ThrowingFunction function) { + if (!isCreated()) { + throw new IllegalStateException("copyFileFromContainer can only be used when the Container is created."); + } + + try ( + DockerClient dockerClient = DockerClientFactory.instance().client(); + InputStream inputStream = dockerClient.copyArchiveFromContainerCmd(getContainerId(), containerPath).exec(); + TarArchiveInputStream tarInputStream = new TarArchiveInputStream(inputStream) + ) { + tarInputStream.getNextTarEntry(); + return function.apply(tarInputStream); + } + } } diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 0062612c10d..ee458339d0a 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1324,87 +1324,9 @@ public synchronized Info fetchDockerDaemonInfo() throws IOException { * {@inheritDoc} */ @Override - public ExecResult execInContainer(String... command) - throws UnsupportedOperationException, IOException, InterruptedException { - - return execInContainer(UTF8, command); - } - - /** - * {@inheritDoc} - */ - @Override - public void copyFileToContainer(MountableFile mountableFile, String containerPath) { - File sourceFile = new File(mountableFile.getResolvedPath()); - - if (containerPath.endsWith("/") && sourceFile.isFile()) { - logger().warn("folder-like containerPath in copyFileToContainer is deprecated, please explicitly specify a file path"); - copyFileToContainer((Transferable) mountableFile, containerPath + sourceFile.getName()); - } else { - copyFileToContainer((Transferable) mountableFile, containerPath); - } - } - - @Override - @SneakyThrows(IOException.class) - public void copyFileToContainer(Transferable transferable, String containerPath) { - if (!isCreated()) { - throw new IllegalStateException("copyFileToContainer can only be used with created / running container"); - } - - try ( - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(byteArrayOutputStream) - ) { - tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); - - transferable.transferTo(tarArchive, containerPath); - tarArchive.finish(); - - dockerClient - .copyArchiveToContainerCmd(containerId) - .withTarInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) - .withRemotePath("/") - .exec(); - } - } - - /** - * {@inheritDoc} - */ - @Override + @SneakyThrows public void copyFileFromContainer(String containerPath, String destinationPath) { - copyFileFromContainer(containerPath, inputStream -> { - try(FileOutputStream output = new FileOutputStream(destinationPath)) { - IOUtils.copy(inputStream, output); - return null; - } - }); - } - - @Override - @SneakyThrows(Exception.class) - public T copyFileFromContainer(String containerPath, ThrowingFunction consumer) { - if (!isCreated()) { - throw new IllegalStateException("copyFileFromContainer can only be used when the Container is created."); - } - - try ( - InputStream inputStream = dockerClient.copyArchiveFromContainerCmd(containerId, containerPath).exec(); - TarArchiveInputStream tarInputStream = new TarArchiveInputStream(inputStream) - ) { - tarInputStream.getNextTarEntry(); - return consumer.apply(tarInputStream); - } - } - - /** - * {@inheritDoc} - */ - @Override - public ExecResult execInContainer(Charset outputCharset, String... command) - throws UnsupportedOperationException, IOException, InterruptedException { - return ExecInContainerPattern.execInContainer(getContainerInfo(), outputCharset, command); + Container.super.copyFileFromContainer(containerPath, destinationPath); } /** From 728261c7c9cdb5c02d736f31461d11717f97618a Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 13 Jan 2020 20:02:12 +0000 Subject: [PATCH 0478/4969] Bump flaky annotation review dates (#2248) --- .../couchbase/BaseCouchbaseContainerTest.java | 6 +++--- .../org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java | 2 +- .../java/org/testcontainers/containers/ToxiproxyTest.java | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java index 6deba2c4c5e..ef2f0925c48 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java @@ -47,7 +47,7 @@ protected void failed(Throwable e, Description description) { }); @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2020-03-01") public void shouldInsertDocument() { RawJsonDocument expected = RawJsonDocument.create(ID, DOCUMENT); getBucket().upsert(expected); @@ -56,7 +56,7 @@ public void shouldInsertDocument() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2020-03-01") public void shouldExecuteN1ql() { getBucket().query(N1qlQuery.simple("INSERT INTO " + TEST_BUCKET + " (KEY, VALUE) VALUES ('" + ID + "', " + DOCUMENT + ")")); @@ -69,7 +69,7 @@ public void shouldExecuteN1ql() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2019-12-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2020-03-01") public void shouldCreateView() { View view = DefaultView.create(VIEW_NAME, VIEW_FUNCTION); DesignDocument document = DesignDocument.create(VIEW_NAME, Lists.newArrayList(view)); diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java index fb9794e29a8..07a17f68ade 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -20,7 +20,7 @@ public class DatabaseDriverTmpfsTest { public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1687", reviewDate = "2019-12-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1687", reviewDate = "2020-03-01") public void tmpfs() throws IOException, InterruptedException, SQLException { final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw"; try (Connection ignored = DriverManager.getConnection(jdbcUrl)) { diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index 840165fb8ee..c96e2efd19e 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -45,7 +45,7 @@ public void testDirect() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-12-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2020-03-01") public void testLatencyViaProxy() throws IOException { // obtainProxyObject { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); @@ -72,7 +72,7 @@ public void testLatencyViaProxy() throws IOException { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-12-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2020-03-01") public void testConnectionCut() { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); final Jedis jedis = new Jedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); @@ -97,7 +97,7 @@ public void testConnectionCut() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2019-12-01") + @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2020-03-01") public void testMultipleProxiesCanBeCreated() { try (GenericContainer secondRedis = new GenericContainer("redis:5.0.4") .withExposedPorts(6379) From d4f6d13b4b730cbb24a82939cd6d3472e818e6d2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2020 10:15:54 +0000 Subject: [PATCH 0479/4969] Bump pulsar-client from 2.4.1 to 2.5.0 in /modules/pulsar (#2252) Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.4.1 to 2.5.0. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.4.1...v2.5.0) Signed-off-by: dependabot-preview[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 046debc2b9b..81be68579d7 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.4.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.14.0' } From 5b48d4dbb3092a4919bcea9aa2aa034b08dbfa91 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2020 10:16:04 +0000 Subject: [PATCH 0480/4969] Bump mysql-connector-java from 8.0.18 to 8.0.19 in /modules/spock (#2242) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.18 to 8.0.19. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot-preview[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 465547f1d6e..d964e67c5cf 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -14,5 +14,5 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.10' testRuntime 'org.postgresql:postgresql:42.2.9' - testRuntime 'mysql:mysql-connector-java:8.0.18' + testRuntime 'mysql:mysql-connector-java:8.0.19' } From 2be3b44a348646d34f0e8737e825b7f32bac9220 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2020 10:16:22 +0000 Subject: [PATCH 0481/4969] Bump mysql-connector-java from 8.0.18 to 8.0.19 in /modules/mysql (#2241) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.18 to 8.0.19. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: Richard North --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 0b70ea3af6a..43867df521a 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { compile project(':jdbc') - testCompile 'mysql:mysql-connector-java:8.0.18' + testCompile 'mysql:mysql-connector-java:8.0.19' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.30' testCompile 'commons-dbutils:commons-dbutils:1.7' From dd5fe11e6bdae0657cc6a2551e3890f64973ce3c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2020 10:17:28 +0000 Subject: [PATCH 0482/4969] Bump junit from 4.12 to 4.13 in /examples (#2220) Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/master/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13) Signed-off-by: dependabot-preview[bot] --- examples/mongodb-container/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 11c5f2bbe24..d3b85856b8a 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -8,5 +8,5 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index b665b9a24a4..9dea8531b5e 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -12,6 +12,6 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' testImplementation 'ch.qos.logback:logback-classic:1.2.3' } From 9f748ab1fd1a63e5ad1509e0681be6cfe2210e2c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2020 10:17:44 +0000 Subject: [PATCH 0483/4969] =?UTF-8?q?Bump=20mysql-connector-java=20from=20?= =?UTF-8?q?8.0.18=20to=208.0.19=20in=20/modules/jun=E2=80=A6=20(#2244)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.18 to 8.0.19. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot-preview[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 0ea792ec8b3..a2698da90d9 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -14,7 +14,7 @@ dependencies { } testRuntime 'org.postgresql:postgresql:42.2.9' - testRuntime 'mysql:mysql-connector-java:8.0.18' + testRuntime 'mysql:mysql-connector-java:8.0.19' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.2' } From 4671f3a007ab38e16fa1c3b0dd80ad899fafc2aa Mon Sep 17 00:00:00 2001 From: Michael DePouw Date: Sat, 18 Jan 2020 05:23:35 -0500 Subject: [PATCH 0484/4969] fix anchor link for link to feature description (#2257) --- docs/supported_docker_environment/windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/windows.md b/docs/supported_docker_environment/windows.md index 122965ef133..b35ee1aa2ee 100644 --- a/docs/supported_docker_environment/windows.md +++ b/docs/supported_docker_environment/windows.md @@ -17,7 +17,7 @@ If you wish to use Testcontainers on Windows, please confirm that it works corre effort. ### MySQL containers -* MySQL server prevents custom configuration file (ini-script) from being loaded due to security measures ([link to feature description](../modules/databases/index.md#using-an-init-script)) +* MySQL server prevents custom configuration file (ini-script) from being loaded due to security measures ([link to feature description](../modules/databases/index.md#using-an-init-script-from-a-file)) ### Windows Container on Windows (WCOW) From 23e9718a56eeac3ca2ec87c8a2525fa8e4bf76df Mon Sep 17 00:00:00 2001 From: Per Lundberg Date: Sat, 18 Jan 2020 12:24:44 +0200 Subject: [PATCH 0485/4969] =?UTF-8?q?Fix=20/proc/net/tcp*=20check=20in=20I?= =?UTF-8?q?nternalCommandPortListeningCheck=20t=E2=80=A6=20(#2195)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wait/internal/InternalCommandPortListeningCheck.java | 2 +- .../wait/internal/InternalCommandPortListeningCheckTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index 43ed94bc84d..2013ddc4d9c 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -29,7 +29,7 @@ public Boolean call() { for (int internalPort : internalPorts) { command += " && "; command += " ("; - command += format("cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%x", internalPort); + command += format("cat /proc/net/tcp* | awk '{print $2}' | grep -i :%x", internalPort); command += " || "; command += format("nc -vz -w 1 localhost %d", internalPort); command += " || "; diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java index 71a14c3c79e..bee4f0a231a 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java @@ -11,8 +11,8 @@ public class InternalCommandPortListeningCheckTest { - // Linking a custom configuration into the container so that nginx is listening on port 8080. This is necessary to proof - // that the command formatting uses the correct casing for hexadecimal numberd (i.e. 1F90 and not 1f90). + // Linking a custom configuration into the container so that nginx is listening on port 8080. This is necessary to prove + // that the command formatting uses the correct casing for hexadecimal numbers (i.e. 1F90 and not 1f90). @Rule public GenericContainer nginx = new GenericContainer<>("nginx:1.9.4") .withClasspathResourceMapping("nginx_on_8080.conf", "/etc/nginx/conf.d/default.conf", BindMode.READ_ONLY); From 7143939ed97df0d14b0d44e99bdfa7561a2dd1cb Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Sat, 18 Jan 2020 11:33:05 +0100 Subject: [PATCH 0486/4969] Accept List in deepStart (#2221) --- .../main/java/org/testcontainers/lifecycle/Startables.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startables.java b/core/src/main/java/org/testcontainers/lifecycle/Startables.java index 6cf57cc6f6e..b20c5c91b54 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/Startables.java +++ b/core/src/main/java/org/testcontainers/lifecycle/Startables.java @@ -27,7 +27,7 @@ public Thread newThread(Runnable r) { /** * @see #deepStart(Stream) */ - public CompletableFuture deepStart(Collection startables) { + public CompletableFuture deepStart(Collection startables) { return deepStart(startables.stream()); } @@ -49,7 +49,7 @@ public CompletableFuture deepStart(Collection startables) { * @param startables a {@link Stream} of {@link Startable}s to start and scan for transitive dependencies. * @return a {@link CompletableFuture} that resolves once all {@link Startable}s have started. */ - public CompletableFuture deepStart(Stream startables) { + public CompletableFuture deepStart(Stream startables) { return deepStart(new HashMap<>(), startables); } @@ -58,7 +58,7 @@ public CompletableFuture deepStart(Stream startables) { * @param started an intermediate storage for already started {@link Startable}s to prevent multiple starts. * @param startables a {@link Stream} of {@link Startable}s to start and scan for transitive dependencies. */ - private CompletableFuture deepStart(Map> started, Stream startables) { + private CompletableFuture deepStart(Map> started, Stream startables) { CompletableFuture[] futures = startables .sequential() .map(it -> { From fb869c06db062abc86b4bd88400d9b2ccfb2bb18 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 19 Jan 2020 13:04:13 +0000 Subject: [PATCH 0487/4969] Prevent duplicate attempts to start Ryuk container (#2245) Prevent duplicate attempts to start Ryuk container If for example, checks fail once but the Docker client is otherwise initialized, an error would occur due to an attempt to start a Ryuk container twice with the same name. This changed is aimed at avoiding that situation. Additionally, if checks fail once they should fail on every subsequent attempt to start a client. Therefore, we cache the failure and rethrow it. Co-authored-by: Sergei Egorov --- .../testcontainers/DockerClientFactory.java | 99 +++++++++++-------- .../DockerClientFactoryTest.java | 36 +++++++ .../MockTestcontainersConfigurationRule.java | 3 + 3 files changed, 96 insertions(+), 42 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 0ca7d41a209..2edcdf38e24 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -17,9 +17,6 @@ import lombok.SneakyThrows; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; @@ -68,12 +65,16 @@ public class DockerClientFactory { @VisibleForTesting DockerClient dockerClient; + @VisibleForTesting + RuntimeException cachedChecksFailure; + private String activeApiVersion; private String activeExecutionDriver; @Getter(lazy = true) private final boolean fileMountingSupported = checkMountableFile(); + static { System.setProperty("org.testcontainers.shaded.io.netty.packagePrefix", "org.testcontainers.shaded."); } @@ -124,6 +125,12 @@ public DockerClient client() { return dockerClient; } + // fail-fast if checks have failed previously + if (cachedChecksFailure != null) { + log.debug("There is a cached checks failure - throwing", cachedChecksFailure); + throw cachedChecksFailure; + } + final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); String hostIpAddress = strategy.getDockerHostIpAddress(); @@ -140,33 +147,47 @@ public DockerClient client() { " Operating System: " + dockerInfo.getOperatingSystem() + "\n" + " Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB"); - String ryukContainerId = null; + final String ryukContainerId; + boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); if (useRyuk) { + log.debug("Ryuk is enabled"); ryukContainerId = ResourceReaper.start(hostIpAddress, client); log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit"); + } else { + log.debug("Ryuk is disabled"); + ryukContainerId = null; } boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks(); if (checksEnabled) { - VisibleAssertions.info("Checking the system..."); - checkDockerVersion(version.getVersion()); - if (ryukContainerId != null) { - checkDiskSpace(client, ryukContainerId); - } else { - runInsideDocker( - client, - createContainerCmd -> { - createContainerCmd.withName("testcontainers-checks-" + SESSION_ID); - createContainerCmd.getHostConfig().withAutoRemove(true); - createContainerCmd.withCmd("tail", "-f", "/dev/null"); - }, - (__, containerId) -> { - checkDiskSpace(client, containerId); - return ""; - } - ); + log.debug("Checks are enabled"); + + try { + log.info("Checking the system..."); + checkDockerVersion(version.getVersion()); + if (ryukContainerId != null) { + checkDiskSpace(client, ryukContainerId); + } else { + runInsideDocker( + client, + createContainerCmd -> { + createContainerCmd.withName("testcontainers-checks-" + SESSION_ID); + createContainerCmd.getHostConfig().withAutoRemove(true); + createContainerCmd.withCmd("tail", "-f", "/dev/null"); + }, + (__, containerId) -> { + checkDiskSpace(client, containerId); + return ""; + } + ); + } + } catch (RuntimeException e) { + cachedChecksFailure = e; + throw e; } + } else { + log.debug("Checks are disabled"); } dockerClient = client; @@ -174,17 +195,8 @@ public DockerClient client() { } private void checkDockerVersion(String dockerVersion) { - VisibleAssertions.assertThat("Docker version", dockerVersion, new BaseMatcher() { - @Override - public boolean matches(Object o) { - return new ComparableVersion(o.toString()).compareTo(new ComparableVersion("1.6.0")) >= 0; - } - - @Override - public void describeTo(Description description) { - description.appendText("should be at least 1.6.0"); - } - }); + boolean versionIsSufficient = new ComparableVersion(dockerVersion).compareTo(new ComparableVersion("1.6.0")) >= 0; + check("Docker server version should be at least 1.6.0", versionIsSufficient); } private void checkDiskSpace(DockerClient dockerClient, String id) { @@ -201,12 +213,21 @@ private void checkDiskSpace(DockerClient dockerClient, String id) { DiskSpaceUsage df = parseAvailableDiskSpace(outputStream.toString()); - VisibleAssertions.assertTrue( + check( "Docker environment should have more than 2GB free disk space", df.availableMB.map(it -> it >= 2048).orElse(true) ); } + private void check(String message, boolean isSuccessful) { + if (isSuccessful) { + log.info("✔︎ {}", message); + } else { + log.error("❌ {}", message); + throw new IllegalStateException("Check failed: " + message); + } + } + private boolean checkMountableFile() { DockerClient dockerClient = client(); @@ -267,8 +288,8 @@ private T runInsideDocker(DockerClient client, Consumer } finally { try { client.removeContainerCmd(id).withRemoveVolumes(true).withForce(true).exec(); - } catch (NotFoundException | InternalServerErrorException ignored) { - log.debug("", ignored); + } catch (NotFoundException | InternalServerErrorException e) { + log.debug("Swallowed exception while removing container", e); } } } @@ -286,7 +307,7 @@ DiskSpaceUsage parseAvailableDiskSpace(String dfOutput) { for (String line : lines) { String[] fields = line.split("\\s+"); if (fields.length > 5 && fields[5].equals("/")) { - long availableKB = Long.valueOf(fields[3]); + long availableKB = Long.parseLong(fields[3]); df.availableMB = Optional.of(availableKB / 1024L); df.usedPercent = Optional.of(Integer.valueOf(fields[4].replace("%", ""))); break; @@ -318,10 +339,4 @@ public String getActiveExecutionDriver() { public boolean isUsing(Class providerStrategyClass) { return strategy != null && providerStrategyClass.isAssignableFrom(this.strategy.getClass()); } - - private static class NotEnoughDiskSpaceException extends RuntimeException { - NotEnoughDiskSpaceException(String message) { - super(message); - } - } } diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index 19a591be919..60fd69e9fd3 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -1,19 +1,28 @@ package org.testcontainers; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.NotFoundException; +import org.junit.Rule; import org.junit.Test; +import org.mockito.Mockito; import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory.DiskSpaceUsage; import org.testcontainers.dockerclient.LogToStringContainerCallback; +import org.testcontainers.utility.MockTestcontainersConfigurationRule; import org.testcontainers.utility.TestcontainersConfiguration; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Test for {@link DockerClientFactory}. */ public class DockerClientFactoryTest { + @Rule + public MockTestcontainersConfigurationRule configurationMock = new MockTestcontainersConfigurationRule(); + @Test public void runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally() { @@ -52,4 +61,31 @@ public void dockerHostIpAddress() { instance.strategy = null; assertThat(instance.dockerHostIpAddress()).isNotNull(); } + + @Test + public void failedChecksFailFast() { + Mockito.doReturn(false).when(TestcontainersConfiguration.getInstance()).isDisableChecks(); + + // Make sure that Ryuk is started + assertThat(DockerClientFactory.instance().client()).isNotNull(); + + DockerClientFactory instance = new DockerClientFactory(); + DockerClient dockerClient = instance.dockerClient; + assertThat(instance.cachedChecksFailure).isNull(); + try { + // Remove cached client to force the initialization logic + instance.dockerClient = null; + + // Ryuk should fail to start twice due to the name conflict (equal to the session id) + assertThatThrownBy(instance::client).isInstanceOf(DockerException.class); + + RuntimeException failure = new IllegalStateException("Boom!"); + instance.cachedChecksFailure = failure; + // Fail fast + assertThatThrownBy(instance::client).isEqualTo(failure); + } finally { + instance.dockerClient = dockerClient; + instance.cachedChecksFailure = null; + } + } } diff --git a/core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java b/core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java index 4d156fd752e..ba467f13897 100644 --- a/core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java +++ b/core/src/test/java/org/testcontainers/utility/MockTestcontainersConfigurationRule.java @@ -23,6 +23,9 @@ public Statement apply(@NotNull Statement base, @NotNull Description description @Override public void evaluate() throws Throwable { TestcontainersConfiguration previous = REF.get(); + if (previous == null) { + previous = TestcontainersConfiguration.getInstance(); + } REF.set(Mockito.spy(previous)); try { From a1dac13a4a0a2ae9f4acd97a7e9a246093ead5f3 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 19 Jan 2020 14:25:37 +0000 Subject: [PATCH 0488/4969] =?UTF-8?q?Replace=20unicode=20characters=20in?= =?UTF-8?q?=20strings=20with=20unicode=20escape=20seque=E2=80=A6=20(#2261)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/testcontainers/DockerClientFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 2edcdf38e24..8d9da8825d2 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -221,9 +221,9 @@ private void checkDiskSpace(DockerClient dockerClient, String id) { private void check(String message, boolean isSuccessful) { if (isSuccessful) { - log.info("✔︎ {}", message); + log.info("\u2714︎ {}", message); } else { - log.error("❌ {}", message); + log.error("\u274c {}", message); throw new IllegalStateException("Check failed: " + message); } } From ad703f0503634fa6a53a915b875e145fbb1757e3 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 19 Jan 2020 20:32:00 +0000 Subject: [PATCH 0489/4969] Allow bintray upload to overwrite existing publications So that a re-run of a partially failed publication is permitted --- gradle/bintray.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle/bintray.gradle b/gradle/bintray.gradle index 6990393401e..5ddfefd8e49 100644 --- a/gradle/bintray.gradle +++ b/gradle/bintray.gradle @@ -12,6 +12,7 @@ bintray { name = 'testcontainers' publish = true + override = true version { name = project.version From 92a0d8c2248e96fa589e40fbb26847744bf37ca5 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 22 Jan 2020 21:22:48 +0000 Subject: [PATCH 0490/4969] Restore Travis Release automation (#2279) * Restore Travis Release automation Temporary, for duration of [this apparent issue](https://github.community/t5/GitHub-Actions/Read-timeout-issues-uploading-large-number-of-files-to-Bintray/m-p/42760#M5104) * Remove gradle release script temporarily * Empty commit to trigger build (Travis webhook was reinstated) --- .github/workflows/gradle-release.yml | 22 ---------------------- .travis.yml | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 22 deletions(-) delete mode 100644 .github/workflows/gradle-release.yml create mode 100644 .travis.yml diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml deleted file mode 100644 index d35c0aa73f8..00000000000 --- a/.github/workflows/gradle-release.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Gradle Release - -on: - release: - types: [published] - -jobs: - build: - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - name: Verify CI check status - run: .github/workflows/scripts/check_ci_status.sh $GITHUB_SHA - - name: Release with Gradle - run: ./gradlew -Pversion=${GITHUB_REF##*/} release --scan --no-daemon -i - env: - BINTRAY_USER: ${{ secrets.BINTRAY_USER }} - BINTRAY_API_KEY: ${{ secrets.BINTRAY_API_KEY }} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..daf52bf1aa5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,26 @@ +if: branch = master AND tag is present + +language: java +jdk: + - openjdk8 + +sudo: required +services: + - docker + +jobs: + include: + - stage: before_deploy + script: .github/workflows/scripts/check_ci_status.sh $TRAVIS_COMMIT + + - stage: deploy + sudo: false + services: [] + install: skip + script: skip + deploy: + provider: script + script: ./gradlew -Pversion=$TRAVIS_TAG release --scan --no-daemon -i + on: + tags: true + branch: master From 97d2bf1a305a9b2ae701cfe645254327be2657b0 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 22 Jan 2020 21:55:08 +0000 Subject: [PATCH 0491/4969] Simplify conditional travis execution --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index daf52bf1aa5..d05af36ac15 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -if: branch = master AND tag is present +if: tag is present language: java jdk: From 2a56996fe688bdd191299847a9286a5faa66830e Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 22 Jan 2020 22:02:44 +0000 Subject: [PATCH 0492/4969] Remove CI status check --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d05af36ac15..ec7a5d343d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,6 @@ services: jobs: include: - - stage: before_deploy - script: .github/workflows/scripts/check_ci_status.sh $TRAVIS_COMMIT - stage: deploy sudo: false From 63f60423fa31fbd3b1d7f17221f17f5d2b6daf33 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:22:51 +0000 Subject: [PATCH 0493/4969] Bump mongo-java-driver from 3.12.0 to 3.12.1 in /core (#2264) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.0 to 3.12.1. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.0...r3.12.1) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 2d76c38c0de..d7d9c581c1f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,7 +108,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.2.0' testCompile 'com.rabbitmq:amqp-client:5.8.0' - testCompile 'org.mongodb:mongo-java-driver:3.12.0' + testCompile 'org.mongodb:mongo-java-driver:3.12.1' testCompile ('org.mockito:mockito-core:3.2.4') { exclude(module: 'hamcrest-core') } From 1e645e129d17eed31d1989aee4099f7b8b8f82af Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:23:37 +0000 Subject: [PATCH 0494/4969] Bump org.springframework.boot in /examples (#2273) Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.2.2.RELEASE to 2.2.4.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.2.RELEASE...v2.2.4.RELEASE) Signed-off-by: dependabot-preview[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 5b6d71934b9..db570bf67ac 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.2.RELEASE' + id 'org.springframework.boot' version '2.2.4.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index bea11bf0909..e74e04a95e5 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.2.RELEASE' + id 'org.springframework.boot' version '2.2.4.RELEASE' } apply plugin: 'io.spring.dependency-management' From 8a2b77cf5d7e6e7fdf6073eb93aadf2c06c1e9ce Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:23:51 +0000 Subject: [PATCH 0495/4969] Bump okhttp from 3.14.5 to 3.14.6 in /examples (#2268) Bumps [okhttp](https://github.com/square/okhttp) from 3.14.5 to 3.14.6. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/docs/changelog_3x.md) - [Commits](https://github.com/square/okhttp/compare/parent-3.14.5...parent-3.14.6) Signed-off-by: dependabot-preview[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 3e603dec908..f1977ea2c0b 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:3.14.5' + implementation 'com.squareup.okhttp3:okhttp:3.14.6' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.9' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 9b27f6bb52ed55a5a14552dfa04f71ed41c7a5fc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:24:08 +0000 Subject: [PATCH 0496/4969] Bump rest-assured from 4.1.2 to 4.2.0 in /modules/vault (#2266) Bumps [rest-assured](https://github.com/jayway/rest-assured) from 4.1.2 to 4.2.0. - [Release notes](https://github.com/jayway/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/jayway/rest-assured/compare/rest-assured-4.1.2...rest-assured-4.2.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: Richard North --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 0a68c9310e0..ac72d306a5c 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { compile project(':testcontainers') testCompile 'com.bettercloud:vault-java-driver:5.1.0' - testCompile 'io.rest-assured:rest-assured:4.1.2' + testCompile 'io.rest-assured:rest-assured:4.2.0' testCompile 'org.assertj:assertj-core:3.14.0' } From a9006ae80e61f78bcadd970cdba9117727536b2d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:24:19 +0000 Subject: [PATCH 0497/4969] Bump httpclient from 4.5.10 to 4.5.11 in /modules/junit-jupiter (#2265) Bumps httpclient from 4.5.10 to 4.5.11. Signed-off-by: dependabot-preview[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index a2698da90d9..7b29e36b4dd 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,7 +8,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'redis.clients:jedis:3.2.0' - testCompile 'org.apache.httpcomponents:httpclient:4.5.10' + testCompile 'org.apache.httpcomponents:httpclient:4.5.11' testCompile ('org.mockito:mockito-core:3.2.4') { exclude(module: 'hamcrest-core') } From fa1f8ce05365ac0c6cd4893dc476c5b43279b607 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:24:28 +0000 Subject: [PATCH 0498/4969] Bump httpclient from 4.5.10 to 4.5.11 in /modules/spock (#2263) Bumps httpclient from 4.5.10 to 4.5.11. Signed-off-by: dependabot-preview[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index d964e67c5cf..f26858947ce 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.2' - testCompile 'org.apache.httpcomponents:httpclient:4.5.10' + testCompile 'org.apache.httpcomponents:httpclient:4.5.11' testRuntime 'org.postgresql:postgresql:42.2.9' testRuntime 'mysql:mysql-connector-java:8.0.19' From bd148a9291e9e840fe5ed2c3f8ae8de2490eff8f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:24:36 +0000 Subject: [PATCH 0499/4969] Bump elasticsearch-rest-client in /modules/elasticsearch (#2277) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.5.1 to 7.5.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.5.1...v7.5.2) Signed-off-by: dependabot-preview[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 2201efff48a..41d5b0f27ab 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.5.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.5.2" testCompile "org.elasticsearch.client:transport:6.7.1" } From 3b83ce9017e58255fb3087e5f6fde31db0bb9ba8 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 24 Jan 2020 09:57:53 +0000 Subject: [PATCH 0500/4969] Fix CI Docker Compose test failure (#2284) ``` org.testcontainers.junit.DockerComposeContainerWithBuildTest > performTest[removeMode = ALL] FAILED java.lang.RuntimeException: java.lang.AssertionError: the pulled image is present after running: 'true' does not equal expected 'false' at org.rnorth.ducttape.timeouts.Timeouts.callFuture(Timeouts.java:68) at org.rnorth.ducttape.timeouts.Timeouts.getWithTimeout(Timeouts.java:43) at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:40) at org.testcontainers.junit.DockerComposeContainerWithBuildTest.performTest(DockerComposeContainerWithBuildTest.java:72) Caused by: java.lang.AssertionError: the pulled image is present after running: 'true' does not equal expected 'false' at org.rnorth.visibleassertions.VisibleAssertions.fail(VisibleAssertions.java:440) at org.rnorth.visibleassertions.VisibleAssertions.assertEquals(VisibleAssertions.java:174) at org.testcontainers.junit.DockerComposeContainerWithBuildTest.lambda$performTest$1(DockerComposeContainerWithBuildTest.java:74) ``` Hypothesis: docker-compose cannot remove the `redis` (latest) image because there is some other running container that relies on that image. This may be a CI-specific problem depending on the Azure Pipelines Docker setup. To work around (without publishing our own single-use image): use an old version of the Redis image that is unlikely to be in use by concurrent builds. --- core/src/test/resources/compose-build-test/Dockerfile | 2 +- core/src/test/resources/compose-build-test/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/resources/compose-build-test/Dockerfile b/core/src/test/resources/compose-build-test/Dockerfile index 521e2d23b80..f5df49b0152 100644 --- a/core/src/test/resources/compose-build-test/Dockerfile +++ b/core/src/test/resources/compose-build-test/Dockerfile @@ -1,3 +1,3 @@ -FROM redis +FROM redis:2.6.17 CMD ["redis-server"] diff --git a/core/src/test/resources/compose-build-test/docker-compose.yml b/core/src/test/resources/compose-build-test/docker-compose.yml index 333b2fa46f1..5b9f3e2c21b 100644 --- a/core/src/test/resources/compose-build-test/docker-compose.yml +++ b/core/src/test/resources/compose-build-test/docker-compose.yml @@ -3,4 +3,4 @@ services: customredis: build: . normalredis: - image: redis:latest + image: redis:2.6.17 From 32bd7a449732dee460787d1a7b92aab3e5a26167 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 24 Jan 2020 19:31:53 +0000 Subject: [PATCH 0501/4969] Update docs version to match latest release --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index eaec3ae13a1..189bc3b6788 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,4 +84,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.12.3 + latest_version: 1.12.5 From 142e585b567f7bac6b9dc97418634362e7ff9d70 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 24 Jan 2020 20:36:51 +0100 Subject: [PATCH 0502/4969] Mention JDBC URL change in Spring Boot 2.3.0 (#2286) See https://github.com/spring-projects/spring-boot/pull/19044 --- docs/modules/databases/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index 2511502f650..32026953802 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -45,7 +45,7 @@ As long as you have Testcontainers and the appropriate JDBC driver on your class _N.B:_ * _TC needs to be on your application's classpath at runtime for this to work_ -* _For Spring Boot you need to specify the driver manually `spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver`_ +* _For Spring Boot (Before version `2.3.0`) you need to specify the driver manually `spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver`_ **Original URL**: `jdbc:mysql:5.7.22://localhost:3306/databasename` From a1b6641d6de0b1542421e79f2de6c42d08f26870 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:34:35 +0000 Subject: [PATCH 0503/4969] Bump assertj-core from 3.14.0 to 3.15.0 in /modules/database-commons (#2307) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.15.0) Signed-off-by: dependabot-preview[bot] --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index ea3e0b07360..d8738a6cb69 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.14.0' + testCompile 'org.assertj:assertj-core:3.15.0' } From 3854933cfe94eca9976a0e7086fb8bc066b39c0a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:34:57 +0000 Subject: [PATCH 0504/4969] Bump assertj-core from 3.14.0 to 3.15.0 in /modules/neo4j (#2306) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.15.0) Signed-off-by: dependabot-preview[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 00e1e36f8b7..9361824fdd6 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -30,5 +30,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.14.0' + testCompile 'org.assertj:assertj-core:3.15.0' } From 110d700950a7ac7f651d3ae2c4c3bed2d40ab5fa Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:35:38 +0000 Subject: [PATCH 0505/4969] Bump assertj-core from 3.14.0 to 3.15.0 in /modules/pulsar (#2305) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.15.0) Signed-off-by: dependabot-preview[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 81be68579d7..88d783fc221 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,5 +4,5 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.0' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.14.0' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.15.0' } From 3dbc728ac1ae757b497e338fdefa4633e6546ce8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:36:18 +0000 Subject: [PATCH 0506/4969] Bump assertj-core from 3.14.0 to 3.15.0 in /modules/vault (#2304) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.15.0) Signed-off-by: dependabot-preview[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index ac72d306a5c..1c8a4083b9c 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.2.0' - testCompile 'org.assertj:assertj-core:3.14.0' + testCompile 'org.assertj:assertj-core:3.15.0' } From bbc82dd14a9032909e7c1c4a4aaf3c3e499611c3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:36:43 +0000 Subject: [PATCH 0507/4969] Bump assertj-core from 3.14.0 to 3.15.0 in /modules/kafka (#2303) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.15.0) Signed-off-by: dependabot-preview[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index d064e46c1dc..3960cd96b69 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.4.0' - testCompile 'org.assertj:assertj-core:3.14.0' + testCompile 'org.assertj:assertj-core:3.15.0' testCompile 'com.google.guava:guava:23.0' } From 8f3f4af5b1219d22b4b3367e020d41984b2bf3f1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:36:51 +0000 Subject: [PATCH 0508/4969] Bump assertj-core from 3.14.0 to 3.15.0 in /core (#2308) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.15.0) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d7d9c581c1f..25aaa396a60 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -115,7 +115,7 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.14.0' + testCompile 'org.assertj:assertj-core:3.15.0' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" From 7a4d4c668ffefa642e80750b7e53eba069e99af8 Mon Sep 17 00:00:00 2001 From: dark Date: Thu, 30 Jan 2020 02:37:42 +0900 Subject: [PATCH 0509/4969] Add junit-jupiter dependency in junit 5 quickstart docs (#2301) Co-authored-by: dark --- docs/quickstart/junit_5_quickstart.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/quickstart/junit_5_quickstart.md b/docs/quickstart/junit_5_quickstart.md index 5a07af24731..179a87a5448 100644 --- a/docs/quickstart/junit_5_quickstart.md +++ b/docs/quickstart/junit_5_quickstart.md @@ -27,6 +27,7 @@ testCompile "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion" testCompile "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion" testCompile "org.testcontainers:testcontainers:{{latest_version}}" +testCompile "org.testcontainers:junit-jupiter:{{latest_version}}" ``` ```xml tab='Maven' From 85f1b5978803283d723247ed025c3118bbaa4352 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:38:00 +0000 Subject: [PATCH 0510/4969] Bump mariadb-java-client from 2.5.3 to 2.5.4 in /modules/mariadb (#2298) Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.5.3 to 2.5.4. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.5.3...2.5.4) Signed-off-by: dependabot-preview[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index fac747aa68e..c7d1dc96676 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.3' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.4' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.30' From ae3cbc4620aeda338a853efaa8f9590f4f06e31f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:38:50 +0000 Subject: [PATCH 0511/4969] =?UTF-8?q?Bump=20junit-jupiter-api=20from=205.5?= =?UTF-8?q?.2=20to=205.6.0=20in=20/modules/junit-ju=E2=80=A6=20(#2271)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump junit-jupiter-api from 5.5.2 to 5.6.0 in /modules/junit-jupiter Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.5.2 to 5.6.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.5.2...r5.6.0) Signed-off-by: dependabot-preview[bot] * Match engine and API versions to fix compile error Co-authored-by: Richard North --- modules/junit-jupiter/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7b29e36b4dd..7bb6393a586 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.5.2' + compile 'org.junit.jupiter:junit-jupiter-api:5.6.0' testCompile project(':mysql') testCompile project(':postgresql') @@ -15,7 +15,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.9' testRuntime 'mysql:mysql-connector-java:8.0.19' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.2' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.0' } test { From 797c39c81bc125489ccc728d0c4f576002016919 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2020 08:30:47 +0000 Subject: [PATCH 0512/4969] Bump java-client from 2.7.11 to 2.7.12 in /modules/couchbase (#2323) Bumps [java-client](https://github.com/couchbase/couchbase-java-client) from 2.7.11 to 2.7.12. - [Release notes](https://github.com/couchbase/couchbase-java-client/releases) - [Commits](https://github.com/couchbase/couchbase-java-client/compare/2.7.11...2.7.12) Signed-off-by: dependabot-preview[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 27074f1bff7..d6a7e51681e 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.11' + compile 'com.couchbase.client:java-client:2.7.12' testCompile project(':test-support') } From a2995478699597d6a61fc2b475ff6f8ff8937275 Mon Sep 17 00:00:00 2001 From: worldtiki Date: Wed, 5 Feb 2020 08:38:40 +0000 Subject: [PATCH 0513/4969] =?UTF-8?q?Add=20small=20delay=20in=20while=20lo?= =?UTF-8?q?op=20to=20avoid=20spamming=20logs=20(ResourceR=E2=80=A6=20(#228?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add small delay in while loop to avoid spamming logs (ResourceReaper) * Add small delay in while loop to avoid spamming logs (ResourceReaper) - Replaced Thread.sleep with RateLimiter --- .../utility/ResourceReaper.java | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index f46db952c37..f74905e60ef 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -15,10 +15,11 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.rnorth.ducttape.ratelimits.RateLimiter; +import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -49,6 +50,11 @@ public final class ResourceReaper { private static final Logger LOGGER = LoggerFactory.getLogger(ResourceReaper.class); private static final List>> DEATH_NOTE = new ArrayList<>(); + private static final RateLimiter RYUK_ACK_RATE_LIMITER = RateLimiterBuilder + .newBuilder() + .withRate(4, TimeUnit.SECONDS) + .withConstantThroughput() + .build(); private static ResourceReaper instance; private final DockerClient dockerClient; @@ -110,34 +116,36 @@ public static String start(String hostIpAddress, DockerClient client) { DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { while (true) { - int index = 0; - try(Socket clientSocket = new Socket(hostIpAddress, ryukPort)) { - FilterRegistry registry = new FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); - - synchronized (DEATH_NOTE) { - while (true) { - if (DEATH_NOTE.size() <= index) { - try { - DEATH_NOTE.wait(1_000); - continue; - } catch (InterruptedException e) { - throw new RuntimeException(e); + RYUK_ACK_RATE_LIMITER.doWhenReady(() -> { + int index = 0; + try(Socket clientSocket = new Socket(hostIpAddress, ryukPort)) { + FilterRegistry registry = new FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); + + synchronized (DEATH_NOTE) { + while (true) { + if (DEATH_NOTE.size() <= index) { + try { + DEATH_NOTE.wait(1_000); + continue; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + List> filters = DEATH_NOTE.get(index); + boolean isAcknowledged = registry.register(filters); + if (isAcknowledged) { + log.debug("Received 'ACK' from Ryuk"); + ryukScheduledLatch.countDown(); + index++; + } else { + log.debug("Didn't receive 'ACK' from Ryuk. Will retry to send filters."); } - } - List> filters = DEATH_NOTE.get(index); - boolean isAcknowledged = registry.register(filters); - if (isAcknowledged) { - log.debug("Received 'ACK' from Ryuk"); - ryukScheduledLatch.countDown(); - index++; - } else { - log.debug("Didn't receive 'ACK' from Ryuk. Will retry to send filters."); } } + } catch (IOException e) { + log.warn("Can not connect to Ryuk at {}:{}", hostIpAddress, ryukPort, e); } - } catch (IOException e) { - log.warn("Can not connect to Ryuk at {}:{}", hostIpAddress, ryukPort, e); - } + }); } }, "testcontainers-ryuk" @@ -341,12 +349,12 @@ public void unregisterNetwork(String identifier) { public void unregisterContainer(String identifier) { registeredContainers.remove(identifier); } - + public void registerImageForCleanup(String dockerImageName) { setHook(); registeredImages.add(dockerImageName); } - + private void removeImage(String dockerImageName) { LOGGER.trace("Removing image tagged {}", dockerImageName); try { From d4d9bea7c80fadf2e70cb90b54d2bea8dd8d6d48 Mon Sep 17 00:00:00 2001 From: MariuszCwikla <47976407+MariuszCwikla@users.noreply.github.com> Date: Wed, 5 Feb 2020 09:43:31 +0100 Subject: [PATCH 0514/4969] Fix localstack cloudwatchlogs service (#2316) --- modules/localstack/build.gradle | 1 + .../localstack/LocalStackContainer.java | 2 +- .../localstack/LocalstackContainerTest.java | 31 +++++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 819419c57ee..6d87d282d90 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,4 +6,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.636' } diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 36eaacba89b..e21cc735447 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -154,7 +154,7 @@ public enum Service { SSM("ssm", 4583), SECRETSMANAGER("secretsmanager", 4584), STEPFUNCTIONS("stepfunctions", 4585), - CLOUDWATCHLOGS("cloudwatchlogs", 4586), + CLOUDWATCHLOGS("logs", 4586), STS("sts", 4592), IAM("iam", 4593); diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index 1b222c0fbc7..7ad31f6340f 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -1,6 +1,12 @@ package org.testcontainers.containers.localstack; +import com.amazonaws.services.logs.AWSLogs; +import com.amazonaws.services.logs.AWSLogsClientBuilder; +import com.amazonaws.services.logs.model.CreateLogGroupRequest; +import com.amazonaws.services.logs.model.CreateLogGroupResult; +import com.amazonaws.services.logs.model.DescribeLogGroupsRequest; +import com.amazonaws.services.logs.model.LogGroup; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.Bucket; @@ -13,6 +19,7 @@ import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; @@ -31,6 +38,7 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCHLOGS; /** * Tests for Localstack Container, used both in bridge network (exposed to host) and docker network modes. @@ -48,7 +56,7 @@ public static class WithoutNetwork { // without_network { @ClassRule public static LocalStackContainer localstack = new LocalStackContainer() - .withServices(S3, SQS); + .withServices(S3, SQS, CLOUDWATCHLOGS); // } @Test @@ -95,6 +103,20 @@ public void sqsTestOverBridgeNetwork() { .count(); assertEquals("the sent message can be received", 1L, messageCount); } + + @Test + @Ignore("Fails due to https://github.com/localstack/localstack/issues/1434") + public void cloudWatchLogsTestOverBridgeNetwork() { + AWSLogs logs = AWSLogsClientBuilder.standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(CLOUDWATCHLOGS)) + .withCredentials(localstack.getDefaultCredentialsProvider()).build(); + + logs.createLogGroup(new CreateLogGroupRequest("foo")); + + List groups = logs.describeLogGroups().getLogGroups(); + assertEquals("One log group should be created", 1, groups.size()); + assertEquals("Name of created log group is [foo]", "foo", groups.get(0).getLogGroupName()); + } } public static class WithNetwork { @@ -105,7 +127,7 @@ public static class WithNetwork { public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer() .withNetwork(network) .withNetworkAliases("notthis", "localstack") // the last alias is used for HOSTNAME_EXTERNAL - .withServices(S3, SQS); + .withServices(S3, SQS, CLOUDWATCHLOGS); // } @ClassRule @@ -139,6 +161,11 @@ public void sqsTestOverDockerNetwork() throws Exception { assertTrue("the sent message can be received", message.contains("\"Body\": \"test\"")); } + @Test + public void cloudWatchLogsTestOverDockerNetwork() throws Exception { + runAwsCliAgainstDockerNetworkContainer("logs create-log-group --log-group-name foo", CLOUDWATCHLOGS.getPort()); + } + private String runAwsCliAgainstDockerNetworkContainer(String command, final int port) throws Exception { final String[] commandParts = String.format("/usr/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", command, port).split(" "); final Container.ExecResult execResult = awsCliInDockerNetwork.execInContainer(commandParts); From 7cb8ef5850533717b78d78381d40fd7af0b8bf1a Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Wed, 5 Feb 2020 10:18:02 +0100 Subject: [PATCH 0515/4969] adds OrientDB 3.0.x module (#1414) Co-authored-by: Richard North Co-authored-by: Sergei Egorov --- docs/modules/databases/orientdb.md | 78 +++++++++ modules/orientdb/build.gradle | 11 ++ .../containers/OrientDBContainer.java | 153 ++++++++++++++++++ .../containers/OrientDBContainerTest.java | 73 +++++++++ .../src/test/resources/initscript.osql | 6 + .../src/test/resources/logback-test.xml | 18 +++ 6 files changed, 339 insertions(+) create mode 100644 docs/modules/databases/orientdb.md create mode 100644 modules/orientdb/build.gradle create mode 100644 modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java create mode 100644 modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java create mode 100644 modules/orientdb/src/test/resources/initscript.osql create mode 100644 modules/orientdb/src/test/resources/logback-test.xml diff --git a/docs/modules/databases/orientdb.md b/docs/modules/databases/orientdb.md new file mode 100644 index 00000000000..80ed96f9548 --- /dev/null +++ b/docs/modules/databases/orientdb.md @@ -0,0 +1,78 @@ +# OrientDB Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + + +This module helps running [OrientDB](https://orientdb.org/download) using Testcontainers. + +Note that it's based on the [official Docker image](https://hub.docker.com/_/orientdb/) provided by OrientDB. + +## Usage example + +Declare your Testcontainer as a `@ClassRule` or `@Rule` in a JUnit 4 test or as static or member attribute of a JUnit 5 test annotated with `@Container` as you would with other Testcontainers. +You can call `getDbUrl()` OrientDB container and build the `ODatabaseSession` by your own, but a more useful `getSession()` method is provided. +On the JVM you would most likely use the [Java driver](https://github.com/). + +The following example uses the JUnit 5 extension `@Testcontainers` and demonstrates both the usage of the Java Client: + +```java tab="JUnit 5 example" +@Testcontainers +public class ExampleTest { + + @Container + private static OrientDBContainer container = new OrientDBContainer(); + + @Test + void testDbCreation() { + + final ODatabaseSession session = container.getSession(); + + session.command("CREATE CLASS Person EXTENDS V"); + session.command("INSERT INTO Person set name='john'"); + session.command("INSERT INTO Person set name='jane'"); + + assertThat(session.query("SELECT FROM Person").stream()).hasSize(2); + } + +} +``` + +You are not limited to Unit tests and can of course use an instance of the OrientDB Testcontainer in vanilla Java code as well. + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:orientdb:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + orientdb + {{latest_version}} + test + +``` + +!!! hint + Add the OrientDB Java client if you plan to access the Testcontainer: + + ```groovy tab='Gradle' + compile "com.orientechnologies:orientdb-client:3.0.24" + ``` + + ```xml tab='Maven' + + com.orientechnologies + orientdb-client + 3.0.24 + + ``` + + + + diff --git a/modules/orientdb/build.gradle b/modules/orientdb/build.gradle new file mode 100644 index 00000000000..ffa1350172a --- /dev/null +++ b/modules/orientdb/build.gradle @@ -0,0 +1,11 @@ +description = "TestContainers :: Orientdb" + +dependencies { + compile project(":testcontainers") + + compile "com.orientechnologies:orientdb-client:3.0.24" + + testCompile 'org.assertj:assertj-core:3.12.0' + testCompile 'org.apache.tinkerpop:gremlin-driver:3.3.4' + testCompile "com.orientechnologies:orientdb-gremlin:3.0.18" +} diff --git a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java new file mode 100644 index 00000000000..b368d96bf8c --- /dev/null +++ b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java @@ -0,0 +1,153 @@ +package org.testcontainers.containers; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.orientechnologies.orient.core.db.ODatabaseSession; +import com.orientechnologies.orient.core.db.ODatabaseType; +import com.orientechnologies.orient.core.db.OrientDB; +import com.orientechnologies.orient.core.db.OrientDBConfig; +import lombok.NonNull; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.containers.wait.strategy.WaitAllStrategy; +import org.testcontainers.containers.wait.strategy.WaitStrategy; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Optional; + +import static java.net.HttpURLConnection.HTTP_OK; + +/** + * @author robfrank + */ +public class OrientDBContainer extends GenericContainer { + private static final Logger LOGGER = LoggerFactory.getLogger(OrientDBContainer.class); + + private static final String DEFAULT_IMAGE_NAME = "orientdb"; + private static final String DEFAULT_TAG = "3.0.24-tp3"; + private static final String DOCKER_IMAGE_NAME = DEFAULT_IMAGE_NAME + ":" + DEFAULT_TAG; + + private static final String DEFAULT_USERNAME = "admin"; + private static final String DEFAULT_PASSWORD = "admin"; + private static final String DEFAULT_SERVER_PASSWORD = "root"; + + private static final String DEFAULT_DATABASE_NAME = "testcontainers"; + + private static final int DEFAULT_BINARY_PORT = 2424; + private static final int DEFAULT_HTTP_PORT = 2480; + + private String databaseName; + private String serverPassword; + private Optional scriptPath = Optional.empty(); + + private OrientDB orientDB; + private ODatabaseSession session; + + public OrientDBContainer() { + this(DOCKER_IMAGE_NAME); + } + + public OrientDBContainer(@NonNull String dockerImageName) { + super(dockerImageName); + + serverPassword = DEFAULT_SERVER_PASSWORD; + databaseName = DEFAULT_DATABASE_NAME; + + WaitStrategy waitForHttp = new HttpWaitStrategy() + .forPort(DEFAULT_HTTP_PORT) + .forStatusCodeMatching(response -> response == HTTP_OK); + + waitStrategy = new WaitAllStrategy() + .withStrategy(Wait.forListeningPort()) + .withStrategy(waitForHttp) + .withStartupTimeout(Duration.ofMinutes(2)); + } + + @Override + protected void configure() { + addExposedPorts(DEFAULT_BINARY_PORT, DEFAULT_HTTP_PORT); + addEnv("ORIENTDB_ROOT_PASSWORD", serverPassword); + } + + public String getDatabaseName() { + return databaseName; + } + + public String getTestQueryString() { + return "SELECT FROM V"; + } + + public OrientDBContainer withDatabaseName(final String databaseName) { + this.databaseName = databaseName; + return self(); + } + + public OrientDBContainer withServerPassword(final String serverPassword) { + this.serverPassword = serverPassword; + return self(); + } + + public OrientDBContainer withScriptPath(String scriptPath) { + this.scriptPath = Optional.of(scriptPath); + return self(); + } + + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + orientDB = new OrientDB(getServerUrl(), "root", serverPassword, OrientDBConfig.defaultConfig()); + } + + public OrientDB getOrientDB() { + return orientDB; + } + + public String getServerUrl() { + return "remote:" + getContainerIpAddress() + ":" + getMappedPort(2424); + } + + public String getDbUrl() { + return getServerUrl() + "/" + databaseName; + } + + public ODatabaseSession getSession() { + return getSession(DEFAULT_USERNAME, DEFAULT_PASSWORD); + } + + public synchronized ODatabaseSession getSession(String username, String password) { + orientDB.createIfNotExists(databaseName, ODatabaseType.PLOCAL); + + if (session == null) { + session = orientDB.open(databaseName, username, password); + + scriptPath.ifPresent(path -> loadScript(path, session)); + } + return session; + } + + private void loadScript(String path, ODatabaseSession session) { + try { + URL resource = getClass().getClassLoader().getResource(path); + + if (resource == null) { + LOGGER.warn("Could not load classpath init script: {}", scriptPath); + throw new RuntimeException("Could not load classpath init script: " + scriptPath + ". Resource not found."); + } + + String script = IOUtils.toString(resource, StandardCharsets.UTF_8); + + session.execute("sql", script); + } catch (IOException e) { + LOGGER.warn("Could not load classpath init script: {}", scriptPath); + throw new RuntimeException("Could not load classpath init script: " + scriptPath, e); + } catch (UnsupportedOperationException e) { + LOGGER.error("Error while executing init script: {}", scriptPath, e); + throw new RuntimeException("Error while executing init script: " + scriptPath, e); + } + } + +} diff --git a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java new file mode 100644 index 00000000000..0a067b375b6 --- /dev/null +++ b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java @@ -0,0 +1,73 @@ +package org.testcontainers.containers; + +import com.orientechnologies.orient.core.db.ODatabaseSession; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.*; + +/** + * @author robfrank + */ +public class OrientDBContainerTest { + + @Test + public void shouldReturnTheSameSession() { + try (OrientDBContainer container = new OrientDBContainer()) { + container.start(); + + final ODatabaseSession session = container.getSession(); + final ODatabaseSession session2 = container.getSession(); + + assertThat(session).isSameAs(session2); + } + } + + @Test + public void shouldInitializeWithCommands() { + try (OrientDBContainer container = new OrientDBContainer()) { + container.start(); + + final ODatabaseSession session = container.getSession(); + + session.command("CREATE CLASS Person EXTENDS V"); + session.command("INSERT INTO Person set name='john'"); + session.command("INSERT INTO Person set name='jane'"); + + assertThat(session.query("SELECT FROM Person").stream()).hasSize(2); + } + } + + @Test + public void shouldQueryWithGremlin() { + + try (OrientDBContainer container = new OrientDBContainer()) { + container.start(); + + final ODatabaseSession session = container.getSession("admin", "admin"); + + session.command("CREATE CLASS Person EXTENDS V"); + session.command("INSERT INTO Person set name='john'"); + session.command("INSERT INTO Person set name='jane'"); + + assertThat(session.execute("gremlin", + "g.V().hasLabel('Person')").stream()).hasSize(2); + } + } + + @Test + public void shouldInitializeDatabaseFromScript() { + try (OrientDBContainer container = new OrientDBContainer() + .withScriptPath("initscript.osql") + .withDatabaseName("persons")) { + + container.start(); + + assertThat(container.getDbUrl()) + .isEqualTo("remote:" + container.getContainerIpAddress() + ":" + container.getMappedPort(2424) + "/persons"); + + final ODatabaseSession session = container.getSession(); + + assertThat(session.query("SELECT FROM Person").stream()).hasSize(4); + } + } +} diff --git a/modules/orientdb/src/test/resources/initscript.osql b/modules/orientdb/src/test/resources/initscript.osql new file mode 100644 index 00000000000..e1ba22bbb3e --- /dev/null +++ b/modules/orientdb/src/test/resources/initscript.osql @@ -0,0 +1,6 @@ +CREATE CLASS Person EXTENDS V; + +INSERT INTO Person set name="john"; +INSERT INTO Person set name="paul"; +INSERT INTO Person set name="luke"; +INSERT INTO Person set name="albert"; diff --git a/modules/orientdb/src/test/resources/logback-test.xml b/modules/orientdb/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..7bd6a94d827 --- /dev/null +++ b/modules/orientdb/src/test/resources/logback-test.xml @@ -0,0 +1,18 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + + + \ No newline at end of file From 142558426edcc8c993612b1a9e229259106b22bf Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 7 Feb 2020 20:56:15 +0000 Subject: [PATCH 0516/4969] Pin mkdocs dependencies to avoid version incompatibility (#2335) See https://github.com/squidfunk/mkdocs-material/issues/1450 for more background --- requirements.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index a936d8a0a95..dd80510a4b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ -mkdocs +mkdocs==1.0.4 -e git+https://github.com/rnorth/mkdocs-codeinclude-plugin#egg=mkdocs_codeinclude_plugin -mkdocs-material -mkdocs-markdownextradata-plugin +mkdocs-material==4.6.0 +mkdocs-markdownextradata-plugin==0.1.1 +markdown>=3.1,<3.2 From 61ce025d2affb602384af6312235f895bb104983 Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Sat, 8 Feb 2020 21:07:45 +0100 Subject: [PATCH 0517/4969] Add Presto container (#2196) * Add Presto container * Add incubating note to module docs Co-authored-by: Richard North --- docs/modules/databases/index.md | 4 + docs/modules/databases/presto.md | 88 +++++++++++++ mkdocs.yml | 1 + modules/jdbc-test/build.gradle | 2 + .../testcontainers/jdbc/JDBCDriverTest.java | 1 + modules/presto/build.gradle | 8 ++ .../containers/PrestoContainer.java | 104 +++++++++++++++ .../containers/PrestoContainerProvider.java | 35 +++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../containers/PrestoContainerTest.java | 121 ++++++++++++++++++ modules/presto/src/test/resources/initial.sql | 2 + 11 files changed, 367 insertions(+) create mode 100644 docs/modules/databases/presto.md create mode 100644 modules/presto/build.gradle create mode 100644 modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java create mode 100644 modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java create mode 100644 modules/presto/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java create mode 100644 modules/presto/src/test/resources/initial.sql diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index 32026953802..d7654cc6a33 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -69,6 +69,10 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database `jdbc:tc:postgis:9.6:///databasename` +### Using Presto + +`jdbc:tc:presto:329://localhost/memory/default` + ## Using a classpath init script Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: diff --git a/docs/modules/databases/presto.md b/docs/modules/databases/presto.md new file mode 100644 index 00000000000..52776d06daf --- /dev/null +++ b/docs/modules/databases/presto.md @@ -0,0 +1,88 @@ +# Presto Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +See [Database containers](./index.md) for documentation and usage that is common to all database container types. + +## Usage example + +Running Presto as a stand-in for in a test: + +```java +public class SomeTest { + + @Rule + public PrestoContainer presto = new PrestoContainer(); + + @Test + public void someTestMethod() { + String url = presto.getJdbcUrl(); + + ... create a connection and run test as normal +``` + +Presto comes with several catalogs preconfigured. Most useful ones for testing are + +* `tpch` catalog using the [Presto TPCH Connector](https://prestosql.io/docs/current/connector/tpch.html). + This is a read-only catalog that defines standard TPCH schema, so is available for querying without a need + to create any tables. +* `memory` catalog using the [Presto Memory Connector](https://prestosql.io/docs/current/connector/memory.html). + This catalog can be used for creating schemas and tables and does not require any storage, as everything + is stored fully in-memory. + +Example test using the `tpch` and `memory` catalogs: + +```java +public class SomeTest { + @Rule + public PrestoContainer prestoSql = new PrestoContainer(); + + @Test + public void queryMemoryAndTpchConnectors() throws SQLException { + try (Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement()) { + // Prepare data + statement.execute("CREATE TABLE memory.default.table_with_array AS SELECT 1 id, ARRAY[1, 42, 2, 42, 4, 42] my_array"); + + // Query Presto using newly created table and a builtin connector + try (ResultSet resultSet = statement.executeQuery("" + + "SELECT nationkey, element " + + "FROM tpch.tiny.nation " + + "JOIN memory.default.table_with_array twa ON nationkey = twa.id " + + "LEFT JOIN UNNEST(my_array) a(element) ON true " + + "ORDER BY element OFFSET 1 FETCH NEXT 3 ROWS WITH TIES ")) { + List actualElements = new ArrayList<>(); + while (resultSet.next()) { + actualElements.add(resultSet.getInt("element")); + } + Assert.assertEquals(Arrays.asList(2, 4, 42, 42, 42), actualElements); + } + } + } +} +``` + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:presto:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + presto + {{latest_version}} + test + +``` + +!!! hint + Adding this Testcontainers library JAR will not automatically add the Presto JDBC driver JAR to your project. + You should ensure that your project has the Presto JDBC driver as a dependency, if you plan on using it. + Refer to [Presto project download page](https://prestosql.io/download.html) for instructions. + + diff --git a/mkdocs.yml b/mkdocs.yml index 189bc3b6788..f66f382ccb0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -53,6 +53,7 @@ nav: - modules/databases/neo4j.md - modules/databases/oraclexe.md - modules/databases/postgres.md + - modules/databases/presto.md - modules/docker_compose.md - modules/elasticsearch.md - modules/kafka.md diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 842f2a761eb..c7c909782bb 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -7,6 +7,7 @@ repositories { dependencies { compile project(':mysql') compile project(':postgresql') + compile project(':presto') compile project(':cockroachdb') compile project(':mariadb') compile project(':oracle-xe') @@ -16,6 +17,7 @@ dependencies { testCompile 'com.google.guava:guava:18.0' testCompile 'org.postgresql:postgresql:42.0.0' + testCompile 'io.prestosql:presto-jdbc:329' testCompile 'mysql:mysql-connector-java:8.0.14' testCompile 'org.mariadb.jdbc:mariadb-java-client:1.4.6' testCompile 'com.oracle:ojdbc6:12.1.0.1-atlassian-hosted' diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index 2089513df06..ca55a1d1841 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -53,6 +53,7 @@ public static Iterable data() { {"jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, {"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, {"jdbc:tc:postgis:9.6://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + {"jdbc:tc:presto:329://hostname/", EnumSet.of(Options.PmdKnownBroken)}, {"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)}, {"jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class)}, {"jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, diff --git a/modules/presto/build.gradle b/modules/presto/build.gradle new file mode 100644 index 00000000000..07aad11168e --- /dev/null +++ b/modules/presto/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: JDBC :: Presto" + +dependencies { + compile project(':jdbc') + + testCompile 'io.prestosql:presto-jdbc:329' + testCompile 'commons-dbutils:commons-dbutils:1.7' +} diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java new file mode 100644 index 00000000000..186acb18af6 --- /dev/null +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -0,0 +1,104 @@ +package org.testcontainers.containers; + +import org.jetbrains.annotations.NotNull; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; + +import java.sql.Connection; +import java.sql.SQLException; +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Strings.nullToEmpty; +import static java.lang.String.format; +import static java.time.temporal.ChronoUnit.SECONDS; + +public class PrestoContainer> extends JdbcDatabaseContainer { + public static final String NAME = "presto"; + public static final String IMAGE = "prestosql/presto"; + public static final String DEFAULT_TAG = "329"; + + public static final Integer PRESTO_PORT = 8080; + + private String username = "test"; + private String catalog = null; + + public PrestoContainer() { + this(IMAGE + ":" + DEFAULT_TAG); + } + + public PrestoContainer(final String dockerImageName) { + super(dockerImageName); + this.waitStrategy = new LogMessageWaitStrategy() + .withRegEx(".*io.prestosql.server.PrestoServer\\s+======== SERVER STARTED ========.*") + .withStartupTimeout(Duration.of(60, SECONDS)); + } + + @NotNull + @Override + protected Set getLivenessCheckPorts() { + return new HashSet<>(getMappedPort(PRESTO_PORT)); + } + + @Override + protected void configure() { + addExposedPort(PRESTO_PORT); + } + + @Override + public String getDriverClassName() { + return "io.prestosql.jdbc.PrestoDriver"; + } + + @Override + public String getJdbcUrl() { + return format("jdbc:presto://%s:%s/%s", getContainerIpAddress(), getMappedPort(PRESTO_PORT), nullToEmpty(catalog)); + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return ""; + } + + @Override + public String getDatabaseName() { + return catalog; + } + + @Override + public String getTestQueryString() { + return "SELECT count(*) FROM tpch.tiny.nation"; + } + + @Override + public SELF withUsername(final String username) { + this.username = username; + return self(); + } + + /** + * @deprecated This operation is not supported. + */ + @Override + @Deprecated + public SELF withPassword(final String password) { + // ignored, Presto does not support password authentication without TLS + // TODO: make JDBCDriverTest not pass a password unconditionally and remove this method + return self(); + } + + @Override + public SELF withDatabaseName(String dbName) { + this.catalog = dbName; + return self(); + } + + public Connection createConnection() throws SQLException, NoDriverFoundException { + return createConnection(""); + } +} diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java new file mode 100644 index 00000000000..663cf9be4a9 --- /dev/null +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java @@ -0,0 +1,35 @@ +package org.testcontainers.containers; + +import org.testcontainers.jdbc.ConnectionUrl; + +import java.util.Objects; + +/** + * Factory for Presto containers. + */ +public class PrestoContainerProvider extends JdbcDatabaseContainerProvider { + + public static final String USER_PARAM = "user"; + public static final String PASSWORD_PARAM = "password"; + + @Override + public boolean supports(String databaseType) { + return databaseType.equals(PrestoContainer.NAME); + } + + @Override + public JdbcDatabaseContainer newInstance() { + return newInstance(PrestoContainer.DEFAULT_TAG); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new PrestoContainer(PrestoContainer.IMAGE + ":" + tag); + } + + @Override + public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { + return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); + } + +} diff --git a/modules/presto/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/presto/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..ad36a36a117 --- /dev/null +++ b/modules/presto/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.containers.PrestoContainerProvider diff --git a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java new file mode 100644 index 00000000000..07fb6fa30ed --- /dev/null +++ b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java @@ -0,0 +1,121 @@ +package org.testcontainers.containers; + +import org.junit.Assert; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static java.lang.Integer.parseInt; +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author findepi + */ +public class PrestoContainerTest { + @Test + public void testSimple() throws Exception { + try (PrestoContainer prestoSql = new PrestoContainer<>()) { + prestoSql.start(); + try (Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + assertTrue("No result", resultSet.next()); + assertEquals("Presto version", PrestoContainer.DEFAULT_TAG, resultSet.getString("node_version")); + } + } + } + + @Test + public void testSpecificVersion() throws Exception { + String prestoVersion = Integer.toString(parseInt(PrestoContainer.DEFAULT_TAG) - 1); + try (PrestoContainer prestoSql = new PrestoContainer<>("prestosql/presto:" + prestoVersion)) { + prestoSql.start(); + try (Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + assertTrue("No result", resultSet.next()); + assertEquals("Presto version", prestoVersion, resultSet.getString("node_version")); + } + } + } + + @Test + public void testQueryMemoryAndTpch() throws SQLException { + try (PrestoContainer prestoSql = new PrestoContainer<>()) { + prestoSql.start(); + try (Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement()) { + // Prepare data + statement.execute("CREATE TABLE memory.default.table_with_array AS SELECT 1 id, ARRAY[1, 42, 2, 42, 4, 42] my_array"); + + // Query Presto using newly created table and a builtin connector + try (ResultSet resultSet = statement.executeQuery("" + + "SELECT nationkey, element " + + "FROM tpch.tiny.nation " + + "JOIN memory.default.table_with_array twa ON nationkey = twa.id " + + "LEFT JOIN UNNEST(my_array) a(element) ON true " + + "ORDER BY element OFFSET 1 FETCH NEXT 3 ROWS WITH TIES ")) { + List actualElements = new ArrayList<>(); + while (resultSet.next()) { + actualElements.add(resultSet.getInt("element")); + } + Assert.assertEquals(Arrays.asList(2, 4, 42, 42, 42), actualElements); + } + } + } + } + + @Test + public void testInitScript() throws Exception { + try (PrestoContainer prestoSql = new PrestoContainer<>()) { + prestoSql.withInitScript("initial.sql"); + prestoSql.start(); + try (Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table")) { + assertTrue("No result", resultSet.next()); + assertEquals("Value", 12345678909324L, resultSet.getObject("a")); + assertFalse("Too many result", resultSet.next()); + } + } + } + + @Test + public void testTcJdbcUri() throws Exception { + try (Connection connection = DriverManager.getConnection(format("jdbc:tc:presto:%s://hostname/", PrestoContainer.DEFAULT_TAG))) { + // Verify metadata with tc: JDBC connection URI + assertEquals(connection.getMetaData().getDatabaseMajorVersion(), parseInt(PrestoContainer.DEFAULT_TAG)); + + // Verify transactions with tc: JDBC connection URI + assertTrue("Is autocommit", connection.getAutoCommit()); + connection.setAutoCommit(false); + assertFalse("Is autocommit", connection.getAutoCommit()); + assertEquals("Transaction isolation", Connection.TRANSACTION_READ_UNCOMMITTED, connection.getTransactionIsolation()); + + try (Statement statement = connection.createStatement()) { + assertEquals("Update result", 0, statement.executeUpdate("CREATE TABLE memory.default.test_tc(a bigint)")); + try (ResultSet resultSet = statement.executeQuery("SELECT sum(cast(node_version AS bigint)) AS v FROM system.runtime.nodes")) { + assertTrue(resultSet.next()); + assertEquals(PrestoContainer.DEFAULT_TAG, resultSet.getString("v")); + assertFalse(resultSet.next()); + } + connection.commit(); + } finally { + connection.rollback(); + } + connection.setAutoCommit(true); + assertTrue("Is autocommit", connection.getAutoCommit()); + assertEquals("Transaction isolation should be retained", Connection.TRANSACTION_READ_UNCOMMITTED, connection.getTransactionIsolation()); + } + } +} diff --git a/modules/presto/src/test/resources/initial.sql b/modules/presto/src/test/resources/initial.sql new file mode 100644 index 00000000000..1a3ecdab4f9 --- /dev/null +++ b/modules/presto/src/test/resources/initial.sql @@ -0,0 +1,2 @@ +CREATE TABLE memory.default.test_table(a bigint); +INSERT INTO memory.default.test_table(a) VALUES (12345678909324); From 0e13f273a96e59432ac0f0244e61accfe2467e27 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 8 Feb 2020 20:08:35 +0000 Subject: [PATCH 0518/4969] =?UTF-8?q?Bump=20aws-java-sdk-logs=20from=201.1?= =?UTF-8?q?1.636=20to=201.11.717=20in=20/modules/lo=E2=80=A6=20(#2327)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.636 to 1.11.717. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.636...1.11.717) Signed-off-by: dependabot-preview[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 6d87d282d90..81490d2daef 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,5 +6,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.636' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.717' } From d4b2369e30a55ebe34d79062bf018d2576223904 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 8 Feb 2020 20:08:53 +0000 Subject: [PATCH 0519/4969] Bump lombok from 1.18.10 to 1.18.12 in /examples (#2333) Bumps [lombok](https://github.com/rzwitserloot/lombok) from 1.18.10 to 1.18.12. - [Release notes](https://github.com/rzwitserloot/lombok/releases) - [Changelog](https://github.com/rzwitserloot/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/rzwitserloot/lombok/compare/v1.18.10...v1.18.12) Signed-off-by: dependabot-preview[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 1f4e257cad1..fb8413bdec8 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.10" + compileOnly "org.projectlombok:lombok:1.18.12" annotationProcessor "org.projectlombok:lombok:1.18.10" implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.6' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index e74e04a95e5..49052847de1 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -9,7 +9,7 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.10" + compileOnly "org.projectlombok:lombok:1.18.12" annotationProcessor "org.projectlombok:lombok:1.18.10" implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' From 3ba7a7936b5f9e44ef2624edc9e275a39d25add4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 8 Feb 2020 20:09:08 +0000 Subject: [PATCH 0520/4969] Bump postgresql from 42.2.9 to 42.2.10 in /modules/spock (#2329) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.9 to 42.2.10. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.9...REL42.2.10) Signed-off-by: dependabot-preview[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index f26858947ce..c7b51cc9c5f 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -13,6 +13,6 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'org.apache.httpcomponents:httpclient:4.5.11' - testRuntime 'org.postgresql:postgresql:42.2.9' + testRuntime 'org.postgresql:postgresql:42.2.10' testRuntime 'mysql:mysql-connector-java:8.0.19' } From 0d25192210d18ee77b34ad80496d169b9b159512 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 8 Feb 2020 20:09:19 +0000 Subject: [PATCH 0521/4969] Bump postgresql from 42.2.9 to 42.2.10 in /modules/postgresql (#2328) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.9 to 42.2.10. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.9...REL42.2.10) Signed-off-by: dependabot-preview[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index a4bf697a3ad..9acf9ead2aa 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { compile project(':jdbc') - testCompile 'org.postgresql:postgresql:42.2.9' + testCompile 'org.postgresql:postgresql:42.2.10' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' } From 39f1267a5733c27b57477fe7f11321f8d3cde95a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 8 Feb 2020 20:09:30 +0000 Subject: [PATCH 0522/4969] Bump postgresql from 42.2.9 to 42.2.10 in /modules/junit-jupiter (#2330) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.9 to 42.2.10. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.9...REL42.2.10) Signed-off-by: dependabot-preview[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7bb6393a586..b01333b5ec9 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } - testRuntime 'org.postgresql:postgresql:42.2.9' + testRuntime 'org.postgresql:postgresql:42.2.10' testRuntime 'mysql:mysql-connector-java:8.0.19' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.0' } From b1117888694f21dfa2f31a30af7acda6cb34fa2c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 8 Feb 2020 20:23:14 +0000 Subject: [PATCH 0523/4969] =?UTF-8?q?Bump=20aws-java-sdk-logs=20from=201.1?= =?UTF-8?q?1.636=20to=201.11.718=20in=20/modules/lo=E2=80=A6=20(#2336)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.636 to 1.11.718. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.636...1.11.718) Signed-off-by: dependabot-preview[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 81490d2daef..c1c12257baa 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,5 +6,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.717' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.718' } From d4cf9d78314e5a6edbb4c0c2601a16304a865e85 Mon Sep 17 00:00:00 2001 From: Artjom Kalita Date: Sun, 9 Feb 2020 17:34:44 +0200 Subject: [PATCH 0524/4969] Add functionality to retrieve container by its name (#2314) Since `DockerComposeContainer#project` is private, there is currently no way of accessing containers started by Docker Compose. This change adds a new API to the DockerComposeContainer to obtain a `ContainerState` reference by the service's name. Fixes #2302. --- .../containers/DockerComposeContainer.java | 23 ++++++++++++++-- .../junit/DockerComposeContainerTest.java | 26 ++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 7dec6399b8f..839db7c89db 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -22,7 +22,14 @@ import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.lifecycle.Startable; -import org.testcontainers.utility.*; +import org.testcontainers.utility.AuditLogger; +import org.testcontainers.utility.Base58; +import org.testcontainers.utility.CommandLine; +import org.testcontainers.utility.DockerLoggerFactory; +import org.testcontainers.utility.LogUtils; +import org.testcontainers.utility.MountableFile; +import org.testcontainers.utility.ResourceReaper; +import org.testcontainers.utility.TestcontainersConfiguration; import org.zeroturnaround.exec.InvalidExitValueException; import org.zeroturnaround.exec.ProcessExecutor; import org.zeroturnaround.exec.stream.slf4j.Slf4jStream; @@ -30,7 +37,15 @@ import java.io.File; import java.time.Duration; import java.util.AbstractMap.SimpleEntry; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -479,6 +494,10 @@ public SELF withRemoveImages(RemoveImages removeImages) { return self(); } + public Optional getContainerByServiceName(String serviceName) { + return Optional.ofNullable(serviceInstanceMap.get(serviceName)); + } + private void followLogs(String containerId, Consumer consumer) { LogUtils.followOutput(DockerClientFactory.instance().client(), containerId, consumer); } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java index bf69656ac04..53d90872332 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java @@ -2,12 +2,18 @@ import org.junit.Rule; import org.junit.Test; +import org.testcontainers.containers.ContainerState; import org.testcontainers.containers.DockerComposeContainer; import java.io.File; +import java.util.Optional; +import static java.lang.String.format; +import static java.util.Collections.singletonList; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** * Created by rnorth on 08/08/2015. @@ -16,9 +22,8 @@ public class DockerComposeContainerTest extends BaseDockerComposeTest { @Rule public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("redis_1", REDIS_PORT) - .withExposedService("db_1", 3306) - ; + .withExposedService("redis_1", REDIS_PORT) + .withExposedService("db_1", 3306); @Override protected DockerComposeContainer getEnvironment() { @@ -33,4 +38,19 @@ public void testGetServicePort() { assertNotNull("Port is set for service with instance number", serviceWithoutInstancePort); assertEquals("Service ports are the same", serviceWithInstancePort, serviceWithoutInstancePort); } + + @Test + public void shouldRetrieveContainerByServiceName() { + String existingServiceName = "db_1"; + Optional result = environment.getContainerByServiceName(existingServiceName); + assertTrue(format("Container should be found by service name %s", existingServiceName), result.isPresent()); + assertEquals("Mapped port for result container was wrong, probably wrong container found", result.get().getExposedPorts(), singletonList(3306)); + } + + @Test + public void shouldReturnEmptyResultOnNoneExistingService() { + String notExistingServiceName = "db_256"; + Optional result = environment.getContainerByServiceName(notExistingServiceName); + assertFalse(format("No container should be found under service name %s", notExistingServiceName), result.isPresent()); + } } From 2e9adb94ec09c074c43984e14e710daf9d1d6c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivo=20=C5=A0m=C3=ADd?= Date: Sun, 9 Feb 2020 20:34:02 +0100 Subject: [PATCH 0525/4969] checkMountableFile on Windows (#2296) --- .../java/org/testcontainers/utility/MountableFile.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 22939b0e1fd..7b7367b9290 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -242,7 +242,11 @@ private String extractClassPathResourceToTempLocation(final String hostPath) { // Mark temporary files/dirs for deletion at JVM shutdown deleteOnExit(tmpLocation.toPath()); - return tmpLocation.getAbsolutePath(); + try { + return tmpLocation.getCanonicalPath(); + } catch (IOException e) { + throw new IllegalStateException(e); + } } private File createTempDirectory() { @@ -371,8 +375,8 @@ public static int getUnixFileMode(final Path path) { try { int unixMode = (int) Files.readAttributes(path, "unix:mode").get("mode"); // Truncate mode bits for z/OS - if ("OS/390".equals(SystemUtils.OS_NAME) || - "z/OS".equals(SystemUtils.OS_NAME) || + if ("OS/390".equals(SystemUtils.OS_NAME) || + "z/OS".equals(SystemUtils.OS_NAME) || "zOS".equals(SystemUtils.OS_NAME) ) { unixMode &= TarConstants.MAXID; unixMode |= Files.isDirectory(path) ? 040000 : 0100000; From f99de58845c77e8ca1982ef555b598215c24e217 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2020 16:20:29 +0000 Subject: [PATCH 0526/4969] =?UTF-8?q?Bump=20aws-java-sdk-logs=20from=201.1?= =?UTF-8?q?1.718=20to=201.11.722=20in=20/modules/lo=E2=80=A6=20(#2353)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.718 to 1.11.722. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.718...1.11.722) Signed-off-by: dependabot-preview[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c1c12257baa..2bdf076a68c 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,5 +6,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.718' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.722' } From 4d28d29ffddccc72aa939e6780358832f32bc1bf Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2020 16:20:34 +0000 Subject: [PATCH 0527/4969] Bump tomcat-jdbc from 9.0.30 to 9.0.31 in /modules/mysql (#2344) Bumps tomcat-jdbc from 9.0.30 to 9.0.31. Signed-off-by: dependabot-preview[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 43867df521a..11c522197b7 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.19' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.30' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.31' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' } From 5364d699adedcfdf98668319a51affa6aa677c1d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2020 16:20:42 +0000 Subject: [PATCH 0528/4969] Bump tomcat-jdbc from 9.0.30 to 9.0.31 in /modules/mariadb (#2343) Bumps tomcat-jdbc from 9.0.30 to 9.0.31. Signed-off-by: dependabot-preview[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index c7d1dc96676..c479824ae47 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.4' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.30' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.31' testCompile 'org.vibur:vibur-dbcp:25.0' } From f242e290b65ced9ef67dc056540fa55077e3bd24 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2020 16:20:47 +0000 Subject: [PATCH 0529/4969] Bump postgresql from 42.2.9 to 42.2.10 in /examples (#2338) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.9 to 42.2.10. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.9...REL42.2.10) Signed-off-by: dependabot-preview[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index f1977ea2c0b..081b2ac04fa 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:3.14.6' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.9' + testImplementation 'org.postgresql:postgresql:42.2.10' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From 7c8e0ea62ce648b7b75dbdf05263c251284e800b Mon Sep 17 00:00:00 2001 From: nshipyakov <58605486+nshipyakov@users.noreply.github.com> Date: Sun, 16 Feb 2020 23:48:23 +0300 Subject: [PATCH 0530/4969] Kafka: replace deprecated poll method millis param with Duration (#2318) --- .../java/org/testcontainers/containers/KafkaContainerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index add8b2b171d..1490caa3328 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -13,6 +13,7 @@ import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; +import java.time.Duration; import java.util.Arrays; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -100,7 +101,7 @@ protected void testKafkaFunctionality(String bootstrapServers) throws Exception producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); Unreliables.retryUntilTrue(10, TimeUnit.SECONDS, () -> { - ConsumerRecords records = consumer.poll(100); + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); if (records.isEmpty()) { return false; From c7642e581f449fb5bf466a3a74e030be6f57c666 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 16 Feb 2020 20:49:06 +0000 Subject: [PATCH 0531/4969] =?UTF-8?q?Bump=20elasticsearch-rest-client=20fr?= =?UTF-8?q?om=207.5.2=20to=207.6.0=20in=20/modules/=E2=80=A6=20(#2347)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.5.2 to 7.6.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.5.2...v7.6.0) Signed-off-by: dependabot-preview[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 41d5b0f27ab..17c34818a82 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.5.2" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.0" testCompile "org.elasticsearch.client:transport:6.7.1" } From edb54a6bd9fa85fbba748dfe11837ab9c7e31ccb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 16 Feb 2020 20:49:39 +0000 Subject: [PATCH 0532/4969] Bump commons-compress from 1.19 to 1.20 in /core (#2337) Bumps commons-compress from 1.19 to 1.20. Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 25aaa396a60..ab9b92115e9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -60,7 +60,7 @@ dependencies { compile 'org.slf4j:slf4j-api:1.7.30' compile 'org.jetbrains:annotations:17.0.0' compile 'javax.annotation:javax.annotation-api:1.3.2' - compile 'org.apache.commons:commons-compress:1.19' + compile 'org.apache.commons:commons-compress:1.20' // Added for JDK9 compatibility since it's missing this package compile 'javax.xml.bind:jaxb-api:2.3.1' compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { From 573a6222d4a82b24c2d18883a21631d2108d9252 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 16 Feb 2020 20:51:17 +0000 Subject: [PATCH 0533/4969] Bump okhttp from 3.14.4 to 3.14.6 in /core (#2243) Bumps [okhttp](https://github.com/square/okhttp) from 3.14.4 to 3.14.6. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/docs/changelog_3x.md) - [Commits](https://github.com/square/okhttp/compare/parent-3.14.4...parent-3.14.6) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index ab9b92115e9..1f76589a64f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -97,7 +97,7 @@ dependencies { shaded "org.yaml:snakeyaml:1.25" - shaded 'com.squareup.okhttp3:okhttp:3.14.4' + shaded 'com.squareup.okhttp3:okhttp:3.14.6' shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From 6f7b17a9717bb600eccd839b2d84566392e7d999 Mon Sep 17 00:00:00 2001 From: pertu Date: Sun, 16 Feb 2020 20:53:09 +0000 Subject: [PATCH 0534/4969] Set sourceJar.from=allSource for modules/spock (#2281) Fixes issue #2280 By default, sourceJar.from = allJava (see gradle/publishing.gradle) But Spock module is in Groovy => sourceJar.from should be allGroovy/allSource Co-authored-by: Richard North --- modules/spock/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index c7b51cc9c5f..074711d8bda 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,3 +16,9 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.10' testRuntime 'mysql:mysql-connector-java:8.0.19' } + +sourceJar { + /* allJava is default (see gradle/publishing.gradle:sourceJar) + allSource contains both .java and .groovy files */ + from sourceSets.main.allSource +} From 6ec63f863f760e4e4b31965695834622dbcde505 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 24 Feb 2020 14:19:35 +0100 Subject: [PATCH 0535/4969] Prune images between module checks (#2376) --- azure-pipelines.yml | 4 +--- build.gradle | 11 +++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4b060c5fcea..68330550ee1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,9 +37,7 @@ jobs: inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' - options: '--continue -x testcontainers:check -x jdbc-test:check' + options: '--continue -x testcontainers:check -x jdbc-test:check -PpostCheckCommand="docker image prune -af"' tasks: 'check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - - diff --git a/build.gradle b/build.gradle index bac06d64052..c8b2267a049 100644 --- a/build.gradle +++ b/build.gradle @@ -71,6 +71,17 @@ subprojects { // Ensure that Javadoc generation is always tested check.dependsOn(javadoc) + def postCheckCommand = properties["postCheckCommand"] + if (postCheckCommand) { + check.finalizedBy(tasks.create("postCheckExec", Exec) { + if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { + commandLine('cmd', '/c', postCheckCommand) + } else { + commandLine('sh', '-c', postCheckCommand) + } + }) + } + javadoc { dependsOn delombok source = delombok.outputs From b262a20c5c71ec56d8f05f0269bbfec054754606 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 28 Feb 2020 09:53:31 +0000 Subject: [PATCH 0536/4969] =?UTF-8?q?Adding=20Windows=20Subsystem=20for=20?= =?UTF-8?q?Linux=20section=20to=20the=20windows=20docum=E2=80=A6=20(#2282)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Luis Miguel Mejía Suárez Co-authored-by: Richard North Co-authored-by: Luis Miguel Mejía Suárez Co-authored-by: Kevin Wittek --- docs/contributing.md | 6 +++--- docs/supported_docker_environment/index.md | 1 + docs/supported_docker_environment/windows.md | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 70cd452b143..7d87945c704 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -4,9 +4,9 @@ * Join our [Slack group](http://slack.testcontainers.org) * [Post an issue](https://github.com/testcontainers/testcontainers-java/issues) if you find any bugs * Contribute improvements or fixes using a [Pull Request](https://github.com/testcontainers/testcontainers-java/pulls). If you're going to contribute, thank you! Please just be sure to: - * discuss with the authors on an issue ticket prior to doing anything big - * follow the style, naming and structure conventions of the rest of the project - * make commits atomic and easy to merge + * discuss with the authors on an issue ticket prior to doing anything big. + * follow the style, naming and structure conventions of the rest of the project. + * make commits atomic and easy to merge. * when updating documentation, please see [our guidance for documentation contributions](contributing_docs.md). * verify all tests are passing. Build the project with `./gradlew check` to do this. **N.B.** Gradle's Build Cache is enabled by default, but you can add `--no-build-cache` flag to disable it. diff --git a/docs/supported_docker_environment/index.md b/docs/supported_docker_environment/index.md index 3477275c2f2..7622a5051cd 100644 --- a/docs/supported_docker_environment/index.md +++ b/docs/supported_docker_environment/index.md @@ -12,6 +12,7 @@ | Mac OS X - Docker for Mac | 1.12.0 | *Support is best-efforts at present*. `getTestHostIpAddress()` is [not currently supported](https://github.com/testcontainers/testcontainers-java/issues/166) due to limitations in Docker for Mac. | | Windows - Docker Toolbox | | *Support is limited at present and this is not currently tested on a regular basis*. | | Windows - Docker for Windows | | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md) | +| Windows - Windows Subsystem for Linux (WSL) | Docker v17.06 | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md). | ## Docker environment discovery diff --git a/docs/supported_docker_environment/windows.md b/docs/supported_docker_environment/windows.md index b35ee1aa2ee..6365456b095 100644 --- a/docs/supported_docker_environment/windows.md +++ b/docs/supported_docker_environment/windows.md @@ -23,6 +23,25 @@ effort. * WCOW is currently not supported, since Testcontainers uses auxiliary Linux containers for certain tasks and Docker for Windows does not support hybrid engine mode at the time of writing. +## Windows Subsystem for Linux + +Testcontainers supports communicating with Docker for Windows within the Windows Subsystem for Linux *([**WSL**](https://docs.microsoft.com/en-us/windows/wsl/about))*. +The following additional configurations steps are required: + ++ Expose the Docker for Windows daemon on tcp port `2375` without **TLS**. + *(Right-click the Docker for Windows icon on the task bar, click setting and go to `General`)*. + ++ Set the `DOCKER_HOST` environment variable inside the **WSL** shell to `tcp://localhost:2375`. + It is recommended to add this to your `~/.bashrc` file, so it’s available every time you open your terminal. + ++ **Optional** - Only if volumes are required: + Inside the **WSL** shell, modify the `/ect/wsl.conf` file to mount the Windows drives on `/` instead of on `/mnt/`. + *(Reboot required after this step)*. + Remember to share the drives, on which you will store your volumes, with Docker for Windows. + *(Right-click the Docker for Windows icon on the task bar, click setting and go to `Shared Drives`)*. + +More information about running Docker within the **WSL** can be found [here](https://nickjanetakis.com/blog/setting-up-docker-for-windows-and-wsl-to-work-flawlessly). + ## Reporting issues Please report any issues with the Windows build of Testcontainers [here](https://github.com/testcontainers/testcontainers-java/issues) From df48901ed2783ff582ddabd6eb94279e21fd74ab Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 4 Mar 2020 22:24:55 +0100 Subject: [PATCH 0537/4969] Idiomatize testcontainer object creation in kotlin example (#1964) Co-authored-by: Kevin Wittek --- .../kotlin/com/example/redis/AbstractIntegrationTest.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt index dc8b0bf9e68..6350ace9bd9 100644 --- a/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt +++ b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt @@ -17,11 +17,8 @@ import org.testcontainers.containers.GenericContainer abstract class AbstractIntegrationTest { companion object { - val redisContainer = object : GenericContainer("redis:3-alpine") { - init { - withExposedPorts(6379) - } - } + val redisContainer = GenericContainer("redis:3-alpine") + .apply { withExposedPorts(6379) } } internal class Initializer : ApplicationContextInitializer { From 0981d275c10769f237aa0a5f75386851ee971bf4 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 15:07:39 +0000 Subject: [PATCH 0538/4969] Bump mockito-core from 3.2.4 to 3.3.0 in /modules/junit-jupiter (#2372) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.2.4 to 3.3.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.2.4...v3.3.0) Signed-off-by: dependabot-preview[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index b01333b5ec9..7f6d4533509 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'redis.clients:jedis:3.2.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.11' - testCompile ('org.mockito:mockito-core:3.2.4') { + testCompile ('org.mockito:mockito-core:3.3.0') { exclude(module: 'hamcrest-core') } From 7b4f3810d0e5b80123fa2c81fe79b64161232be5 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 15:08:13 +0000 Subject: [PATCH 0539/4969] =?UTF-8?q?Bump=20org.springframework.boot=20fro?= =?UTF-8?q?m=202.2.4.RELEASE=20to=202.2.5.RELEA=E2=80=A6=20(#2387)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.2.4.RELEASE to 2.2.5.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.4.RELEASE...v2.2.5.RELEASE) Signed-off-by: dependabot-preview[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index db570bf67ac..c9bed8d1467 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.4.RELEASE' + id 'org.springframework.boot' version '2.2.5.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 49052847de1..bd9cc9e95f2 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.4.RELEASE' + id 'org.springframework.boot' version '2.2.5.RELEASE' } apply plugin: 'io.spring.dependency-management' From f8a6fa0c818987e4ab2656417eeac4c9982f773c Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 15:08:22 +0000 Subject: [PATCH 0540/4969] Bump java-client from 2.7.12 to 2.7.13 in /modules/couchbase (#2397) Bumps [java-client](https://github.com/couchbase/couchbase-java-client) from 2.7.12 to 2.7.13. - [Release notes](https://github.com/couchbase/couchbase-java-client/releases) - [Commits](https://github.com/couchbase/couchbase-java-client/compare/2.7.12...2.7.13) Signed-off-by: dependabot-preview[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index d6a7e51681e..66f29fc4718 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.12' + compile 'com.couchbase.client:java-client:2.7.13' testCompile project(':test-support') } From e6ee290f39f552c91edbc5c4cdc28c1bb44a18c4 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 15:08:38 +0000 Subject: [PATCH 0541/4969] =?UTF-8?q?Bump=20aws-java-sdk-logs=20from=201.1?= =?UTF-8?q?1.722=20to=201.11.737=20in=20/modules/lo=E2=80=A6=20(#2399)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.722 to 1.11.737. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.722...1.11.737) Signed-off-by: dependabot-preview[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 2bdf076a68c..49e586b19f7 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,5 +6,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.722' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.737' } From 832c6e0ecf861d22a87bdd1760d22e9c74f64993 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 15:08:51 +0000 Subject: [PATCH 0542/4969] =?UTF-8?q?Bump=20elasticsearch-rest-client=20fr?= =?UTF-8?q?om=207.6.0=20to=207.6.1=20in=20/modules/=E2=80=A6=20(#2401)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.6.0 to 7.6.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.6.0...v7.6.1) Signed-off-by: dependabot-preview[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 17c34818a82..75697344874 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.1" testCompile "org.elasticsearch.client:transport:6.7.1" } From f43e799cea8d6ae4aa22927f773b8d0ae5926fc8 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 15:09:56 +0000 Subject: [PATCH 0543/4969] Bump mockito-core from 3.2.4 to 3.3.0 in /core (#2370) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.2.4 to 3.3.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.2.4...v3.3.0) Signed-off-by: dependabot-preview[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 1f76589a64f..5040a487f50 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -109,7 +109,7 @@ dependencies { testCompile 'redis.clients:jedis:3.2.0' testCompile 'com.rabbitmq:amqp-client:5.8.0' testCompile 'org.mongodb:mongo-java-driver:3.12.1' - testCompile ('org.mockito:mockito-core:3.2.4') { + testCompile ('org.mockito:mockito-core:3.3.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 16e9be99861da40edaab78f45b524102af6049f2 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 21:04:30 +0000 Subject: [PATCH 0544/4969] #1975: add example for Cassandra module (#2210) --- docs/modules/databases/cassandra.md | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/modules/databases/cassandra.md b/docs/modules/databases/cassandra.md index 0d9a52a0166..d15304afa81 100644 --- a/docs/modules/databases/cassandra.md +++ b/docs/modules/databases/cassandra.md @@ -1,5 +1,38 @@ # Cassandra Module +## Usage example + +This example connects to the Cassandra Cluster, creates a keyspaces and asserts that is has been created. + +```java tab="JUnit 4 example" +public class SomeTest { + + @Rule + public CassandraContainer cassandra = new CassandraContainer(); + + + @Test + public void test(){ + Cluster cluster = cassandra.getCluster(); + + try(Session session = cluster.connect()) { + + session.execute("CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};"); + + List keyspaces = session.getCluster().getMetadata().getKeyspaces(); + List filteredKeyspaces = keyspaces + .stream() + .filter(km -> km.getName().equals("test")) + .collect(Collectors.toList()); + + assertEquals(1, filteredKeyspaces.size()); + } + } + +} +``` + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: From bf187bb83cb76df9c65f66bc335080d18d5256fe Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Mar 2020 22:58:18 +0000 Subject: [PATCH 0545/4969] Fix missing link to OrientDB in docs and update version --- mkdocs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index f66f382ccb0..49876885dfd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,6 +52,7 @@ nav: - modules/databases/mysql.md - modules/databases/neo4j.md - modules/databases/oraclexe.md + - modules/databases/orientdb.md - modules/databases/postgres.md - modules/databases/presto.md - modules/docker_compose.md @@ -85,4 +86,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.12.5 + latest_version: 1.13.0 From b437227a065e0bc1ff5f58e6bd88fbaef9b58343 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 10 Mar 2020 07:32:17 +0100 Subject: [PATCH 0546/4969] Fix internal port check when other ports are opened as well on the target container (#2363) * Remove redundant execCreateCmd call This one is never used and probably causes some garbage on the docker side. * Allow leading zeros in /proc/net/tcp* when doing internal port listen check When at least one process is listening for a port that is significantly higher then the port we're checking, this check will fail as the checked port will contain leading zeros in the output of "cat /proc/net/tcp". This commit fixes this by changing the grep to ":0*XXX". * Surround grep parameter with ' Otherwise unnecessary shell expansion is tried * Refactor/Rewrite InternalCommandPortListeningCheckTest to test all possible checks This commit refactors InternalCommandPortListeningCheckTest to work with 3 different nginx based containers, each being able to only succeed one of the 3 tests performed in InternalCommandPortListeningCheck. Each test is now executed agains all 3 containers to ensure that all tests work as expected. * Add test for low+high ports This test should fail without the leading zeros fix found a few commits before this one. * Check for bash existence instead of only mentioning it in a comment * Rename nginx_on_8080.conf to nginx.conf It's not only port 8080 anymore, so better not have it in the name. * Make container a @Rule again by moving initialization into contructor * Wait a few seconds for InternalCommandPortListeningCheck to pass --- .../containers/ExecInContainerPattern.java | 4 -- .../InternalCommandPortListeningCheck.java | 2 +- ...InternalCommandPortListeningCheckTest.java | 55 ++++++++++++++++--- .../Dockerfile-bash | 11 ++++ .../Dockerfile-nc | 9 +++ .../Dockerfile-tcp | 9 +++ .../internal-port-check-dockerfile/nginx.conf | 8 +++ core/src/test/resources/nginx_on_8080.conf | 5 -- 8 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 core/src/test/resources/internal-port-check-dockerfile/Dockerfile-bash create mode 100644 core/src/test/resources/internal-port-check-dockerfile/Dockerfile-nc create mode 100644 core/src/test/resources/internal-port-check-dockerfile/Dockerfile-tcp create mode 100644 core/src/test/resources/internal-port-check-dockerfile/nginx.conf delete mode 100644 core/src/test/resources/nginx_on_8080.conf diff --git a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java index 3d0f4c2c360..359065d732b 100644 --- a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java +++ b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java @@ -66,10 +66,6 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn DockerClient dockerClient = DockerClientFactory.instance().client(); - dockerClient - .execCreateCmd(containerId) - .withCmd(command); - log.debug("{}: Running \"exec\" command: {}", containerName, String.join(" ", command)); final ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId) .withAttachStdout(true).withAttachStderr(true).withCmd(command).exec(); diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index 2013ddc4d9c..9b4be81b4c4 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -29,7 +29,7 @@ public Boolean call() { for (int internalPort : internalPorts) { command += " && "; command += " ("; - command += format("cat /proc/net/tcp* | awk '{print $2}' | grep -i :%x", internalPort); + command += format("cat /proc/net/tcp* | awk '{print $2}' | grep -i ':0*%x'", internalPort); command += " || "; command += format("nc -vz -w 1 localhost %d", internalPort); command += " || "; diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java index bee4f0a231a..00c0bc9d1ef 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java @@ -3,23 +3,47 @@ import com.google.common.collect.ImmutableSet; import org.junit.Rule; import org.junit.Test; -import org.testcontainers.containers.BindMode; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.rnorth.ducttape.TimeoutException; +import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.images.builder.ImageFromDockerfile; +import java.util.concurrent.TimeUnit; + +import static java.util.Arrays.asList; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +@RunWith(Parameterized.class) public class InternalCommandPortListeningCheckTest { - // Linking a custom configuration into the container so that nginx is listening on port 8080. This is necessary to prove - // that the command formatting uses the correct casing for hexadecimal numbers (i.e. 1F90 and not 1f90). + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"internal-port-check-dockerfile/Dockerfile-tcp"}, + {"internal-port-check-dockerfile/Dockerfile-nc"}, + {"internal-port-check-dockerfile/Dockerfile-bash"}, + }); + } + @Rule - public GenericContainer nginx = new GenericContainer<>("nginx:1.9.4") - .withClasspathResourceMapping("nginx_on_8080.conf", "/etc/nginx/conf.d/default.conf", BindMode.READ_ONLY); + public GenericContainer container; + + public InternalCommandPortListeningCheckTest(String dockerfile) { + container = new GenericContainer(new ImageFromDockerfile() + .withFileFromClasspath("Dockerfile", dockerfile) + .withFileFromClasspath("nginx.conf", "internal-port-check-dockerfile/nginx.conf") + ); + } @Test public void singleListening() { - final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(nginx, ImmutableSet.of(8080)); + final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(container, ImmutableSet.of(8080)); + + Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); final Boolean result = check.call(); @@ -28,10 +52,27 @@ public void singleListening() { @Test public void nonListening() { - final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(nginx, ImmutableSet.of(8080, 1234)); + final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(container, ImmutableSet.of(8080, 1234)); + + try { + Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); + } catch (TimeoutException e) { + // we expect it to timeout + } final Boolean result = check.call(); assertFalse("InternalCommandPortListeningCheck detects a non-listening port among many", result); } + + @Test + public void lowAndHighPortListening() { + final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(container, ImmutableSet.of(100, 8080)); + + Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); + + final Boolean result = check.call(); + + assertTrue("InternalCommandPortListeningCheck identifies a low and a high port", result); + } } diff --git a/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-bash b/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-bash new file mode 100644 index 00000000000..02373da980e --- /dev/null +++ b/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-bash @@ -0,0 +1,11 @@ +FROM nginx:1.17-alpine + +RUN apk add bash + +# Make sure the /proc/net/tcp* check fails in this container +RUN rm /usr/bin/awk + +# Make sure the nc check fails in this container +RUN rm /usr/bin/nc + +ADD nginx.conf /etc/nginx/conf.d/default.conf diff --git a/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-nc b/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-nc new file mode 100644 index 00000000000..f69b74a8754 --- /dev/null +++ b/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-nc @@ -0,0 +1,9 @@ +FROM nginx:1.17-alpine + +# If this fails, you ended up using a base image with bash installed. Consider removing /bin/bash in this case +RUN if bash -c true &> /dev/null; then exit 1; fi + +# Make sure the /proc/net/tcp* check fails in this container +RUN rm /usr/bin/awk + +ADD nginx.conf /etc/nginx/conf.d/default.conf diff --git a/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-tcp b/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-tcp new file mode 100644 index 00000000000..8699db537aa --- /dev/null +++ b/core/src/test/resources/internal-port-check-dockerfile/Dockerfile-tcp @@ -0,0 +1,9 @@ +FROM nginx:1.17-alpine + +# If this fails, you ended up using a base image with bash installed. Consider removing /bin/bash in this case +RUN if bash -c true &> /dev/null; then exit 1; fi + +# Make sure the nc check fails in this container +RUN rm /usr/bin/nc + +ADD nginx.conf /etc/nginx/conf.d/default.conf diff --git a/core/src/test/resources/internal-port-check-dockerfile/nginx.conf b/core/src/test/resources/internal-port-check-dockerfile/nginx.conf new file mode 100644 index 00000000000..f69ddf345cf --- /dev/null +++ b/core/src/test/resources/internal-port-check-dockerfile/nginx.conf @@ -0,0 +1,8 @@ +# This configuration makes Nginx listen on port port 8080 + +server { + # Port 8080 is necessary to prove that the command formatting in the /proc/net/tcp* check uses the correct casing for hexadecimal numbers (i.e. 1F90 and not 1f90) + listen 8080; + # Port 100 is necessary to ensure that the /proc/net/tcp* check also succeeds with trailing zeros in the hexadecimal port + listen 100; +} diff --git a/core/src/test/resources/nginx_on_8080.conf b/core/src/test/resources/nginx_on_8080.conf deleted file mode 100644 index c7927d46265..00000000000 --- a/core/src/test/resources/nginx_on_8080.conf +++ /dev/null @@ -1,5 +0,0 @@ -# This configuration makes Nginx listen on port port 8080 - -server { - listen 8080; -} \ No newline at end of file From 16fda4216018d94f2bf9c20379d3a3573050a06c Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 10 Mar 2020 07:35:28 +0100 Subject: [PATCH 0547/4969] Fix invalid connection URLs returned by PostgreSQLContainer (fixes #1976) (#2049) * Reproduce #1976 in tests * Override constructUrlForConnection for PostgreSQLContainer * Lighten PostgreSQLConnectionURLTest * Lighten PostgreSQLConnectionURLTest * Cater for base URLs without query strings --- .../containers/PostgreSQLContainer.java | 22 +++++- .../PostgreSQLConnectionURLTest.java | 68 +++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 85ad910aa17..cef66d0c492 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -7,6 +7,7 @@ import java.util.HashSet; import java.util.Set; +import static java.lang.String.format; import static java.time.temporal.ChronoUnit.SECONDS; /** @@ -24,6 +25,8 @@ public class PostgreSQLContainer> extends private static final String FSYNC_OFF_OPTION = "fsync=off"; + private static final String QUERY_PARAM_SEPARATOR = "&"; + public PostgreSQLContainer() { this(IMAGE + ":" + DEFAULT_TAG); } @@ -59,7 +62,24 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { // Disable Postgres driver use of java.util.logging to reduce noise at startup time - return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + "/" + databaseName + "?loggerLevel=OFF"; + return format("jdbc:postgresql://%s:%d/%s?loggerLevel=OFF", getContainerIpAddress(), getMappedPort(POSTGRESQL_PORT), databaseName); + } + + @Override + protected String constructUrlForConnection(String queryString) { + String baseUrl = getJdbcUrl(); + + if ("".equals(queryString)) { + return baseUrl; + } + + if (!queryString.startsWith("?")) { + throw new IllegalArgumentException("The '?' character must be included"); + } + + return baseUrl.contains("?") + ? baseUrl + QUERY_PARAM_SEPARATOR + queryString.substring(1) + : baseUrl + queryString; } @Override diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java new file mode 100644 index 00000000000..ec6a8756cab --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -0,0 +1,68 @@ +package org.testcontainers.containers; + +import org.junit.Test; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; + +public class PostgreSQLConnectionURLTest { + + @Test + public void shouldCorrectlyAppendQueryString() { + PostgreSQLContainer postgres = new FixedJdbcUrlPostgreSQLContainer(); + String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); + String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); + + assertTrue("Query String contains expected params", queryString.contains("&stringtype=unspecified&stringtype=unspecified")); + assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); + assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); + } + + @Test + public void shouldCorrectlyAppendQueryStringWhenNoBaseParams() { + PostgreSQLContainer postgres = new NoParamsUrlPostgreSQLContainer(); + String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); + String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); + + assertTrue("Query String contains expected params", queryString.contains("?stringtype=unspecified&stringtype=unspecified")); + assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); + assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); + } + + @Test + public void shouldReturnOriginalURLWhenEmptyQueryString() { + PostgreSQLContainer postgres = new FixedJdbcUrlPostgreSQLContainer(); + String connectionUrl = postgres.constructUrlForConnection(""); + + assertTrue("Query String remains unchanged", postgres.getJdbcUrl().equals(connectionUrl)); + } + + @Test + public void shouldRejectInvalidQueryString() { + assertThrows("Fails when invalid query string provided", IllegalArgumentException.class, + () -> new NoParamsUrlPostgreSQLContainer().constructUrlForConnection("stringtype=unspecified")); + } + + static class FixedJdbcUrlPostgreSQLContainer extends PostgreSQLContainer { + + @Override + public String getContainerIpAddress() { + return "localhost"; + } + + @Override + public Integer getMappedPort(int originalPort) { + return 34532; + } + } + + static class NoParamsUrlPostgreSQLContainer extends PostgreSQLContainer { + + @Override + public String getJdbcUrl() { + return "jdbc:postgresql://host:port/database"; + } + } +} From 7d5f4c9e35b5d671f24125395aed3f741f6c3d9e Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 12 Mar 2020 21:14:19 +0100 Subject: [PATCH 0548/4969] Update to docker-java 3.2.0 (#2297) * Test new `docker-java` module * global Jitpack repo * update to the current master of docker-java * try docker-java-core * use 3.2.0-rc1 * update to docker-java 3.2.0-rc2 * remove unnecessary dependency * Update to docker-java 3.2.0-rc3, use their okhttp cmd factory * post-merge fixes * Update to docker-java 3.2.0-rc4 * fix JarFileShadingTest * Add japicmp task * Update to 3.2.0-rc5 * postpone shading changes * reduce the changeset * do not run japicmp on Windows * try running modules' tests without the checks * split module runs * fix the tasks list * fix the tasks list (2) * do not disable the checks * try `postCheckCommand` * make `postCheckCommand` optional * Update azure-pipelines.yml * Update to docker-java 3.2.0 * restore `postCheckCommand` --- core/build.gradle | 66 ++++++++++++++++--- .../testcontainers/JarFileShadingTest.java | 1 - .../testcontainers/PublicBinaryAPITest.java | 12 ++++ .../containers/GenericContainer.java | 8 +-- .../containers/VncRecordingContainer.java | 5 +- .../AuditLoggingDockerClient.java | 3 + .../dockerclient/DockerClientConfigUtils.java | 9 ++- .../DockerClientProviderStrategy.java | 9 ++- .../NpipeSocketClientProviderStrategy.java | 13 +--- .../AuthDelegatingDockerClientConfig.java | 3 + .../okhttp/NamedPipeSocketFactory.java | 4 ++ .../okhttp/OkHttpDockerCmdExecFactory.java | 12 +++- .../transport/okhttp/OkHttpWebTarget.java | 8 +-- .../transport/okhttp/UnixSocketFactory.java | 4 ++ ...eLimitedLoggedPullImageResultCallback.java | 5 +- .../couchbase/CouchbaseContainer.java | 3 +- .../containers/KafkaContainer.java | 3 +- 17 files changed, 123 insertions(+), 45 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 5040a487f50..0d452f5cc1d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,3 +1,18 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + // https://github.com/melix/japicmp-gradle-plugin/issues/36 + classpath 'com.google.guava:guava:28.2-jre' + } +} + +plugins { + id 'me.champeau.gradle.japicmp' version '0.2.8' +} + apply plugin: 'com.github.johnrengelman.shadow' description = "Testcontainers Core" @@ -9,6 +24,7 @@ sourceSets { idea.module.testSourceDirs += sourceSets.jarFileTest.allSource.srcDirs configurations { + baseline shaded [runtime, compileOnly, testCompile]*.extendsFrom shaded } @@ -55,7 +71,47 @@ task jarFileTest(type: Test) { } project.tasks.check.dependsOn(jarFileTest) +task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { + dependsOn(tasks.shadowJar) + + oldClasspath = configurations.baseline + newClasspath = shadowJar.outputs.files + ignoreMissingClasses = true + + accessModifier = "protected" + failOnModification = true + failOnSourceIncompatibility = true + + // TODO cleanup excludes after we release the version based on docker-java 3.2.0 + + packageExcludes = [ + "com.github.dockerjava.*", + "org.testcontainers.shaded.*", + ] + + classExcludes = [ + // 'METHOD_REMOVED_IN_SUPERCLASS' + "org.testcontainers.containers.output.FrameConsumerResultCallback", + "org.testcontainers.dockerclient.LogToStringContainerCallback", + + // 'METHOD_RETURN_TYPE_CHANGED', exposed `com.github.dockerjava.core.command.PullImageResultCallback` to the public API + "org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback", + ] + + onlyBinaryIncompatibleModified = true + htmlOutputFile = file("$buildDir/reports/japi.html") +} +// do not run on Windows by default +// TODO investigate zip issue on Windows +if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { + project.tasks.check.dependsOn(japicmp) +} + dependencies { + baseline 'org.testcontainers:testcontainers:1.12.5', { + exclude group: "*", module: "*" + } + compile 'junit:junit:4.12' compile 'org.slf4j:slf4j-api:1.7.30' compile 'org.jetbrains:annotations:17.0.0' @@ -82,15 +138,9 @@ dependencies { exclude(group: "net.java.dev.jna") } - shaded ('com.github.docker-java:docker-java:3.1.5') { - exclude(group: 'org.glassfish.jersey.core') - exclude(group: 'org.glassfish.jersey.connectors') - exclude(group: 'org.glassfish.jersey.inject') - exclude(group: 'log4j') + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.0') { + exclude(group: 'net.java.dev.jna') exclude(group: 'com.google.code.findbug') - exclude(group: 'com.kohlschutter.junixsocket') - exclude(group: 'io.netty') - exclude(group: 'org.apache.httpcomponents') exclude(group: 'org.slf4j') exclude(group: 'org.apache.commons', module: 'commons-compress') } diff --git a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java index cf807087d55..587ab6277f6 100644 --- a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java +++ b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java @@ -14,7 +14,6 @@ public class JarFileShadingTest extends AbstractJarFileTest { @Test public void testPackages() throws Exception { assertThatFileList(root).containsOnly( - "docker-java.properties", "org", "META-INF", "com" diff --git a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java index 6d995e7e0be..93d1a759096 100644 --- a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java +++ b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java @@ -2,6 +2,8 @@ import lombok.RequiredArgsConstructor; import org.assertj.core.api.Assertions; +import org.junit.Assume; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -84,6 +86,16 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IO private final ClassNode classNode; + @Before + public void setUp() { + Assume.assumeFalse(classNode.name.startsWith("com.github.dockerjava.")); + switch (classNode.name) { + // TODO should go to docker-java project + case "org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig": + Assume.assumeTrue(false); + } + } + @Test public void testSuperClass() { assertThat(classNode.superName) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index ee458339d0a..03d03759506 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -20,12 +20,12 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; +import com.google.common.hash.Hashing; import lombok.AccessLevel; import lombok.Data; import lombok.NonNull; import lombok.Setter; import lombok.SneakyThrows; -import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; @@ -520,12 +520,12 @@ void checksumFile(File file, Checksum checksum) { @SneakyThrows(JsonProcessingException.class) final String hash(CreateContainerCmd createCommand) { // TODO add Testcontainers' version to the hash - String commandJson = new ObjectMapper() + byte[] commandJson = new ObjectMapper() .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY) .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) - .writeValueAsString(createCommand); + .writeValueAsBytes(createCommand); - return DigestUtils.sha1Hex(commandJson); + return Hashing.sha1().hashBytes(commandJson).toString(); } @VisibleForTesting diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index 1b06215b706..298593a116b 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -5,7 +5,6 @@ import lombok.NonNull; import lombok.SneakyThrows; import lombok.ToString; -import org.apache.commons.codec.binary.Base64; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.rnorth.ducttape.TimeoutException; import org.rnorth.ducttape.unreliables.Unreliables; @@ -17,6 +16,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.StandardCopyOption; +import java.util.Base64; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -112,9 +112,10 @@ public VncRecordingContainer withFrameRate(int frameRate) { @Override protected void configure() { withCreateContainerCmdModifier(it -> it.withEntrypoint("/bin/sh")); + String encodedPassword = Base64.getEncoder().encodeToString(vncPassword.getBytes()); setCommand( "-c", - "echo '" + Base64.encodeBase64String(vncPassword.getBytes()) + "' | base64 -d > /vnc_password && " + + "echo '" + encodedPassword + "' | base64 -d > /vnc_password && " + "flvrec.py -o " + RECORDING_FILE_NAME + " -d -r " + frameRate + " -P /vnc_password " + targetNetworkAlias + " " + vncPort ); } diff --git a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java index f982945f9d4..891709e3a0c 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java @@ -15,9 +15,12 @@ /** * Wrapper for {@link DockerClient} to facilitate 'audit logging' of potentially destruction actions using * {@link org.testcontainers.utility.AuditLogger}. + * + * @deprecated should not be used publicly */ @Slf4j @SuppressWarnings("unchecked") +@Deprecated public class AuditLoggingDockerClient implements DockerClient { @Delegate(excludes = InterceptedMethods.class) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java index d88dc76331f..1060d663d65 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java @@ -7,6 +7,7 @@ import org.testcontainers.DockerClientFactory; import java.io.File; +import java.net.URI; import java.util.Optional; import static java.util.concurrent.TimeUnit.SECONDS; @@ -48,11 +49,15 @@ public class DockerClientConfigUtils { */ @Deprecated public static String getDockerHostIpAddress(DockerClientConfig config) { - switch (config.getDockerHost().getScheme()) { + return getDockerHostIpAddress(config.getDockerHost()); + } + + public static String getDockerHostIpAddress(URI dockerHost) { + switch (dockerHost.getScheme()) { case "http": case "https": case "tcp": - return config.getDockerHost().getHost(); + return dockerHost.getHost(); case "unix": case "npipe": if (IN_A_CONTAINER) { diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index aa607964ae5..1c5aea87723 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -2,8 +2,9 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Network; -import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.okhttp.OkHttpDockerCmdExecFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; import org.apache.commons.io.IOUtils; @@ -16,7 +17,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.dockerclient.auth.AuthDelegatingDockerClientConfig; -import org.testcontainers.dockerclient.transport.okhttp.OkHttpDockerCmdExecFactory; import org.testcontainers.utility.TestcontainersConfiguration; import java.net.URI; @@ -172,10 +172,9 @@ public DockerClient getClient() { } protected DockerClient getClientForConfig(DockerClientConfig config) { - return DockerClientBuilder + return DockerClientImpl .getInstance(new AuthDelegatingDockerClientConfig(config)) - .withDockerCmdExecFactory(new OkHttpDockerCmdExecFactory()) - .build(); + .withDockerCmdExecFactory(new OkHttpDockerCmdExecFactory()); } protected void ping(DockerClient client, int timeoutInSeconds) { diff --git a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java index b8d85f11623..329bde36433 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java @@ -8,8 +8,6 @@ import org.apache.commons.lang.SystemUtils; import org.jetbrains.annotations.NotNull; -import java.net.URI; - @Slf4j public class NpipeSocketClientProviderStrategy extends DockerClientProviderStrategy { @@ -38,19 +36,12 @@ public void test() throws InvalidConfigurationException { @NotNull private DockerClientConfig tryConfiguration() { - URI dockerHost = URI.create(SOCKET_LOCATION); - config = new DelegatingDockerClientConfig( DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost("tcp://localhost:0") + .withDockerHost(SOCKET_LOCATION) .withDockerTlsVerify(false) .build() - ) { - @Override - public URI getDockerHost() { - return dockerHost; - } - }; + ); client = getClientForConfig(config); final int timeout = Integer.parseInt(System.getProperty(PING_TIMEOUT_PROPERTY_NAME, PING_TIMEOUT_DEFAULT)); diff --git a/core/src/main/java/org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig.java b/core/src/main/java/org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig.java index d75f3ce6bc1..a68605fdfda 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig.java +++ b/core/src/main/java/org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig.java @@ -14,8 +14,11 @@ * configuration is obtained. A delegate {@link DockerClientConfig} will be called first * to try and obtain auth credentials, but after that {@link RegistryAuthLocator} will be * used to try and improve the auth resolution (e.g. using credential helpers). + * + * @deprecated should not be used publicly, to be moved to docker-java */ @Slf4j +@Deprecated public class AuthDelegatingDockerClientConfig implements DockerClientConfig { @Delegate(excludes = DelegateExclusions.class) diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java index d150eedb6a5..d26e2977318 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java @@ -13,6 +13,10 @@ import java.net.SocketAddress; import java.util.concurrent.TimeUnit; +/** + * @deprecated use com.github.docker-java:docker-java-transport-okhttp + */ +@Deprecated @Value @EqualsAndHashCode(callSuper = false) public class NamedPipeSocketFactory extends SocketFactory { diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java index 841d012e2b3..4da568834d5 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java @@ -1,5 +1,6 @@ package org.testcontainers.dockerclient.transport.okhttp; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.command.PingCmd; import com.github.dockerjava.core.AbstractDockerCmdExecFactory; import com.github.dockerjava.core.DockerClientConfig; @@ -25,11 +26,17 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; +/** + * @deprecated use com.github.docker-java:docker-java-transport-okhttp + */ +@Deprecated @Slf4j public class OkHttpDockerCmdExecFactory extends AbstractDockerCmdExecFactory { private static final String SOCKET_SUFFIX = ".socket"; + private ObjectMapper objectMapper; + private OkHttpClient okHttpClient; private HttpUrl baseUrl; @@ -100,11 +107,14 @@ public void init(DockerClientConfig dockerClientConfig) { baseUrlBuilder = HttpUrl.get(dockerHost.toString()).newBuilder(); } baseUrl = baseUrlBuilder.build(); + + objectMapper = dockerClientConfig.getObjectMapper(); } @Override - protected WebTarget getBaseResource() { + protected OkHttpWebTarget getBaseResource() { return new OkHttpWebTarget( + objectMapper, okHttpClient, baseUrl, ImmutableList.of(), diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java index 7e12b0b4541..9c360522d20 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.github.dockerjava.core.InvocationBuilder; import com.github.dockerjava.core.WebTarget; import com.google.common.collect.HashMultimap; @@ -25,8 +24,7 @@ @Value class OkHttpWebTarget implements WebTarget { - private static final ObjectMapper MAPPER = new ObjectMapper() - .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + ObjectMapper objectMapper; OkHttpClient okHttpClient; @@ -56,7 +54,7 @@ public InvocationBuilder request() { } return new OkHttpInvocationBuilder( - MAPPER, + objectMapper, okHttpClient, baseUrlBuilder.build() ); @@ -110,6 +108,6 @@ public OkHttpWebTarget queryParamsJsonMap(String name, Map value } // when param value is JSON string - return queryParam(name, MAPPER.writeValueAsString(values)); + return queryParam(name, objectMapper.writeValueAsString(values)); } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java index 2fbdb936447..d1e55f3e647 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java +++ b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java @@ -15,6 +15,10 @@ import java.net.Socket; import java.net.SocketAddress; +/** + * @deprecated use com.github.docker-java:docker-java-transport-okhttp + */ +@Deprecated @Value @EqualsAndHashCode(callSuper = false) public class UnixSocketFactory extends SocketFactory { diff --git a/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java index 20b7de6c666..274eedefded 100644 --- a/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java +++ b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java @@ -47,9 +47,10 @@ public TimeLimitedLoggedPullImageResultCallback(Logger logger) { } @Override - public PullImageResultCallback awaitCompletion() throws InterruptedException { + public TimeLimitedLoggedPullImageResultCallback awaitCompletion() throws InterruptedException { waitingThreads.add(Thread.currentThread()); - return super.awaitCompletion(); + super.awaitCompletion(); + return this; } @Override diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 19583d5a0e4..e43cf8f652d 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -26,7 +26,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.command.InspectContainerResponse; -import com.github.dockerjava.core.command.ExecStartResultCallback; import com.google.common.collect.Lists; import lombok.*; import org.apache.commons.compress.utils.Sets; @@ -171,7 +170,7 @@ private void startProxy(String networkAlias) { .exec(); dockerClient.execStartCmd(createCmdResponse.getId()) - .exec(new ExecStartResultCallback()) + .start() .awaitCompletion(10, TimeUnit.SECONDS); } diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index b0ce047f5d4..5aab0f52ffa 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -2,7 +2,6 @@ import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.command.InspectContainerResponse; -import com.github.dockerjava.core.command.ExecStartResultCallback; import lombok.SneakyThrows; import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.TestcontainersConfiguration; @@ -150,7 +149,7 @@ private String startZookeeper() { ) .exec(); - dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ExecStartResultCallback()).awaitStarted(10, TimeUnit.SECONDS); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).start().awaitStarted(10, TimeUnit.SECONDS); return "localhost:" + ZOOKEEPER_PORT; } From 3f9216ebda2087b3311de979a96918e3ccaefc2d Mon Sep 17 00:00:00 2001 From: MariuszCwikla <47976407+MariuszCwikla@users.noreply.github.com> Date: Fri, 13 Mar 2020 10:53:36 +0100 Subject: [PATCH 0549/4969] Upgrade localstack to 0.10.8 (#2413) --- .../containers/localstack/LocalStackContainer.java | 2 +- .../containers/localstack/LocalstackContainerTest.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index e21cc735447..0d8c3627f6c 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -29,7 +29,7 @@ */ public class LocalStackContainer extends GenericContainer { - public static final String VERSION = "0.9.4"; + public static final String VERSION = "0.10.8"; private static final String HOSTNAME_EXTERNAL_ENV_VAR = "HOSTNAME_EXTERNAL"; private final List services = new ArrayList<>(); diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index 7ad31f6340f..034ff2f0914 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -105,7 +105,6 @@ public void sqsTestOverBridgeNetwork() { } @Test - @Ignore("Fails due to https://github.com/localstack/localstack/issues/1434") public void cloudWatchLogsTestOverBridgeNetwork() { AWSLogs logs = AWSLogsClientBuilder.standard() .withEndpointConfiguration(localstack.getEndpointConfiguration(CLOUDWATCHLOGS)) From 4f8f8b143d6d462257500959be9fa0eb37f2fa12 Mon Sep 17 00:00:00 2001 From: Sandra Parsick Date: Wed, 18 Mar 2020 14:02:57 +0100 Subject: [PATCH 0550/4969] Extend docs with registry mirror as workaround for custom images (#2452) Add a link to registry mirror documentation in docker as a possibility when direct usage of docker hub is not allowed Co-Authored-By: Kevin Wittek --- docs/features/configuration.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 61500cb9cb5..cd01b99b1c7 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -45,6 +45,9 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **localstack.container.image = localstack/localstack** > Used by LocalStack +Another possibility is to set up a registry mirror in your environment so that all images are pulled from there and not directly from Docker Hub. +For more information, see the [official Docker documentation about "Registry as a pull through cache"](https://docs.docker.com/registry/recipes/mirror/). + ## Customizing Ryuk resource reaper > **ryuk.container.image = quay.io/testcontainers/ryuk:0.2.3** From d4f894f081838de96f0053312b08dc2f9a365a64 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 25 Mar 2020 11:44:09 +0100 Subject: [PATCH 0551/4969] Fallback to `getDefaultGateway()` if "bridge" is unavailable. (#2429) Fixes #2239 --- .../dockerclient/DockerClientProviderStrategy.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 1c5aea87723..c305d56389c 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -218,7 +218,9 @@ static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost) { .filter(it -> it.getGateway() != null) .findAny() .map(Network.Ipam.Config::getGateway) - .orElse("localhost"); + .orElseGet(() -> { + return DockerClientConfigUtils.getDefaultGateway().orElse("localhost"); + }); } return "localhost"; default: From 7acb08d6c5c99f94a40998e00fb1db18cc66c061 Mon Sep 17 00:00:00 2001 From: Anton Deriabin Date: Wed, 25 Mar 2020 14:00:27 +0300 Subject: [PATCH 0552/4969] Bump Cucucmber example version to 5.5.0 (#2476) * Bump Cucucmber example version to 5.5.0 * Fixed wrong imports --- examples/cucumber/build.gradle | 4 ++-- .../org/testcontainsers/examples/CucumberTest.java | 4 ++-- .../java/org/testcontainsers/examples/Stepdefs.java | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 5d2caed8c2a..52c59229350 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - implementation 'io.cucumber:cucumber-java:4.8.0' - testImplementation 'io.cucumber:cucumber-junit:4.8.0' + testImplementation 'io.cucumber:cucumber-junit:5.5.0' + testImplementation 'io.cucumber:cucumber-java:5.5.0' testImplementation 'org.testcontainers:selenium' } diff --git a/examples/cucumber/src/test/java/org/testcontainsers/examples/CucumberTest.java b/examples/cucumber/src/test/java/org/testcontainsers/examples/CucumberTest.java index df1a449f1a9..0551b4dbf2e 100644 --- a/examples/cucumber/src/test/java/org/testcontainsers/examples/CucumberTest.java +++ b/examples/cucumber/src/test/java/org/testcontainsers/examples/CucumberTest.java @@ -1,7 +1,7 @@ package org.testcontainsers.examples; -import cucumber.api.CucumberOptions; -import cucumber.api.junit.Cucumber; +import io.cucumber.junit.Cucumber; +import io.cucumber.junit.CucumberOptions; import org.junit.runner.RunWith; @RunWith(Cucumber.class) diff --git a/examples/cucumber/src/test/java/org/testcontainsers/examples/Stepdefs.java b/examples/cucumber/src/test/java/org/testcontainsers/examples/Stepdefs.java index ee3c05d4457..ca70173ae92 100644 --- a/examples/cucumber/src/test/java/org/testcontainsers/examples/Stepdefs.java +++ b/examples/cucumber/src/test/java/org/testcontainsers/examples/Stepdefs.java @@ -1,11 +1,11 @@ package org.testcontainsers.examples; -import cucumber.api.Scenario; -import cucumber.api.java.After; -import cucumber.api.java.Before; -import cucumber.api.java.en.Given; -import cucumber.api.java.en.Then; -import cucumber.api.java.en.When; +import io.cucumber.java.After; +import io.cucumber.java.Before; +import io.cucumber.java.Scenario; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; From a51b1e0d457f652dcd236320b3e089bc2ee0228c Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Thu, 26 Mar 2020 17:36:24 +0100 Subject: [PATCH 0553/4969] Add custom exception message when HealthState not present in response (#2206) See ##2205 --- .../org/testcontainers/containers/ContainerState.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 043bae1d52f..ad006aa3b43 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.HealthState; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.ExposedPort; @@ -89,9 +90,12 @@ default boolean isHealthy() { try { InspectContainerResponse inspectContainerResponse = getCurrentContainerInfo(); - String healthStatus = inspectContainerResponse.getState().getHealth().getStatus(); + HealthState health = inspectContainerResponse.getState().getHealth(); + if (health == null) { + throw new RuntimeException("This container's image does not have a healthcheck declared, so health cannot be determined. Either amend the image or use another approach to determine whether containers are healthy."); + } - return healthStatus.equals(STATE_HEALTHY); + return STATE_HEALTHY.equals(health.getStatus()); } catch (DockerException e) { return false; } From 682bfac4e45b5a900f9ce9d6ca687af692ed6e8c Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 31 Mar 2020 14:41:08 +0200 Subject: [PATCH 0554/4969] Use `@DynamicPropertySource` in the Spring Boot example (#2495) --- examples/spring-boot/build.gradle | 2 +- .../com/example/AbstractIntegrationTest.java | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index bd9cc9e95f2..6cd1db0172a 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.5.RELEASE' + id 'org.springframework.boot' version '2.2.6.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java index 3b092a05ca0..29a1f51ffcc 100644 --- a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java +++ b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java @@ -4,6 +4,8 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.testcontainers.containers.GenericContainer; @@ -15,13 +17,13 @@ @ActiveProfiles("test") public abstract class AbstractIntegrationTest { - static { - GenericContainer redis = new GenericContainer("redis:3-alpine") - .withExposedPorts(6379); - redis.start(); - - System.setProperty("spring.redis.host", redis.getContainerIpAddress()); - System.setProperty("spring.redis.port", redis.getFirstMappedPort() + ""); + static GenericContainer redis = new GenericContainer("redis:3-alpine") + .withExposedPorts(6379); + @DynamicPropertySource + static void redisProperties(DynamicPropertyRegistry registry) { + redis.start(); + registry.add("spring.redis.host", redis::getContainerIpAddress); + registry.add("spring.redis.port", redis::getFirstMappedPort); } } From 7c635e0c86adf3c88bad081d124ea651736c0738 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:02:26 +0100 Subject: [PATCH 0555/4969] Bump mockito-core from 3.3.0 to 3.3.3 in /core (#2439) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.3.0 to 3.3.3. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.3.0...v3.3.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 0d452f5cc1d..6b9a1994ebd 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -159,7 +159,7 @@ dependencies { testCompile 'redis.clients:jedis:3.2.0' testCompile 'com.rabbitmq:amqp-client:5.8.0' testCompile 'org.mongodb:mongo-java-driver:3.12.1' - testCompile ('org.mockito:mockito-core:3.3.0') { + testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 0c02e71a507cdeb106aaf692ccc33bccd5729a6c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:02:35 +0100 Subject: [PATCH 0556/4969] Bump httpclient from 4.5.11 to 4.5.12 in /modules/spock (#2411) Bumps httpclient from 4.5.11 to 4.5.12. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 074711d8bda..19a2a78f1d5 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.2' - testCompile 'org.apache.httpcomponents:httpclient:4.5.11' + testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testRuntime 'org.postgresql:postgresql:42.2.10' testRuntime 'mysql:mysql-connector-java:8.0.19' From ab72e1b07759a292bdd256aa53f274f083aa3339 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:02:44 +0100 Subject: [PATCH 0557/4969] Bump postgresql from 42.2.10 to 42.2.12 in /modules/spock (#2502) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.10 to 42.2.12. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.10...REL42.2.12) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 19a2a78f1d5..2bcf7431808 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -13,7 +13,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testRuntime 'org.postgresql:postgresql:42.2.10' + testRuntime 'org.postgresql:postgresql:42.2.12' testRuntime 'mysql:mysql-connector-java:8.0.19' } From 7025e3fbdb934962454070b00b6444936c1f9ecd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:03:01 +0100 Subject: [PATCH 0558/4969] =?UTF-8?q?Bump=20elasticsearch-rest-client=20fr?= =?UTF-8?q?om=207.6.1=20to=207.6.2=20in=20/modules/=E2=80=A6=20(#2501)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.6.1 to 7.6.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.6.1...v7.6.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 75697344874..6deaf802112 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.2" testCompile "org.elasticsearch.client:transport:6.7.1" } From b3ec8a38a6da5c88b1989ba0d9b3765dcdb44675 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:03:09 +0100 Subject: [PATCH 0559/4969] Bump postgresql from 42.2.10 to 42.2.12 in /examples (#2500) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.10 to 42.2.12. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.10...REL42.2.12) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 081b2ac04fa..4f9a699504d 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:3.14.6' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.10' + testImplementation 'org.postgresql:postgresql:42.2.12' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From b96c84bc2ae71adea293a50015ccd26f520ddb81 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:03:24 +0100 Subject: [PATCH 0560/4969] =?UTF-8?q?Bump=20postgresql=20from=2042.2.10=20?= =?UTF-8?q?to=2042.2.12=20in=20/modules/junit-jupit=E2=80=A6=20(#2498)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.10 to 42.2.12. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.10...REL42.2.12) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7f6d4533509..445bdb3586d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } - testRuntime 'org.postgresql:postgresql:42.2.10' + testRuntime 'org.postgresql:postgresql:42.2.12' testRuntime 'mysql:mysql-connector-java:8.0.19' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.0' } From 2ef0ef28d39d327d351ad96623191fbcc921b238 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:03:39 +0100 Subject: [PATCH 0561/4969] Bump tomcat-jdbc from 9.0.31 to 9.0.33 in /modules/mysql (#2445) Bumps tomcat-jdbc from 9.0.31 to 9.0.33. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 11c522197b7..da609a1b535 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -5,7 +5,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.19' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.31' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' } From e4633d827d057e260d2324d7e9103cd1bcc894cd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:03:51 +0100 Subject: [PATCH 0562/4969] Bump mariadb-java-client from 2.5.4 to 2.6.0 in /modules/mariadb (#2461) Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.5.4 to 2.6.0. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index c479824ae47..505b67ba9e6 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { compile project(':jdbc') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.5.4' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.31' From d64e5790b51e1fdccba86f5c13a8c40b9f3af2a0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:03:57 +0100 Subject: [PATCH 0563/4969] Bump kafka-clients from 2.4.0 to 2.4.1 in /modules/kafka (#2424) Bumps kafka-clients from 2.4.0 to 2.4.1. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 3960cd96b69..cd6745e1eae 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.4.0' + testCompile 'org.apache.kafka:kafka-clients:2.4.1' testCompile 'org.assertj:assertj-core:3.15.0' testCompile 'com.google.guava:guava:23.0' } From 19d954c2ce08f9e762a52e55491bb4108e5a7c17 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:04:09 +0100 Subject: [PATCH 0564/4969] Bump testng from 7.1.1 to 7.2.0 in /examples (#2441) Bumps [testng](https://github.com/cbeust/testng) from 7.1.1 to 7.2.0. - [Release notes](https://github.com/cbeust/testng/releases) - [Changelog](https://github.com/cbeust/testng/blob/master/CHANGES.txt) - [Commits](https://github.com/cbeust/testng/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/redis-backed-cache-testng/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index efe713d5c0e..1779966c692 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' - testImplementation 'org.testng:testng:7.1.1' + testImplementation 'org.testng:testng:7.2.0' } test { From b6866be6c29795c9499e73c91b3a8b40b5c9966e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:04:23 +0100 Subject: [PATCH 0565/4969] Bump postgresql from 42.2.10 to 42.2.12 in /modules/postgresql (#2499) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.10 to 42.2.12. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.10...REL42.2.12) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 9acf9ead2aa..89d40fe6923 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { compile project(':jdbc') - testCompile 'org.postgresql:postgresql:42.2.10' + testCompile 'org.postgresql:postgresql:42.2.12' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' } From 5c2714f55c665bcd9f266b7039d39613f448ae65 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:04:45 +0100 Subject: [PATCH 0566/4969] Bump tomcat-jdbc from 9.0.31 to 9.0.33 in /modules/mariadb (#2444) Bumps tomcat-jdbc from 9.0.31 to 9.0.33. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 505b67ba9e6..be42121f3d8 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -6,6 +6,6 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.31' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' testCompile 'org.vibur:vibur-dbcp:25.0' } From a65789df7b77582f10e5255cc4002f6e5ce4c82e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:04:55 +0100 Subject: [PATCH 0567/4969] Bump okhttp from 3.14.6 to 3.14.7 in /examples (#2481) Bumps [okhttp](https://github.com/square/okhttp) from 3.14.6 to 3.14.7. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/docs/changelog_3x.md) - [Commits](https://github.com/square/okhttp/compare/parent-3.14.6...parent-3.14.7) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 4f9a699504d..e7bed23509d 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:3.14.6' + implementation 'com.squareup.okhttp3:okhttp:3.14.7' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.12' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From fad1667d53c1832cac79fe9f94a688a05d98a933 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2020 20:05:15 +0100 Subject: [PATCH 0568/4969] Bump rest-assured from 4.2.0 to 4.3.0 in /modules/vault (#2440) Bumps [rest-assured](https://github.com/jayway/rest-assured) from 4.2.0 to 4.3.0. - [Release notes](https://github.com/jayway/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/jayway/rest-assured/compare/rest-assured-4.2.0...rest-assured-4.3.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 1c8a4083b9c..bf85047ddd7 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { compile project(':testcontainers') testCompile 'com.bettercloud:vault-java-driver:5.1.0' - testCompile 'io.rest-assured:rest-assured:4.2.0' + testCompile 'io.rest-assured:rest-assured:4.3.0' testCompile 'org.assertj:assertj-core:3.15.0' } From 08e13bf2273ef6e2da004644ae7de6051e39ccda Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 4 Apr 2020 21:37:14 +0200 Subject: [PATCH 0569/4969] Bump Copyrights to 2020 (#2488) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 317bc0c749d..ec5ab97ca12 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ See [LICENSE](LICENSE). ## Copyright -Copyright (c) 2015 - 2019 Richard North and other authors. +Copyright (c) 2015 - 2020 Richard North and other authors. -MS SQL Server module is (c) 2017 - 2019 G DATA Software AG and other authors. +MS SQL Server module is (c) 2017 - 2020 G DATA Software AG and other authors. -Hashicorp Vault module is (c) 2017 - 2019 Capital One Services, LLC and other authors. +Hashicorp Vault module is (c) 2017 - 2020 Capital One Services, LLC and other authors. See [contributors](https://github.com/testcontainers/testcontainers-java/graphs/contributors) for all contributors. From 7eced8b44de8bda25c6312e4a08461d9514d9686 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 4 Apr 2020 20:45:58 +0100 Subject: [PATCH 0570/4969] Cache results of auth lookups (#2213) --- .../utility/RegistryAuthLocator.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index e8651167221..32b49bd8172 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -16,6 +16,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -38,6 +40,8 @@ public class RegistryAuthLocator { private final String commandExtension; private final File configFile; + private final Map> cache = new ConcurrentHashMap<>(); + /** * key - credential helper's name * value - helper's response for "credentials not found" use case @@ -97,9 +101,22 @@ static void setInstance(RegistryAuthLocator overrideInstance) { * @return an AuthConfig that is applicable to this specific image OR the defaultAuthConfig. */ public AuthConfig lookupAuthConfig(DockerImageName dockerImageName, AuthConfig defaultAuthConfig) { + final String registryName = effectiveRegistryName(dockerImageName); + log.debug("Looking up auth config for image: {} at registry: {}", dockerImageName, registryName); + + final Optional cachedAuth = cache.computeIfAbsent(registryName, __ -> lookupUncachedAuthConfig(registryName, dockerImageName)); - log.debug("Looking up auth config for image: {}", dockerImageName); + if (cachedAuth.isPresent()) { + log.debug("Cached auth found: [{}]", toSafeString(cachedAuth.get())); + return cachedAuth.get(); + } else { + log.debug("No matching Auth Configs - falling back to defaultAuthConfig [{}]", toSafeString(defaultAuthConfig)); + // otherwise, defaultAuthConfig should already contain any credentials available + return defaultAuthConfig; + } + } + private Optional lookupUncachedAuthConfig(String registryName, DockerImageName dockerImageName) { log.debug("RegistryAuthLocator has configFile: {} ({}) and commandPathPrefix: {}", configFile, configFile.exists() ? "exists" : "does not exist", @@ -107,37 +124,33 @@ public AuthConfig lookupAuthConfig(DockerImageName dockerImageName, AuthConfig d try { final JsonNode config = OBJECT_MAPPER.readTree(configFile); - final String registryName = effectiveRegistryName(dockerImageName); log.debug("registryName [{}] for dockerImageName [{}]", registryName, dockerImageName); // use helper preferentially (per https://docs.docker.com/engine/reference/commandline/cli/) final AuthConfig helperAuthConfig = authConfigUsingHelper(config, registryName); if (helperAuthConfig != null) { log.debug("found helper auth config [{}]", toSafeString(helperAuthConfig)); - return helperAuthConfig; + return Optional.of(helperAuthConfig); } // no credsHelper to use, using credsStore: final AuthConfig storeAuthConfig = authConfigUsingStore(config, registryName); if (storeAuthConfig != null) { log.debug("found creds store auth config [{}]", toSafeString(storeAuthConfig)); - return storeAuthConfig; + return Optional.of(storeAuthConfig); } // fall back to base64 encoded auth hardcoded in config file final AuthConfig existingAuthConfig = findExistingAuthConfig(config, registryName); if (existingAuthConfig != null) { log.debug("found existing auth config [{}]", toSafeString(existingAuthConfig)); - return existingAuthConfig; + return Optional.of(existingAuthConfig); } - - log.debug("no matching Auth Configs - falling back to defaultAuthConfig [{}]", toSafeString(defaultAuthConfig)); - // otherwise, defaultAuthConfig should already contain any credentials available } catch (Exception e) { log.warn("Failure when attempting to lookup auth config (dockerImageName: {}, configFile: {}. Falling back to docker-java default behaviour. Exception message: {}", dockerImageName, configFile, e.getMessage()); } - return defaultAuthConfig; + return Optional.empty(); } private AuthConfig findExistingAuthConfig(final JsonNode config, final String reposName) throws Exception { From 4c3bbd6c721ac45d36c73e77a232044de26badc3 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 5 Apr 2020 07:11:41 +0100 Subject: [PATCH 0571/4969] Pre-pull images required for Dockerfile/Compose image builds (#2201) * Pre-pull images required for Dockerfile/Compose image builds So that ImageFromDockerfile and Docker Compose can use images from authenticated registries when building temporary images Fixes #1799 * Restore wider test scope --- .../containers/DockerComposeContainer.java | 5 +- .../containers/ParsedDockerComposeFile.java | 71 ++++++++++++++++--- .../images/ParsedDockerfile.java | 67 +++++++++++++++++ .../images/builder/ImageFromDockerfile.java | 22 +++++- ...ParsedDockerComposeFileValidationTest.java | 18 ++++- .../images/ParsedDockerfileTest.java | 54 ++++++++++++++ core/src/test/resources/Dockerfile | 1 + ...gename-parsing-dockerfile-with-context.yml | 12 ++++ ...r-compose-imagename-parsing-dockerfile.yml | 10 +++ 9 files changed, 243 insertions(+), 17 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/images/ParsedDockerfile.java create mode 100644 core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java create mode 100644 core/src/test/resources/Dockerfile create mode 100644 core/src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml create mode 100644 core/src/test/resources/docker-compose-imagename-parsing-dockerfile.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 839db7c89db..61036f690cd 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -178,12 +178,13 @@ private void pullImages() { // (a) as a workaround for https://github.com/docker/compose/issues/5854, which prevents authenticated image pulls being possible when credential helpers are in use // (b) so that credential helper-based auth still works when compose is running from within a container parsedComposeFiles.stream() - .flatMap(it -> it.getServiceImageNames().stream()) + .flatMap(it -> it.getDependencyImageNames().stream()) .forEach(imageName -> { try { + log.info("Preemptively checking local images for '{}', referenced via a compose file or transitive Dockerfile. If not available, it will be pulled.", imageName); DockerClientFactory.instance().checkAndPullImage(dockerClient, imageName); } catch (Exception e) { - log.warn("Failed to pull image '{}'. Exception message was {}", imageName, e.getMessage()); + log.warn("Unable to pre-fetch an image ({}) depended upon by Docker Compose build - startup will continue but may fail. Exception message was: {}", imageName, e.getMessage()); } }); } diff --git a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java index 838607d8337..8f88724647f 100644 --- a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java +++ b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java @@ -5,10 +5,13 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; +import org.testcontainers.images.ParsedDockerfile; import org.yaml.snakeyaml.Yaml; import java.io.File; import java.io.FileInputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -23,9 +26,10 @@ class ParsedDockerComposeFile { private final Map composeFileContent; private final String composeFileName; + private final File composeFile; @Getter - private Set serviceImageNames = new HashSet<>(); + private Set dependencyImageNames = new HashSet<>(); ParsedDockerComposeFile(File composeFile) { Yaml yaml = new Yaml(); @@ -35,7 +39,7 @@ class ParsedDockerComposeFile { throw new IllegalArgumentException("Unable to parse YAML file from " + composeFile.getAbsolutePath(), e); } this.composeFileName = composeFile.getAbsolutePath(); - + this.composeFile = composeFile; parseAndValidate(); } @@ -43,6 +47,7 @@ class ParsedDockerComposeFile { ParsedDockerComposeFile(Map testContent) { this.composeFileContent = testContent; this.composeFileName = ""; + this.composeFile = new File("."); parseAndValidate(); } @@ -80,15 +85,61 @@ private void parseAndValidate() { } final Map serviceDefinitionMap = (Map) serviceDefinition; - if (serviceDefinitionMap.containsKey("container_name")) { - throw new IllegalStateException(String.format( - "Compose file %s has 'container_name' property set for service '%s' but this property is not supported by Testcontainers, consider removing it", - composeFileName, - serviceName - )); + + validateNoContainerNameSpecified(serviceName, serviceDefinitionMap); + findServiceImageName(serviceDefinitionMap); + findImageNamesInDockerfile(serviceDefinitionMap); + } + } + + private void validateNoContainerNameSpecified(String serviceName, Map serviceDefinitionMap) { + if (serviceDefinitionMap.containsKey("container_name")) { + throw new IllegalStateException(String.format( + "Compose file %s has 'container_name' property set for service '%s' but this property is not supported by Testcontainers, consider removing it", + composeFileName, + serviceName + )); + } + } + + private void findServiceImageName(Map serviceDefinitionMap) { + if (serviceDefinitionMap.containsKey("image") && serviceDefinitionMap.get("image") instanceof String) { + final String imageName = (String) serviceDefinitionMap.get("image"); + log.debug("Resolved dependency image for Docker Compose in {}: {}", composeFileName, imageName); + dependencyImageNames.add(imageName); + } + } + + private void findImageNamesInDockerfile(Map serviceDefinitionMap) { + final Object buildNode = serviceDefinitionMap.get("build"); + Path dockerfilePath = null; + + if (buildNode instanceof Map) { + final Map buildElement = (Map) buildNode; + final Object dockerfileRelativePath = buildElement.get("dockerfile"); + final Object contextRelativePath = buildElement.get("context"); + if (dockerfileRelativePath instanceof String && contextRelativePath instanceof String) { + dockerfilePath = composeFile + .getParentFile() + .toPath() + .resolve((String) contextRelativePath) + .resolve((String) dockerfileRelativePath) + .normalize(); } - if (serviceDefinitionMap.containsKey("image") && serviceDefinitionMap.get("image") instanceof String) { - serviceImageNames.add((String) serviceDefinitionMap.get("image")); + } else if (buildNode instanceof String) { + dockerfilePath = composeFile + .getParentFile() + .toPath() + .resolve((String) buildNode) + .resolve("./Dockerfile") + .normalize(); + } + + if (dockerfilePath != null && Files.exists(dockerfilePath)) { + Set resolvedImageNames = new ParsedDockerfile(dockerfilePath).getDependencyImageNames(); + if (!resolvedImageNames.isEmpty()) { + log.debug("Resolved Dockerfile dependency images for Docker Compose in {} -> {}: {}", composeFileName, dockerfilePath, resolvedImageNames); + this.dependencyImageNames.addAll(resolvedImageNames); } } } diff --git a/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java b/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java new file mode 100644 index 00000000000..1ad43813757 --- /dev/null +++ b/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java @@ -0,0 +1,67 @@ +package org.testcontainers.images; + +import com.google.common.annotations.VisibleForTesting; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Representation of a Dockerfile, with partial parsing for extraction of a minimal set of data. + */ +@Slf4j +public class ParsedDockerfile { + + private static final Pattern FROM_LINE_PATTERN = Pattern.compile("FROM ([^\\s]+).*"); + + private final Path dockerFilePath; + + @Getter + private Set dependencyImageNames = Collections.emptySet(); + + public ParsedDockerfile(Path dockerFilePath) { + this.dockerFilePath = dockerFilePath; + parse(read()); + } + + @VisibleForTesting + ParsedDockerfile(List lines) { + this.dockerFilePath = Paths.get("dummy.Dockerfile"); + parse(lines); + } + + private List read() { + if (!Files.exists(dockerFilePath)) { + log.warn("Tried to parse Dockerfile at path {} but none was found", dockerFilePath); + return Collections.emptyList(); + } + + try { + return Files.readAllLines(dockerFilePath); + } catch (IOException e) { + log.warn("Unable to read Dockerfile at path {}", dockerFilePath, e); + return Collections.emptyList(); + } + } + + private void parse(List lines) { + dependencyImageNames = lines.stream() + .map(FROM_LINE_PATTERN::matcher) + .filter(Matcher::matches) + .map(matcher -> matcher.group(1)) + .collect(Collectors.toSet()); + + if (!dependencyImageNames.isEmpty()) { + log.debug("Found dependency images in Dockerfile {}: {}", dockerFilePath, dependencyImageNames); + } + } +} diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index ded64439a64..1140247960a 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -2,10 +2,8 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.BuildImageCmd; -import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.model.BuildResponseItem; import com.github.dockerjava.core.command.BuildImageResultCallback; -import com.google.common.collect.Sets; import lombok.Cleanup; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -14,6 +12,7 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; +import org.testcontainers.images.ParsedDockerfile; import org.testcontainers.images.builder.traits.BuildContextBuilderTrait; import org.testcontainers.images.builder.traits.ClasspathTrait; import org.testcontainers.images.builder.traits.DockerfileTrait; @@ -28,6 +27,7 @@ import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.nio.file.Path; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -51,6 +51,7 @@ public class ImageFromDockerfile extends LazyFuture implements private final Map buildArgs = new HashMap<>(); private Optional dockerFilePath = Optional.empty(); private Optional dockerfile = Optional.empty(); + private Set dependencyImageNames = Collections.emptySet(); public ImageFromDockerfile() { this("testcontainers/" + Base58.randomString(16).toLowerCase()); @@ -81,6 +82,17 @@ protected final String resolve() { Logger logger = DockerLoggerFactory.getLogger(dockerImageName); DockerClient dockerClient = DockerClientFactory.instance().client(); + + dependencyImageNames.forEach(imageName -> { + try { + log.info("Pre-emptively checking local images for '{}', referenced via a Dockerfile. If not available, it will be pulled.", imageName); + DockerClientFactory.instance().checkAndPullImage(dockerClient, imageName); + } catch (Exception e) { + log.warn("Unable to pre-fetch an image ({}) depended upon by Dockerfile - image build will continue but may fail. Exception message was: {}", imageName, e.getMessage()); + } + }); + + try { if (deleteOnExit) { ResourceReaper.instance().registerImageForCleanup(dockerImageName); @@ -139,7 +151,11 @@ public void onNext(BuildResponseItem item) { protected void configure(BuildImageCmd buildImageCmd) { buildImageCmd.withTag(this.getDockerImageName()); this.dockerFilePath.ifPresent(buildImageCmd::withDockerfilePath); - this.dockerfile.ifPresent(p -> buildImageCmd.withDockerfile(p.toFile())); + this.dockerfile.ifPresent(p -> { + buildImageCmd.withDockerfile(p.toFile()); + dependencyImageNames = new ParsedDockerfile(p).getDependencyImageNames(); + }); + this.buildArgs.forEach(buildImageCmd::withBuildArg); } diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java index c553d250ec9..9a8421086f1 100644 --- a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -76,13 +76,27 @@ public void shouldIgnoreUnknownStructure() { public void shouldObtainImageNamesV1() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v1.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - assertEquals("all defined service names are found", Sets.newHashSet("redis", "mysql"), parsedFile.getServiceImageNames()); + assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "postgres"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, postgres from Dockerfile build } @Test public void shouldObtainImageNamesV2() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - assertEquals("all defined service names are found", Sets.newHashSet("redis", "mysql"), parsedFile.getServiceImageNames()); + assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "postgres"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, postgres from Dockerfile build + } + + @Test + public void shouldObtainImageFromDockerfileBuild() { + File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile.yml"); + ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); + assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "alpine:3.2"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, alpine:3.2 from Dockerfile build + } + + @Test + public void shouldObtainImageFromDockerfileBuildWithContext() { + File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml"); + ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); + assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "alpine:3.2"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, alpine:3.2 from Dockerfile build } } diff --git a/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java new file mode 100644 index 00000000000..e2b97f9fab7 --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java @@ -0,0 +1,54 @@ +package org.testcontainers.images; + +import com.google.common.collect.Sets; +import org.junit.Test; + +import java.nio.file.Paths; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +public class ParsedDockerfileTest { + + @Test + public void doesSimpleParsing() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage", "RUN something")); + assertEquals("extracts a single image name", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + } + + @Test + public void handlesTags() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage:tag", "RUN something")); + assertEquals("retains tags in image names", Sets.newHashSet("someimage:tag"), parsedDockerfile.getDependencyImageNames()); + } + + @Test + public void handlesDigests() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage@sha256:abc123", "RUN something")); + assertEquals("retains digests in image names", Sets.newHashSet("someimage@sha256:abc123"), parsedDockerfile.getDependencyImageNames()); + } + + @Test + public void ignoringCommentedFromLines() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage", "#FROM somethingelse")); + assertEquals("ignores commented from lines", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + } + + @Test + public void ignoringBuildStageNames() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage --as=base", "RUN something", "FROM nextimage", "RUN something")); + assertEquals("ignores build stage names and allows multiple images to be extracted", Sets.newHashSet("someimage", "nextimage"), parsedDockerfile.getDependencyImageNames()); + } + + @Test + public void handlesGracefullyIfNoFromLine() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("RUN something", "# is this even a valid Dockerfile?")); + assertEquals("handles invalid Dockerfiles gracefully", Sets.newHashSet(), parsedDockerfile.getDependencyImageNames()); + } + + @Test + public void handlesGracefullyIfDockerfileNotFound() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(Paths.get("nonexistent.Dockerfile")); + assertEquals("handles missing Dockerfiles gracefully", Sets.newHashSet(), parsedDockerfile.getDependencyImageNames()); + } +} diff --git a/core/src/test/resources/Dockerfile b/core/src/test/resources/Dockerfile new file mode 100644 index 00000000000..d3f2fcb60f7 --- /dev/null +++ b/core/src/test/resources/Dockerfile @@ -0,0 +1 @@ +FROM postgres diff --git a/core/src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml b/core/src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml new file mode 100644 index 00000000000..4e86b83720b --- /dev/null +++ b/core/src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml @@ -0,0 +1,12 @@ +version: "2.1" +services: + redis: + image: redis + mysql: + image: mysql + custom: + build: + context: compose-dockerfile + dockerfile: Dockerfile +networks: + custom_network: {} diff --git a/core/src/test/resources/docker-compose-imagename-parsing-dockerfile.yml b/core/src/test/resources/docker-compose-imagename-parsing-dockerfile.yml new file mode 100644 index 00000000000..46d3da26f4c --- /dev/null +++ b/core/src/test/resources/docker-compose-imagename-parsing-dockerfile.yml @@ -0,0 +1,10 @@ +version: "2.1" +services: + redis: + image: redis + mysql: + image: mysql + custom: + build: compose-dockerfile +networks: + custom_network: {} From 5b4cda1b5d5bc0316237d802c4c4b745121fe9ea Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2020 07:12:31 +0100 Subject: [PATCH 0572/4969] Bump mockito-core from 3.3.0 to 3.3.3 in /modules/junit-jupiter (#2437) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.3.0 to 3.3.3. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.3.0...v3.3.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 445bdb3586d..d0a573adcc8 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'redis.clients:jedis:3.2.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.11' - testCompile ('org.mockito:mockito-core:3.3.0') { + testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } From 92fb4e2be425f43685569754f2a572c822e050d9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2020 07:12:40 +0100 Subject: [PATCH 0573/4969] =?UTF-8?q?Bump=20aws-java-sdk-logs=20from=201.1?= =?UTF-8?q?1.737=20to=201.11.759=20in=20/modules/lo=E2=80=A6=20(#2518)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.737 to 1.11.759. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.737...1.11.759) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 49e586b19f7..1e9e3cd9121 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,5 +6,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.737' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.759' } From 08bafcfdae0caab213de28b8b3adedb7b4e35924 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 5 Apr 2020 18:58:30 +0100 Subject: [PATCH 0574/4969] Fix `update-docs-version.yml` script (#2519) Using checkout action to check out master branch --- .github/workflows/update-docs-version.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 7268f72f961..cce6e5b9bf1 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -9,8 +9,8 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - name: Checkout master - run: git checkout master + with: + ref: master - name: Update latest_version property in mkdocs.yml run: | sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml From a09f4d50487bf9b9e9807af0dbf59b802f7490ee Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 5 Apr 2020 18:59:39 +0100 Subject: [PATCH 0575/4969] Expand Container `dependsOn` parameters to accept `Iterable` (#2259) * Expand `dependsOn` parameters to accept `Iterable` * Reinstate a `dependsOn(List)` method, for binary backwards compatibility * Reinstate `deepStart(Collection)` method --- .../containers/GenericContainer.java | 27 +++++++++---------- .../testcontainers/lifecycle/Startables.java | 15 +++++++++-- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 03d03759506..945d1e1aff2 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -26,9 +26,6 @@ import lombok.NonNull; import lombok.Setter; import lombok.SneakyThrows; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; -import org.apache.commons.compress.utils.IOUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; @@ -42,7 +39,6 @@ import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.UnstableAPI; -import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.startupcheck.IsRunningStartupCheckStrategy; import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy; @@ -51,8 +47,8 @@ import org.testcontainers.containers.wait.Wait; import org.testcontainers.containers.wait.WaitStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; +import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.images.RemoteDockerImage; -import org.testcontainers.images.builder.Transferable; import org.testcontainers.lifecycle.Startable; import org.testcontainers.lifecycle.Startables; import org.testcontainers.lifecycle.TestDescription; @@ -64,14 +60,9 @@ import org.testcontainers.utility.PathUtils; import org.testcontainers.utility.ResourceReaper; import org.testcontainers.utility.TestcontainersConfiguration; -import org.testcontainers.utility.ThrowingFunction; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; @@ -82,7 +73,6 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -266,22 +256,29 @@ public void setImage(Future image) { } /** - * @see #dependsOn(List) + * @see #dependsOn(Iterable) */ public SELF dependsOn(Startable... startables) { Collections.addAll(dependencies, startables); return self(); } + /** + * @see #dependsOn(Iterable) + */ + public SELF dependsOn(List startables) { + return this.dependsOn((Iterable) startables); + } + /** * Delays this container's creation and start until provided {@link Startable}s start first. * Note that the circular dependencies are not supported. * * @param startables a list of {@link Startable} to depend on - * @see Startables#deepStart(Collection) + * @see Startables#deepStart(Iterable) */ - public SELF dependsOn(List startables) { - dependencies.addAll(startables); + public SELF dependsOn(Iterable startables) { + startables.forEach(dependencies::add); return self(); } diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startables.java b/core/src/main/java/org/testcontainers/lifecycle/Startables.java index b20c5c91b54..292e1ab17b3 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/Startables.java +++ b/core/src/main/java/org/testcontainers/lifecycle/Startables.java @@ -5,9 +5,13 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; +import java.util.stream.StreamSupport; @UtilityClass public class Startables { @@ -28,7 +32,14 @@ public Thread newThread(Runnable r) { * @see #deepStart(Stream) */ public CompletableFuture deepStart(Collection startables) { - return deepStart(startables.stream()); + return deepStart((Iterable) startables); + } + + /** + * @see #deepStart(Stream) + */ + public CompletableFuture deepStart(Iterable startables) { + return deepStart(StreamSupport.stream(startables.spliterator(), false)); } /** From f5948a9085a75e875472c7b6be8a55f4861271a2 Mon Sep 17 00:00:00 2001 From: Michael Kutz Date: Sat, 11 Apr 2020 13:33:16 +0200 Subject: [PATCH 0576/4969] Remove unidiomatic public modifier in Groovy example code (#2238) The `public` access modifier is quite unidiomatic in Groovy code. Co-authored-by: Kevin Wittek --- .../src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy index d8c056b5070..c2537a948d5 100644 --- a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy +++ b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy @@ -10,7 +10,7 @@ class RedisBackedCacheIntTest extends Specification { private RedisBackedCache underTest // init { - public GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") + GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") .withExposedPorts(6379) // } From 17b9ffc092629b86b301580fa3a8fba18271daa2 Mon Sep 17 00:00:00 2001 From: Mitchell Just Date: Sat, 11 Apr 2020 21:40:14 +1000 Subject: [PATCH 0577/4969] Move static config from `configure()` to constructors (#2473) --- .../containers/ClickHouseContainer.java | 3 --- .../testcontainers/containers/Db2Container.java | 4 ++-- .../containers/InfluxDBContainer.java | 4 ++-- .../containers/MariaDBContainer.java | 4 ++-- .../containers/MSSQLServerContainer.java | 4 +--- .../testcontainers/containers/MySQLContainer.java | 2 +- .../testcontainers/containers/Neo4jContainer.java | 4 ++-- .../testcontainers/containers/NginxContainer.java | 15 ++++++++------- .../containers/OracleContainer.java | 6 +----- .../containers/OrientDBContainer.java | 3 ++- .../containers/PostgreSQLContainer.java | 3 ++- .../containers/PrestoContainer.java | 7 ++----- 12 files changed, 25 insertions(+), 34 deletions(-) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 0fd6174bf3b..9364ecc4d14 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -26,10 +26,7 @@ public ClickHouseContainer() { public ClickHouseContainer(String dockerImageName) { super(dockerImageName); - } - @Override - protected void configure() { withExposedPorts(HTTP_PORT, NATIVE_PORT); waitingFor( new HttpWaitStrategy() diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index 429cc060094..13ef72c328e 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -37,6 +37,8 @@ public Db2Container(String imageName) { this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*Setup has completed\\..*") .withStartupTimeout(Duration.of(10, ChronoUnit.MINUTES)); + + addExposedPort(DB2_PORT); } @Override @@ -52,8 +54,6 @@ protected void configure() { acceptLicense(); } - addExposedPort(DB2_PORT); - addEnv("DBNAME", databaseName); addEnv("DB2INSTANCE", username); addEnv("DB2INST1_PASSWORD", password); diff --git a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java index ee5b449f961..c3ac909f2d4 100644 --- a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java +++ b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java @@ -36,12 +36,12 @@ public InfluxDBContainer(final String version) { waitStrategy = new WaitAllStrategy() .withStrategy(Wait.forHttp("/ping").withBasicCredentials(username, password).forStatusCode(204)) .withStrategy(Wait.forListeningPort()); + + addExposedPort(INFLUXDB_PORT); } @Override protected void configure() { - addExposedPort(INFLUXDB_PORT); - addEnv("INFLUXDB_ADMIN_USER", admin); addEnv("INFLUXDB_ADMIN_PASSWORD", adminPassword); diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index c41136c0bf2..be1b3d3d44d 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -24,6 +24,7 @@ public MariaDBContainer() { public MariaDBContainer(String dockerImageName) { super(dockerImageName); + addExposedPort(MARIADB_PORT); } @Override @@ -35,7 +36,6 @@ protected Integer getLivenessCheckPort() { protected void configure() { optionallyMapResourceParameterAsVolume(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, "/etc/mysql/conf.d", "mariadb-default-conf"); - addExposedPort(MARIADB_PORT); addEnv("MYSQL_DATABASE", databaseName); addEnv("MYSQL_USER", username); if (password != null && !password.isEmpty()) { @@ -83,7 +83,7 @@ public SELF withConfigurationOverride(String s) { parameters.put(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, s); return self(); } - + @Override public SELF withDatabaseName(final String databaseName) { this.databaseName = databaseName; diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index ad1a7d19090..afe3f5b8651 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -36,6 +36,7 @@ public MSSQLServerContainer(final String dockerImageName) { super(dockerImageName); withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); + addExposedPort(MS_SQL_SERVER_PORT); } @Override @@ -45,11 +46,8 @@ protected Integer getLivenessCheckPort() { @Override protected void configure() { - addExposedPort(MS_SQL_SERVER_PORT); - LicenseAcceptance.assertLicenseAccepted(this.getDockerImageName()); addEnv("ACCEPT_EULA", "Y"); - addEnv("SA_PASSWORD", password); } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index fa2e8626b0d..a8549672ff3 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -27,6 +27,7 @@ public MySQLContainer() { public MySQLContainer(String dockerImageName) { super(dockerImageName); + addExposedPort(MYSQL_PORT); } @NotNull @@ -40,7 +41,6 @@ protected void configure() { optionallyMapResourceParameterAsVolume(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, "/etc/mysql/conf.d", "mysql-default-conf"); - addExposedPort(MYSQL_PORT); addEnv("MYSQL_DATABASE", databaseName); addEnv("MYSQL_USER", username); if (password != null && !password.isEmpty()) { diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index fc545122219..0c16927dba8 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -87,6 +87,8 @@ public Neo4jContainer(String dockerImageName) { .withStrategy(waitForBolt) .withStrategy(waitForHttp) .withStartupTimeout(Duration.ofMinutes(2)); + + addExposedPorts(DEFAULT_BOLT_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); } @Override @@ -100,8 +102,6 @@ public Set getLivenessCheckPortNumbers() { @Override protected void configure() { - addExposedPorts(DEFAULT_BOLT_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); - boolean emptyAdminPassword = this.adminPassword == null || this.adminPassword.isEmpty(); String neo4jAuth = emptyAdminPassword ? "none" : String.format(AUTH_FORMAT, this.adminPassword); addEnv("NEO4J_AUTH", neo4jAuth); diff --git a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java index 1badffa1cee..bedf040869f 100644 --- a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java +++ b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java @@ -16,7 +16,14 @@ public class NginxContainer> extends GenericCo private static final int NGINX_DEFAULT_PORT = 80; public NginxContainer() { - super("nginx:1.9.4"); + this("nginx:1.9.4"); + } + + public NginxContainer(String dockerImageName) { + super(dockerImageName); + + addExposedPort(NGINX_DEFAULT_PORT); + setCommand("nginx", "-g", "daemon off;"); } @NotNull @@ -25,12 +32,6 @@ protected Set getLivenessCheckPorts() { return Collections.singleton(getMappedPort(80)); } - @Override - protected void configure() { - addExposedPort(NGINX_DEFAULT_PORT); - setCommand("nginx", "-g", "daemon off;"); - } - public URL getBaseUrl(String scheme, int port) throws MalformedURLException { return new URL(scheme + "://" + getContainerIpAddress() + ":" + getMappedPort(port)); } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index ea0eee1a2ff..bad22af2511 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -46,6 +46,7 @@ public OracleContainer(Future dockerImageName) { super(dockerImageName); withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); + addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT); } @Override @@ -53,11 +54,6 @@ protected Integer getLivenessCheckPort() { return getMappedPort(ORACLE_PORT); } - @Override - protected void configure() { - addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT); - } - @Override public String getDriverClassName() { return "oracle.jdbc.OracleDriver"; diff --git a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java index b368d96bf8c..ca0180640ce 100644 --- a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java +++ b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java @@ -66,11 +66,12 @@ public OrientDBContainer(@NonNull String dockerImageName) { .withStrategy(Wait.forListeningPort()) .withStrategy(waitForHttp) .withStartupTimeout(Duration.ofMinutes(2)); + + addExposedPorts(DEFAULT_BINARY_PORT, DEFAULT_HTTP_PORT); } @Override protected void configure() { - addExposedPorts(DEFAULT_BINARY_PORT, DEFAULT_HTTP_PORT); addEnv("ORIENTDB_ROOT_PASSWORD", serverPassword); } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index cef66d0c492..0fae3a16f4a 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -38,6 +38,8 @@ public PostgreSQLContainer(final String dockerImageName) { .withTimes(2) .withStartupTimeout(Duration.of(60, SECONDS)); this.setCommand("postgres", "-c", FSYNC_OFF_OPTION); + + addExposedPort(POSTGRESQL_PORT); } @NotNull @@ -48,7 +50,6 @@ protected Set getLivenessCheckPorts() { @Override protected void configure() { - addExposedPort(POSTGRESQL_PORT); addEnv("POSTGRES_DB", databaseName); addEnv("POSTGRES_USER", username); addEnv("POSTGRES_PASSWORD", password); diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index 186acb18af6..0f2a82b9b9d 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -32,6 +32,8 @@ public PrestoContainer(final String dockerImageName) { this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*io.prestosql.server.PrestoServer\\s+======== SERVER STARTED ========.*") .withStartupTimeout(Duration.of(60, SECONDS)); + + addExposedPort(PRESTO_PORT); } @NotNull @@ -40,11 +42,6 @@ protected Set getLivenessCheckPorts() { return new HashSet<>(getMappedPort(PRESTO_PORT)); } - @Override - protected void configure() { - addExposedPort(PRESTO_PORT); - } - @Override public String getDriverClassName() { return "io.prestosql.jdbc.PrestoDriver"; From ecdbc11c2d637d3dec50b32655958a9a8ef1e807 Mon Sep 17 00:00:00 2001 From: Sandra Parsick Date: Sat, 11 Apr 2020 13:41:55 +0200 Subject: [PATCH 0578/4969] add more information for using registry mirror (#2477) --- docs/features/configuration.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/features/configuration.md b/docs/features/configuration.md index cd01b99b1c7..ad039528b5d 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -48,6 +48,11 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` Another possibility is to set up a registry mirror in your environment so that all images are pulled from there and not directly from Docker Hub. For more information, see the [official Docker documentation about "Registry as a pull through cache"](https://docs.docker.com/registry/recipes/mirror/). +!!!tip + Registry mirror currently only works for Docker images with image name that has no registry specified (for example, for Docker image `mariadb:10.3.6`, it works, for Docker image `quay.io/testcontainers/ryuk:0.2.3`, not). + Workaround is to to configure the affected Docker image in `.testcontainers.properties`. + For example: `ryuk.container.image = testcontainers/ryuk:0.2.3` or `ryuk.container.image = /testcontainers/ryuk:0.2.3` + ## Customizing Ryuk resource reaper > **ryuk.container.image = quay.io/testcontainers/ryuk:0.2.3** From 21ba44813164aff012993be643ee3ed12ffac107 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 11 Apr 2020 13:49:35 +0200 Subject: [PATCH 0579/4969] Add ciMate (#2550) --- .circleci/config.yml | 11 +++++++++++ .github/workflows/ci.yml | 8 ++++++++ azure-pipelines.yml | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ee4097934a..c4302911f40 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,6 +9,13 @@ jobs: command: ./gradlew testcontainers:build -x test -x check - run: command: ./gradlew testcontainers:check --scan + - run: &ciMate + name: aggregate test reports with ciMate + when: always + command: | + wget -q https://get.cimate.io/release/linux/cimate + chmod +x cimate + ./cimate "**/TEST-*.xml" - run: name: Save test results command: | @@ -29,6 +36,7 @@ jobs: --scan environment: TZ: /usr/share/zoneinfo/ETC/UTC + - run: *ciMate - run: name: Save test results command: | @@ -48,6 +56,7 @@ jobs: command: ./gradlew jdbc-test:check --scan environment: TZ: /usr/share/zoneinfo/ETC/UTC + - run: *ciMate - run: name: Save test results command: | @@ -65,6 +74,7 @@ jobs: - checkout - run: command: ./gradlew selenium:check --scan + - run: *ciMate - run: name: Save test results command: | @@ -82,6 +92,7 @@ jobs: - checkout - run: command: cd examples && ./gradlew check + - run: *ciMate - run: name: Save test results command: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5618be1230d..1a0a97d05f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,3 +18,11 @@ jobs: -w "$PWD" \ openjdk:8-jdk-alpine \ ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' + - name: aggregate test reports with ciMate + if: always() + env: + CIMATE_PROJECT_ID: 2348n4vl + run: | + wget -q https://get.cimate.io/release/linux/cimate + chmod +x cimate + ./cimate "**/TEST-*.xml" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 68330550ee1..8ab7bc98db5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,6 +13,8 @@ jobs: tasks: 'testcontainers:check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' + - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" + condition: succeededOrFailed() - job: jdbc steps: - task: Gradle@2 @@ -27,6 +29,8 @@ jobs: tasks: 'jdbc-test:check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' + - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" + condition: succeededOrFailed() - job: modules steps: - task: Gradle@2 @@ -41,3 +45,5 @@ jobs: tasks: 'check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' + - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" + condition: succeededOrFailed() From 7f3c4d2e0b24105a39e9b9c00117a9cf1de4838b Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 11 Apr 2020 20:06:11 +0200 Subject: [PATCH 0580/4969] set `outputPerTestCase` --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index c8b2267a049..a55753aa7f5 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,12 @@ subprojects { } } + tasks.withType(Test).all { + reports { + junitXml.outputPerTestCase = true + } + } + // Ensure that Javadoc generation is always tested check.dependsOn(javadoc) From 09cc191c137f91c22b55796ab1067898286bde52 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 11 Apr 2020 20:46:15 +0200 Subject: [PATCH 0581/4969] disable ciMate on non-Linux AZP builds --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8ab7bc98db5..5572a4096a3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,7 +14,7 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: succeededOrFailed() + condition: and(succeededOrFailed(),eq(variables.os, 'Linux')) - job: jdbc steps: - task: Gradle@2 @@ -30,7 +30,7 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: succeededOrFailed() + condition: and(succeededOrFailed(), eq(variables.os, 'Linux')) - job: modules steps: - task: Gradle@2 @@ -46,4 +46,4 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: succeededOrFailed() + condition: and(succeededOrFailed(), eq(variables.os, 'Linux')) From dd662ce494c9600c210a7e85006f90729d4163fe Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Apr 2020 13:26:08 +0200 Subject: [PATCH 0582/4969] fix the OS variable in AZP --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5572a4096a3..c56ae9fde36 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,7 +14,7 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: and(succeededOrFailed(),eq(variables.os, 'Linux')) + condition: and(succeededOrFailed(),eq(variables['Agent.OS'], 'Linux')) - job: jdbc steps: - task: Gradle@2 @@ -30,7 +30,7 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: and(succeededOrFailed(), eq(variables.os, 'Linux')) + condition: and(succeededOrFailed(), eq(variables['Agent.OS'], 'Linux')) - job: modules steps: - task: Gradle@2 @@ -46,4 +46,4 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: and(succeededOrFailed(), eq(variables.os, 'Linux')) + condition: and(succeededOrFailed(), eq(variables['Agent.OS'], 'Linux')) From c90a9f996bafbb7f6f26cd875fc936dd84f08a55 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Sun, 12 Apr 2020 15:18:20 +0200 Subject: [PATCH 0583/4969] Temporarily ignore DB2 test - unrelated CI disk space issues (#2557) * Temporary ignore DB2 test in JDBCDriverTest.data We have some problems with file space running out on CI, so the jdbc-test module, pulling a lot of database images, can potentially break the build. * Also ignore SimpleDb2Test --- .../src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java | 2 +- .../src/test/java/org/testcontainers/junit/SimpleDb2Test.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java index ca55a1d1841..c96ce251a63 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java @@ -67,7 +67,7 @@ public static Iterable data() { {"jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken)}, {"jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", EnumSet.noneOf(Options.class)}, {"jdbc:tc:cockroach://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)} +// {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)} }); } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java index c686f979b79..60ad9a23a27 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java @@ -2,6 +2,7 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.Db2Container; @@ -13,6 +14,7 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +@Ignore("Disabled since we had problems with CI disk space filling up from images in jdbc-test module") public class SimpleDb2Test { @Rule From ee05f4ab6780a7490112d26de5f375d70f4949e6 Mon Sep 17 00:00:00 2001 From: Alex Stockinger Date: Sun, 12 Apr 2020 15:24:23 +0200 Subject: [PATCH 0584/4969] Remove unused JEE deps (#2505) Two compile dependencies referencing JEE artifacts don't seem to be required for compilation. This PR removes them from the build. --- core/build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 6b9a1994ebd..f2d7efcc1a9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -115,10 +115,7 @@ dependencies { compile 'junit:junit:4.12' compile 'org.slf4j:slf4j-api:1.7.30' compile 'org.jetbrains:annotations:17.0.0' - compile 'javax.annotation:javax.annotation-api:1.3.2' compile 'org.apache.commons:commons-compress:1.20' - // Added for JDK9 compatibility since it's missing this package - compile 'javax.xml.bind:jaxb-api:2.3.1' compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') } From 0b7e72feeade14168cc52e8c8ac3100f9b1f4066 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Apr 2020 16:01:20 +0200 Subject: [PATCH 0585/4969] Update to docker-java 3.2.1 (#2435) --- build.gradle | 5 ++++- core/build.gradle | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a55753aa7f5..4fbaf42c160 100644 --- a/build.gradle +++ b/build.gradle @@ -107,7 +107,10 @@ subprojects { for (entry in jf.entries()) { def name = entry.name if (name.endsWith(".class")) { - packages.add(name.substring(0, name.lastIndexOf('/'))) + def index = name.lastIndexOf('/') + if (index != -1) { + packages.add(name.substring(0, index)) + } } } jf.close() diff --git a/core/build.gradle b/core/build.gradle index f2d7efcc1a9..01575f0d351 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -135,7 +135,7 @@ dependencies { exclude(group: "net.java.dev.jna") } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.0') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.1') { exclude(group: 'net.java.dev.jna') exclude(group: 'com.google.code.findbug') exclude(group: 'org.slf4j') From 3833ce483aad18ccb1809453da638b22f04c5ad8 Mon Sep 17 00:00:00 2001 From: Andrew Guibert Date: Sun, 12 Apr 2020 09:01:57 -0500 Subject: [PATCH 0586/4969] Add more clear warning message instructing users how to enable reusable containers (#2422) * Add more clear warning message instructing users how to enable reusable containers * Update GenericContainer.java Co-authored-by: Sergei Egorov --- .../org/testcontainers/containers/GenericContainer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 945d1e1aff2..211ad2f59cb 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -69,6 +69,7 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; @@ -376,7 +377,12 @@ private void tryStart(Instant startedAt) { } reusable = true; } else { - logger().info("Reuse was requested but the environment does not support the reuse of containers"); + logger().warn( + "" + + "Reuse was requested but the environment does not support the reuse of containers\n" + + "To enable reuse of containers, you must set 'testcontainers.reuse.enable=true' in a file located at {}", + Paths.get(System.getProperty("user.home"), ".testcontainers.properties") + ); reusable = false; } } else { From cbd3220c555e7ece09163f245cd4114b7860c150 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 12 Apr 2020 16:02:39 +0200 Subject: [PATCH 0587/4969] Protect `NetworkImpl#close` from concurrency issues (#2203) * Increase thread safety of NetworkImpl * un-volatile `id` Co-authored-by: Sergei Egorov --- core/src/main/java/org/testcontainers/containers/Network.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/Network.java b/core/src/main/java/org/testcontainers/containers/Network.java index 411459b62eb..1c00fa00fac 100644 --- a/core/src/main/java/org/testcontainers/containers/Network.java +++ b/core/src/main/java/org/testcontainers/containers/Network.java @@ -97,7 +97,7 @@ protected void after() { } @Override - public void close() { + public synchronized void close() { if (initialized.getAndSet(false)) { ResourceReaper.instance().removeNetworkById(id); } From 84c8d1e290b6f2c5be00477cc67d85dc5ac3b26c Mon Sep 17 00:00:00 2001 From: Alexander Sparkowsky Date: Sun, 12 Apr 2020 16:07:22 +0200 Subject: [PATCH 0588/4969] Support TestLifecycleAware-ness of containers started by the JUnit Jupiter integration (#1326) * Update BrowserWebDriverContainer to honor existing no_proxy setting * Update test to only start one container per test * Use constant for no_proxy key * Cleanup test implementation (#929) * Add signalling of TestLifecycleAware containers. Allow containers like WebBrowserContainers to initialize and/or finalize before/after tests. * #1326 Add early draft to test signalling of TestLifecycleAware containers * Add test for post condition when signalling lifecycleaware containers This kind of test is a bit tricky since the post condition occurs after the original test has been finished. Also it's not nice to pass data between two tests. * Update test for lifecycle aware containers to cover shared case (#1326) In order to check that the afterAll callback has signalled lifecycleaware containers correctly a second extension is used. The order of the extension annotation ensures that the assertion is run after the extension under test. * Update test for lifecycle aware containers to cover shared case (#1326) To test the beforeAll() case the assertion has to be called from within the test class since it's called after all extensions. * Fix formatting (#1326) * Use lighter container for testing (#1326) * Separate store and collect of shared lifecycle-aware-containers (#1326) * Add tests for ordering and capturing test exceptions (#1326) * Make lifecycle tests independent of timing (#1326) Calls to the lifecycle methods are now recorded in an ordered list that is then used to test the correct number and order of calls. This makes the test independent of timing. Unfortunately it's still required to execute tests in a deterministic order. For a better separation of test concerns tests for the lifecycle methods and exception capturing have been moved into separate test classes. * Make mock now implements Startable (#1326) There is no need to start a container since only the TestLifecycleAware is important. * Add AssertJ dependency (#1326) We want to use AssertJ for some tests. * Migrate assertions of TestLifecycleAwareMethodTest to AssertJ (#1326) * Update generation of filesystem friendly description (#1326) * Separated tests for filesystem friendly filename (#1326) * Use lombok to improve readability (#1326) * Generate filesystem friendly name from display name (#1326) Generating a filesystem friendly name in a Junit Jupiter test is a bit tricky. Since tests can be generated dynamically class and/or test method may not be available. The display name provided by the ExtensionContext on the other hand may use characters that are not filesystem safe. This approach removes all characters from the display name that are not in a restricted set of allowed characters. However this may lead to name clashes if two tests have a display name that only differs in characters that are removed from the display name. * Generate filesystem friendly name from URLEncoded unique id (#1326) Co-authored-by: Richard North Co-authored-by: Kevin Wittek --- modules/junit-jupiter/build.gradle | 2 + .../FilesystemFriendlyNameGenerator.java | 24 +++++ .../jupiter/TestcontainerTestDescription.java | 10 ++ .../jupiter/TestcontainersExtension.java | 93 ++++++++++++++++--- .../FilesystemFriendlyNameGeneratorTest.java | 45 +++++++++ .../TestLifecycleAwareContainerMock.java | 54 +++++++++++ ...tLifecycleAwareExceptionCapturingTest.java | 37 ++++++++ .../jupiter/TestLifecycleAwareMethodTest.java | 73 +++++++++++++++ 8 files changed, 326 insertions(+), 12 deletions(-) create mode 100644 modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java create mode 100644 modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainerTestDescription.java create mode 100644 modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java create mode 100644 modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java create mode 100644 modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java create mode 100644 modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index d0a573adcc8..bf52b25913c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,6 +12,8 @@ dependencies { testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } + testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.0' + testCompile 'org.assertj:assertj-core:3.14.0' testRuntime 'org.postgresql:postgresql:42.2.12' testRuntime 'mysql:mysql-connector-java:8.0.19' diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java new file mode 100644 index 00000000000..ef8560b3f19 --- /dev/null +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java @@ -0,0 +1,24 @@ +package org.testcontainers.junit.jupiter; + +import org.junit.jupiter.api.extension.ExtensionContext; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.platform.commons.util.StringUtils.isBlank; + +class FilesystemFriendlyNameGenerator { + private static final String UNKNOWN_NAME = "unknown"; + + static String filesystemFriendlyNameOf(ExtensionContext context) { + String contextId = context.getUniqueId(); + try { + return (isBlank(contextId)) + ? UNKNOWN_NAME + : URLEncoder.encode(contextId, UTF_8.toString()); + } catch (UnsupportedEncodingException e) { + return UNKNOWN_NAME; + } + } +} diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainerTestDescription.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainerTestDescription.java new file mode 100644 index 00000000000..568d228e08c --- /dev/null +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainerTestDescription.java @@ -0,0 +1,10 @@ +package org.testcontainers.junit.jupiter; + +import lombok.Value; +import org.testcontainers.lifecycle.TestDescription; + +@Value +class TestcontainersTestDescription implements TestDescription { + String testId; + String filesystemFriendlyName; +} diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java index e6ce10f8541..1ed5e954e44 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java @@ -1,32 +1,50 @@ package org.testcontainers.junit.jupiter; import lombok.Getter; -import org.junit.jupiter.api.extension.*; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.testcontainers.DockerClientFactory; import org.testcontainers.lifecycle.Startable; +import org.testcontainers.lifecycle.TestDescription; +import org.testcontainers.lifecycle.TestLifecycleAware; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.LinkedHashSet; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Stream; -class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, ExecutionCondition, TestInstancePostProcessor { +import static java.util.stream.Collectors.toList; +import static org.testcontainers.junit.jupiter.FilesystemFriendlyNameGenerator.filesystemFriendlyNameOf; + +class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition, TestInstancePostProcessor { private static final Namespace NAMESPACE = Namespace.create(TestcontainersExtension.class); private static final String TEST_INSTANCE = "testInstance"; + private static final String SHARED_LIFECYCLE_AWARE_CONTAINERS = "sharedLifecycleAwareContainers"; + private static final String LOCAL_LIFECYCLE_AWARE_CONTAINERS = "localLifecycleAwareContainers"; @Override public void postProcessTestInstance(final Object testInstance, final ExtensionContext context) { - ExtensionContext.Store store = context.getStore(NAMESPACE); + Store store = context.getStore(NAMESPACE); store.put(TEST_INSTANCE, testInstance); } @@ -35,19 +53,69 @@ public void beforeAll(ExtensionContext context) { Class testClass = context.getTestClass() .orElseThrow(() -> new ExtensionConfigurationException("TestcontainersExtension is only supported for classes.")); - ExtensionContext.Store store = context.getStore(NAMESPACE); + Store store = context.getStore(NAMESPACE); + List sharedContainersStoreAdapters = findSharedContainers(testClass); + + sharedContainersStoreAdapters.forEach(adapter -> store.getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start())); + + List lifecycleAwareContainers = sharedContainersStoreAdapters + .stream() + .filter(this::isTestLifecycleAware) + .map(lifecycleAwareAdapter -> (TestLifecycleAware) lifecycleAwareAdapter.container) + .collect(toList()); - findSharedContainers(testClass) - .forEach(adapter -> store.getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start())); + store.put(SHARED_LIFECYCLE_AWARE_CONTAINERS, lifecycleAwareContainers); + signalBeforeTestToContainers(lifecycleAwareContainers, testDescriptionFrom(context)); + } + + @Override + public void afterAll(ExtensionContext context) { + signalAfterTestToContainersFor(SHARED_LIFECYCLE_AWARE_CONTAINERS, context); } @Override public void beforeEach(final ExtensionContext context) { - collectParentTestInstances(context) - .parallelStream() + Store store = context.getStore(NAMESPACE); + + List lifecycleAwareContainers = collectParentTestInstances(context).parallelStream() .flatMap(this::findRestartContainers) - .forEach(adapter -> context.getStore(NAMESPACE) - .getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start())); + .peek(adapter -> store.getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start())) + .filter(this::isTestLifecycleAware) + .map(lifecycleAwareAdapter -> (TestLifecycleAware) lifecycleAwareAdapter.container) + .collect(toList()); + + store.put(LOCAL_LIFECYCLE_AWARE_CONTAINERS, lifecycleAwareContainers); + signalBeforeTestToContainers(lifecycleAwareContainers, testDescriptionFrom(context)); + } + + @Override + public void afterEach(ExtensionContext context) { + signalAfterTestToContainersFor(LOCAL_LIFECYCLE_AWARE_CONTAINERS, context); + } + + private void signalBeforeTestToContainers(List lifecycleAwareContainers, TestDescription testDescription) { + lifecycleAwareContainers.forEach(container -> container.beforeTest(testDescription)); + } + + private void signalAfterTestToContainersFor(String storeKey, ExtensionContext context) { + List lifecycleAwareContainers = + (List) context.getStore(NAMESPACE).get(storeKey); + if (lifecycleAwareContainers != null) { + TestDescription description = testDescriptionFrom(context); + Optional throwable = context.getExecutionException(); + lifecycleAwareContainers.forEach(container -> container.afterTest(description, throwable)); + } + } + + private TestDescription testDescriptionFrom(ExtensionContext context) { + return new TestcontainersTestDescription( + context.getUniqueId(), + filesystemFriendlyNameOf(context) + ); + } + + private boolean isTestLifecycleAware(StoreAdapter adapter) { + return adapter.container instanceof TestLifecycleAware; } @Override @@ -101,13 +169,14 @@ private Set collectParentTestInstances(final ExtensionContext context) { return testInstances; } - private Stream findSharedContainers(Class testClass) { + private List findSharedContainers(Class testClass) { return ReflectionUtils.findFields( testClass, isSharedContainer(), ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) .stream() - .map(f -> getContainerInstance(null, f)); + .map(f -> getContainerInstance(null, f)) + .collect(toList()); } private Predicate isSharedContainer() { diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java new file mode 100644 index 00000000000..96617b0e063 --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java @@ -0,0 +1,45 @@ +package org.testcontainers.junit.jupiter; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.testcontainers.junit.jupiter.FilesystemFriendlyNameGenerator.filesystemFriendlyNameOf; + +class FilesystemFriendlyNameGeneratorTest { + + @ParameterizedTest + @MethodSource("provideDisplayNamesAndFilesystemFriendlyNames") + void should_generate_filesystem_friendly_name(String displayName, String expectedName) { + ExtensionContext context = mock(ExtensionContext.class); + doReturn(displayName) + .when(context).getUniqueId(); + + String filesystemFriendlyName = filesystemFriendlyNameOf(context); + + assertThat(filesystemFriendlyName).isEqualTo(expectedName); + } + + private static Stream provideDisplayNamesAndFilesystemFriendlyNames() { + return Stream.of( + Arguments.of("", "unknown"), + Arguments.of(" ", "unknown"), + Arguments.of("not blank", "not+blank"), + Arguments.of("abc ABC 1234567890", "abc+ABC+1234567890"), + Arguments.of( + "no_umlauts_äöüÄÖÜéáíó", + "no_umlauts_%C3%A4%C3%B6%C3%BC%C3%84%C3%96%C3%9C%C3%A9%C3%A1%C3%AD%C3%B3" + ), + Arguments.of( + "[engine:junit-jupiter]/[class:com.example.MyTest]/[test-factory:parameterizedTest()]/[dynamic-test:#3]", + "%5Bengine%3Ajunit-jupiter%5D%2F%5Bclass%3Acom.example.MyTest%5D%2F%5Btest-factory%3AparameterizedTest%28%29%5D%2F%5Bdynamic-test%3A%233%5D" + ) + ); + } +} diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java new file mode 100644 index 00000000000..38751c8789a --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java @@ -0,0 +1,54 @@ +package org.testcontainers.junit.jupiter; + +import org.testcontainers.lifecycle.Startable; +import org.testcontainers.lifecycle.TestDescription; +import org.testcontainers.lifecycle.TestLifecycleAware; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class TestLifecycleAwareContainerMock implements Startable, TestLifecycleAware { + + static final String BEFORE_TEST = "beforeTest"; + static final String AFTER_TEST = "afterTest"; + + private final List lifecycleMethodCalls = new ArrayList<>(); + private final List lifecycleFilesystemFriendlyNames = new ArrayList<>(); + + private Throwable capturedThrowable; + + @Override + public void beforeTest(TestDescription description) { + lifecycleMethodCalls.add(BEFORE_TEST); + lifecycleFilesystemFriendlyNames.add(description.getFilesystemFriendlyName()); + } + + @Override + public void afterTest(TestDescription description, Optional throwable) { + lifecycleMethodCalls.add(AFTER_TEST); + throwable.ifPresent(capturedThrowable -> this.capturedThrowable = capturedThrowable); + } + + List getLifecycleMethodCalls() { + return lifecycleMethodCalls; + } + + Throwable getCapturedThrowable() { + return capturedThrowable; + } + + public List getLifecycleFilesystemFriendlyNames() { + return lifecycleFilesystemFriendlyNames; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } +} diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java new file mode 100644 index 00000000000..85d837a7880 --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java @@ -0,0 +1,37 @@ +package org.testcontainers.junit.jupiter; + +import org.junit.AssumptionViolatedException; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +// The order of @ExtendsWith and @Testcontainers is crucial in order for the tests +@Testcontainers +@TestMethodOrder(OrderAnnotation.class) +class TestLifecycleAwareExceptionCapturingTest { + @Container + private final TestLifecycleAwareContainerMock testContainer = new TestLifecycleAwareContainerMock(); + + private static TestLifecycleAwareContainerMock startedTestContainer; + + @Test + @Order(1) + void failing_test_should_pass_throwable_to_testContainer() { + startedTestContainer = testContainer; + // Force an exception that is captured by the test container without failing the test itself + assumeTrue(false); + } + + @Test + @Order(2) + void should_have_captured_thrownException() { + Throwable capturedThrowable = startedTestContainer.getCapturedThrowable(); + assertTrue(capturedThrowable instanceof AssumptionViolatedException); + assertEquals("got: , expected: is ", capturedThrowable.getMessage()); + } +} diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java new file mode 100644 index 00000000000..cecdff490ef --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java @@ -0,0 +1,73 @@ +package org.testcontainers.junit.jupiter; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.junit.jupiter.TestLifecycleAwareContainerMock.AFTER_TEST; +import static org.testcontainers.junit.jupiter.TestLifecycleAwareContainerMock.BEFORE_TEST; + +// The order of @ExtendsWith and @Testcontainers is crucial for the tests +@ExtendWith({TestLifecycleAwareMethodTest.SharedContainerAfterAllTestExtension.class}) +@Testcontainers +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class TestLifecycleAwareMethodTest { + @Container + private final TestLifecycleAwareContainerMock testContainer = new TestLifecycleAwareContainerMock(); + + @Container + private static final TestLifecycleAwareContainerMock SHARED_CONTAINER = new TestLifecycleAwareContainerMock(); + + private static TestLifecycleAwareContainerMock startedTestContainer; + + @BeforeAll + static void beforeAll() { + assertThat(SHARED_CONTAINER.getLifecycleMethodCalls()).containsExactly(BEFORE_TEST); + + } + + @Test + @Order(1) + void should_prepare_before_and_after_test() { + // we can only test for a call to afterTest() after this test has been finished. + startedTestContainer = testContainer; + } + + @Test + @Order(2) + void should_call_beforeTest_first_afterTest_later_with_filesystem_friendly_name() { + assertThat(startedTestContainer.getLifecycleMethodCalls()) + .containsExactly(BEFORE_TEST, AFTER_TEST); + } + + @Test + void should_have_a_filesystem_friendly_name_container_has_started() { + assertThat(startedTestContainer.getLifecycleFilesystemFriendlyNames()) + .containsExactly( + "%5Bengine%3Ajunit-jupiter%5D%2F%5Bclass%3Aorg.testcontainers.junit.jupiter.TestLifecycleAwareMethodTest%5D%2F%5Bmethod%3Ashould_prepare_before_and_after_test%28%29%5D" + ); + } + + @Test + void static_container_should_have_a_filesystem_friendly_name_after_container_has_started() { + assertThat(SHARED_CONTAINER.getLifecycleFilesystemFriendlyNames()) + .containsExactly( + "%5Bengine%3Ajunit-jupiter%5D%2F%5Bclass%3Aorg.testcontainers.junit.jupiter.TestLifecycleAwareMethodTest%5D" + ); + } + + static class SharedContainerAfterAllTestExtension implements AfterAllCallback { + // Unfortunately it's not possible to write a @Test that is run after all tests + @Override + public void afterAll(ExtensionContext context) { + assertThat(SHARED_CONTAINER.getLifecycleMethodCalls()) + .containsExactly(BEFORE_TEST, AFTER_TEST); + } + } +} From 6c45a20892d837ac736dd293abfe458f96be74fc Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Apr 2020 19:27:49 +0200 Subject: [PATCH 0589/4969] Add R2DBC support (#2545) This PR adds support for [R2DBC](https://r2dbc.io). ## URL support The URL support is similar to the JDBC's, but: 1. Does not reuse containers by URL - it is unclear yet how to "hash" `ConnectionFactoryOptions` 1. The image tag must be explicitly provided via `TC_IMAGE_TAG` r2dbc option 1. TODO: daemon mode 1. TODO: alias support (see #4) ## Example usage The user **must add the `org.testcontainers:r2dbc` module** - unlike JDBC, we use `compileOnly` dependency on R2DBC, since it is a 3rd party dependency. Once both the `r2dbc` and database's module are added, one can use: ```java String url = "r2dbc:tc:postgresql:///db?TC_IMAGE_TAG=10-alpine"; ConnectionFactory connectionFactory = ConnectionFactories.get(url); ``` ## Programmatic access For those who start containers manually and want to obtain `ConnectionFactoryOptions` for already started containers, we provide a helper static method: ```java try (PostgreSQLContainer container = new PostgreSQLContainer<>()) { container.start(); ConnectionFactory connectionFactory = ConnectionFactories.get( PostgreSQLR2DBCDatabaseContainer.getOptions(container) ); } ``` --- docs/modules/databases/index.md | 113 +----------- docs/modules/databases/jdbc.md | 119 +++++++++++++ docs/modules/databases/r2dbc.md | 57 +++++++ mkdocs.yml | 2 + modules/mariadb/build.gradle | 9 + .../containers/MariaDBContainer.java | 2 +- .../MariaDBR2DBCDatabaseContainer.java | 33 ++++ ...MariaDBR2DBCDatabaseContainerProvider.java | 30 ++++ .../MariaDBR2DBCDatabaseContainerTest.java | 23 +++ .../src/test/resources/logback-test.xml | 16 ++ modules/mssqlserver/build.gradle | 13 ++ .../MSSQLR2DBCDatabaseContainer.java | 34 ++++ .../MSSQLR2DBCDatabaseContainerProvider.java | 29 ++++ .../MSSQLR2DBCDatabaseContainerTest.java | 22 +++ .../container-license-acceptance.txt | 1 + .../src/test/resources/logback-test.xml | 16 ++ modules/mysql/build.gradle | 9 + .../MySQLR2DBCDatabaseContainer.java | 33 ++++ .../MySQLR2DBCDatabaseContainerProvider.java | 30 ++++ .../MySQLR2DBCDatabaseContainerTest.java | 23 +++ .../mysql/src/test/resources/logback-test.xml | 16 ++ modules/postgresql/build.gradle | 8 + .../PostgreSQLR2DBCDatabaseContainer.java | 33 ++++ ...tgreSQLR2DBCDatabaseContainerProvider.java | 30 ++++ .../PostgreSQLR2DBCDatabaseContainerTest.java | 27 +++ .../src/test/resources/logback-test.xml | 16 ++ modules/r2dbc/build.gradle | 20 +++ .../r2dbc/CancellableSubscription.java | 23 +++ .../r2dbc/ConnectionPublisher.java | 161 ++++++++++++++++++ .../r2dbc/EmptySubscription.java | 17 ++ .../java/org/testcontainers/r2dbc/Hidden.java | 73 ++++++++ .../r2dbc/R2DBCDatabaseContainer.java | 9 + .../r2dbc/R2DBCDatabaseContainerProvider.java | 15 ++ .../TestcontainersR2DBCConnectionFactory.java | 104 +++++++++++ ...tcontainersR2DBCConnectionFactoryTest.java | 79 +++++++++ .../r2dbc/src/test/resources/logback-test.xml | 16 ++ .../AbstractR2DBCDatabaseContainerTest.java | 64 +++++++ 37 files changed, 1212 insertions(+), 113 deletions(-) create mode 100644 docs/modules/databases/jdbc.md create mode 100644 docs/modules/databases/r2dbc.md create mode 100644 modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java create mode 100644 modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java create mode 100644 modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java create mode 100644 modules/mariadb/src/test/resources/logback-test.xml create mode 100644 modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java create mode 100644 modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java create mode 100644 modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java create mode 100644 modules/mssqlserver/src/test/resources/container-license-acceptance.txt create mode 100644 modules/mssqlserver/src/test/resources/logback-test.xml create mode 100644 modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java create mode 100644 modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java create mode 100644 modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java create mode 100644 modules/mysql/src/test/resources/logback-test.xml create mode 100644 modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java create mode 100644 modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java create mode 100644 modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java create mode 100644 modules/postgresql/src/test/resources/logback-test.xml create mode 100644 modules/r2dbc/build.gradle create mode 100644 modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java create mode 100644 modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java create mode 100644 modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java create mode 100644 modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java create mode 100644 modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java create mode 100644 modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java create mode 100644 modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java create mode 100644 modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java create mode 100644 modules/r2dbc/src/test/resources/logback-test.xml create mode 100644 modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java diff --git a/docs/modules/databases/index.md b/docs/modules/databases/index.md index d7654cc6a33..6685ade55c8 100644 --- a/docs/modules/databases/index.md +++ b/docs/modules/databases/index.md @@ -10,115 +10,4 @@ You might want to use Testcontainers' database support: !!! note Of course, it's still important to have as few tests that hit the database as possible, and make good use of mocks for components higher up the stack. -You can obtain a temporary database in one of two ways: - - * **JUnit @Rule/@ClassRule**: this mode starts a database inside a container before your tests and tears it down afterwards. - * **Using a specially modified JDBC URL**: after making a very simple modification to your system's JDBC URL string, Testcontainers will provide a disposable stand-in database that can be used without requiring modification to your application code. - -## Database container objects - -Add a @Rule or @ClassRule to your test class, e.g.: - -```java -public class SimpleMySQLTest { - @Rule - public MySQLContainer mysql = new MySQLContainer(); -``` - -Now, in your test code (or a suitable setup method), you can obtain details necessary to connect to this database: - - * `mysql.getJdbcUrl()` provides a JDBC URL your code can connect to - * `mysql.getUsername()` provides the username your code should pass to the driver - * `mysql.getPassword()` provides the password your code should pass to the driver - -Note that if you use `@Rule`, you will be given an isolated container for each test method. If you use `@ClassRule`, you will get on isolated container for all the methods in the test class. - -Examples/Tests: - - * [MySQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java) - * [PostgreSQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java) - -## Database containers launched via JDBC URL scheme - -As long as you have Testcontainers and the appropriate JDBC driver on your classpath, you can simply modify regular JDBC connection URLs to get a fresh containerized instance of the database each time your application starts up. - -_N.B:_ - -* _TC needs to be on your application's classpath at runtime for this to work_ -* _For Spring Boot (Before version `2.3.0`) you need to specify the driver manually `spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver`_ - -**Original URL**: `jdbc:mysql:5.7.22://localhost:3306/databasename` - -Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value. - -!!! note - We will use `///` (host-less URIs) from now on to emphasis the unimportance of the `host:port` pair. - From Testcontainers' perspective, `jdbc:mysql:5.7.22://localhost:3306/databasename` and `jdbc:mysql:5.7.22:///databasename` is the same URI. - -### JDBC URL examples - -#### Using Testcontainers with a fixed version - -`jdbc:tc:mysql:5.6.23:///databasename` - -#### Using PostgreSQL - -`jdbc:tc:postgresql:9.6.8:///databasename` - -### Using PostGIS - -`jdbc:tc:postgis:9.6:///databasename` - -### Using Presto - -`jdbc:tc:presto:329://localhost/memory/default` - -## Using a classpath init script - -Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: - -`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=somepath/init_mysql.sql` - -This is useful if you have a fixed script for setting up database schema, etc. - -## Using an init script from a file - -If the init script path is prefixed `file:`, it will be loaded from a file (relative to the working directory, which will usually be the project root). - -`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql` - -#### Using an init function - -Instead of running a fixed script for DB setup, it may be useful to call a Java function that you define. This is intended to allow you to trigger database schema migration tools. To do this, add TC_INITFUNCTION to the URL as follows, passing a full path to the class name and method: - - `jdbc:tc:mysql:5.7.22:///databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction` - -The init function must be a public static method which takes a `java.sql.Connection` as its only parameter, e.g. -```java -public class JDBCDriverTest { - public static void sampleInitFunction(Connection connection) throws SQLException { - // e.g. run schema setup or Flyway/liquibase/etc DB migrations here... - } - ... -``` - -#### Running container in daemon mode - -By default database container is being stopped as soon as last connection is closed. There are cases when you might need to start container and keep it running till you stop it explicitly or JVM is shutdown. To do this, add `TC_DAEMON` parameter to the URL as follows: - - `jdbc:tc:mysql:5.7.22:///databasename?TC_DAEMON=true` - -With this parameter database container will keep running even when there're no open connections. - - -#### Running container with tmpfs options - -Container can have `tmpfs` mounts for storing data in host memory. This is useful if you want to speed up your database tests. Be aware that the data will be lost when the container stops. - -To pass this option to the container, add `TC_TMPFS` parameter to the URL as follows: - - `jdbc:tc:postgresql:9.6.8:///databasename?TC_TMPFS=/testtmpfs:rw` - -If you need more than one option, separate them by comma (e.g. `TC_TMPFS=key:value,key1:value1&other_parameters=foo`). - -For more information about `tmpfs` mount, see [the official Docker documentation](https://docs.docker.com/storage/tmpfs/). +See [JDBC](./jdbc.md) and [R2DBC](./r2dbc.md) for information on how to use Testcontainers with SQL-like databases. \ No newline at end of file diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md new file mode 100644 index 00000000000..5f83d7fcdeb --- /dev/null +++ b/docs/modules/databases/jdbc.md @@ -0,0 +1,119 @@ +# JDBC support + +You can obtain a temporary database in one of two ways: + + * **Using a specially modified JDBC URL**: after making a very simple modification to your system's JDBC URL string, Testcontainers will provide a disposable stand-in database that can be used without requiring modification to your application code. + * **JUnit @Rule/@ClassRule**: this mode starts a database inside a container before your tests and tears it down afterwards. + +## Database containers launched via JDBC URL scheme + +As long as you have Testcontainers and the appropriate JDBC driver on your classpath, you can simply modify regular JDBC connection URLs to get a fresh containerized instance of the database each time your application starts up. + +_N.B:_ + +* _TC needs to be on your application's classpath at runtime for this to work_ +* _For Spring Boot (Before version `2.3.0`) you need to specify the driver manually `spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver`_ + +**Original URL**: `jdbc:mysql://localhost:3306/databasename` + +Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value. + +!!! note + We will use `///` (host-less URIs) from now on to emphasis the unimportance of the `host:port` pair. + From Testcontainers' perspective, `jdbc:mysql:5.7.22://localhost:3306/databasename` and `jdbc:mysql:5.7.22:///databasename` is the same URI. + +!!! warning + If you're using the JDBC URL support, there is no need to instantiate an instance of the container - Testcontainers will do it automagically. + +### JDBC URL examples + +#### Using Testcontainers with a fixed version + +`jdbc:tc:mysql:5.6.23:///databasename` + +#### Using PostgreSQL + +`jdbc:tc:postgresql:9.6.8:///databasename` + +#### Using PostGIS + +`jdbc:tc:postgis:9.6:///databasename` + +#### Using Presto + +`jdbc:tc:presto:329://localhost/memory/default` + +### Using a classpath init script + +Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: + +`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=somepath/init_mysql.sql` + +This is useful if you have a fixed script for setting up database schema, etc. + +### Using an init script from a file + +If the init script path is prefixed `file:`, it will be loaded from a file (relative to the working directory, which will usually be the project root). + +`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql` + +### Using an init function + +Instead of running a fixed script for DB setup, it may be useful to call a Java function that you define. This is intended to allow you to trigger database schema migration tools. To do this, add TC_INITFUNCTION to the URL as follows, passing a full path to the class name and method: + + `jdbc:tc:mysql:5.7.22:///databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction` + +The init function must be a public static method which takes a `java.sql.Connection` as its only parameter, e.g. +```java +public class JDBCDriverTest { + public static void sampleInitFunction(Connection connection) throws SQLException { + // e.g. run schema setup or Flyway/liquibase/etc DB migrations here... + } + ... +``` + +### Running container in daemon mode + +By default database container is being stopped as soon as last connection is closed. There are cases when you might need to start container and keep it running till you stop it explicitly or JVM is shutdown. To do this, add `TC_DAEMON` parameter to the URL as follows: + + `jdbc:tc:mysql:5.7.22:///databasename?TC_DAEMON=true` + +With this parameter database container will keep running even when there're no open connections. + + +### Running container with tmpfs options + +Container can have `tmpfs` mounts for storing data in host memory. This is useful if you want to speed up your database tests. Be aware that the data will be lost when the container stops. + +To pass this option to the container, add `TC_TMPFS` parameter to the URL as follows: + + `jdbc:tc:postgresql:9.6.8:///databasename?TC_TMPFS=/testtmpfs:rw` + +If you need more than one option, separate them by comma (e.g. `TC_TMPFS=key:value,key1:value1&other_parameters=foo`). + +For more information about `tmpfs` mount, see [the official Docker documentation](https://docs.docker.com/storage/tmpfs/). + +## Database container objects + +In case you can't use the URL support, or need to fine-tune the container, you can instantiate it yourself. + +Add a @Rule or @ClassRule to your test class, e.g.: + +```java +public class SimpleMySQLTest { + @Rule + public MySQLContainer mysql = new MySQLContainer(); +``` + +Now, in your test code (or a suitable setup method), you can obtain details necessary to connect to this database: + + * `mysql.getJdbcUrl()` provides a JDBC URL your code can connect to + * `mysql.getUsername()` provides the username your code should pass to the driver + * `mysql.getPassword()` provides the password your code should pass to the driver + +Note that if you use `@Rule`, you will be given an isolated container for each test method. If you use `@ClassRule`, you will get on isolated container for all the methods in the test class. + +Examples/Tests: + + * [MySQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java) + * [PostgreSQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java) \ No newline at end of file diff --git a/docs/modules/databases/r2dbc.md b/docs/modules/databases/r2dbc.md new file mode 100644 index 00000000000..6ba3f401a08 --- /dev/null +++ b/docs/modules/databases/r2dbc.md @@ -0,0 +1,57 @@ +# R2DBC support + +You can obtain a temporary database in one of two ways: + + * **Using a specially modified R2DBC URL**: after making a very simple modification to your system's R2DBC URL string, Testcontainers will provide a disposable stand-in database that can be used without requiring modification to your application code. + * **JUnit @Rule/@ClassRule**: this mode starts a database inside a container before your tests and tears it down afterwards. + +## Database containers launched via R2DBC URL scheme + +As long as you have Testcontainers and the appropriate R2DBC driver on your classpath, you can simply modify regular R2DBC connection URLs to get a fresh containerized instance of the database each time your application starts up. + +The started container will be terminated when the `ConnectionFactory` is closed. + +!!! warning + Both the database module (e.g. `org.testcontainers:mysql`) **and** `org.testcontainers:r2dbc` need to be on your application's classpath at runtime. + +**Original URL**: `r2dbc:mysql://localhost:3306/databasename` + +1. Insert `tc:` after `r2dbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value. +1. Specify the mandatory Docker tag of the database's official image that you want using a `TC_IMAGE_TAG` query parameter. + +**Note that, unlike Testcontainers' JDBC URL support, it is not possible to specify an image tag in the 'scheme' part of the URL, and it is always necessary to specify a tag using `TC_IMAGE_TAG`.** + +So that the URL becomes: +`r2dbc:tc:mysql:///databasename?TC_IMAGE_TAG=5.7.22` + +!!! note + We will use `///` (host-less URIs) from now on to emphasis the unimportance of the `host:port` pair. + From Testcontainers' perspective, `r2dbc:mysql://localhost:3306/databasename` and `r2dbc:mysql:///databasename` is the same URI. + +!!! warning + If you're using the R2DBC URL support, there is no need to instantiate an instance of the container - Testcontainers will do it automagically. + +### R2DBC URL examples + +#### Using MySQL + +`r2dbc:tc:mysql:///databasename?TC_IMAGE_TAG=5.6.23` + +#### Using MariaDB + +`r2dbc:tc:mariadb:///databasename?TC_IMAGE_TAG=10.3.6` + +#### Using PostgreSQL + +`r2dbc:tc:postgresql:///databasename?TC_IMAGE_TAG=9.6.8` + +#### Using MSSQL: + +`r2dbc:tc:sqlserver:///?TC_IMAGE_TAG=2017-CU12` + +## Obtaining `ConnectionFactoryOptions` from database container objects + +If you already have an instance of the database container, you can get an instance of `ConnectionFactoryOptions` from it: + +[Creating `ConnectionFactoryOptions` from an instance)](../../../modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java) inside_block:get_options + diff --git a/mkdocs.yml b/mkdocs.yml index 49876885dfd..c2d39bc9d2c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,6 +40,8 @@ nav: - Modules: - Databases: - modules/databases/index.md + - modules/databases/jdbc.md + - modules/databases/r2dbc.md - modules/databases/cassandra.md - modules/databases/cockroachdb.md - modules/databases/couchbase.md diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index be42121f3d8..93b2de2a716 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -1,11 +1,20 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + compile project(':jdbc') + compileOnly project(':r2dbc') + compileOnly 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' testCompile 'org.vibur:vibur-dbcp:25.0' + + testCompile testFixtures(project(':r2dbc')) + testCompile 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' } diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index be1b3d3d44d..e402bc24e0e 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -11,7 +11,7 @@ public class MariaDBContainer> extends JdbcD public static final String IMAGE = "mariadb"; public static final String DEFAULT_TAG = "10.3.6"; - private static final Integer MARIADB_PORT = 3306; + static final Integer MARIADB_PORT = 3306; private String databaseName = "test"; private String username = "test"; private String password = "test"; diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java new file mode 100644 index 00000000000..4ddbed997d4 --- /dev/null +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java @@ -0,0 +1,33 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import org.testcontainers.lifecycle.Startable; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; + +@RequiredArgsConstructor +public class MariaDBR2DBCDatabaseContainer implements R2DBCDatabaseContainer { + + @Delegate(types = Startable.class) + private final MariaDBContainer container; + + public static ConnectionFactoryOptions getOptions(MariaDBContainer container) { + ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + .option(ConnectionFactoryOptions.DRIVER, MariaDBR2DBCDatabaseContainerProvider.DRIVER) + .build(); + + return new MariaDBR2DBCDatabaseContainer(container).configure(options); + } + + @Override + public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { + return options.mutate() + .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MariaDBContainer.MARIADB_PORT)) + .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build(); + } +} diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java new file mode 100644 index 00000000000..79cb627f8a9 --- /dev/null +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java @@ -0,0 +1,30 @@ +package org.testcontainers.containers; + +import com.google.auto.service.AutoService; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.mariadb.r2dbc.MariadbConnectionFactoryProvider; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; +import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; + +@AutoService(R2DBCDatabaseContainerProvider.class) +public class MariaDBR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { + + static final String DRIVER = MariadbConnectionFactoryProvider.MARIADB_DRIVER; + + @Override + public boolean supports(ConnectionFactoryOptions options) { + return DRIVER.equals(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)); + } + + @Override + public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) { + String image = MariaDBContainer.IMAGE + ":" + options.getRequiredValue(IMAGE_TAG_OPTION); + MariaDBContainer container = new MariaDBContainer<>(image) + .withDatabaseName(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)); + + if (Boolean.TRUE.equals(options.getValue(REUSABLE_OPTION))) { + container.withReuse(true); + } + return new MariaDBR2DBCDatabaseContainer(container); + } +} diff --git a/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java new file mode 100644 index 00000000000..30e8cad9c32 --- /dev/null +++ b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java @@ -0,0 +1,23 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; + +public class MariaDBR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { + + @Override + protected ConnectionFactoryOptions getOptions(MariaDBContainer container) { + return MariaDBR2DBCDatabaseContainer.getOptions(container); + } + + @Override + protected String createR2DBCUrl() { + return "r2dbc:tc:mariadb:///db?TC_IMAGE_TAG=10.3.6"; + } + + @Override + protected MariaDBContainer createContainer() { + return new MariaDBContainer<>(); + } + +} diff --git a/modules/mariadb/src/test/resources/logback-test.xml b/modules/mariadb/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/mariadb/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 62434722d63..3c44df64eda 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -1,5 +1,18 @@ description = "Testcontainers :: MS SQL Server" dependencies { + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + compile project(':jdbc') + + compileOnly project(':r2dbc') + compileOnly 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' + + testCompile project(':r2dbc') + testCompile 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' + + // MSSQL's wait strategy requires the JDBC driver + testCompile testFixtures(project(':r2dbc')) + testCompile 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8' } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java new file mode 100644 index 00000000000..27c486c218c --- /dev/null +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java @@ -0,0 +1,34 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import org.testcontainers.lifecycle.Startable; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; + +@RequiredArgsConstructor +public class MSSQLR2DBCDatabaseContainer implements R2DBCDatabaseContainer { + + @Delegate(types = Startable.class) + private final MSSQLServerContainer container; + + public static ConnectionFactoryOptions getOptions(MSSQLServerContainer container) { + ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + .option(ConnectionFactoryOptions.DRIVER, MSSQLR2DBCDatabaseContainerProvider.DRIVER) + .build(); + + return new MSSQLR2DBCDatabaseContainer(container).configure(options); + } + + @Override + public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { + return options.mutate() + .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MSSQLServerContainer.MS_SQL_SERVER_PORT)) + // TODO enable if/when MSSQLServerContainer adds support for customizing the DB name + // .option(ConnectionFactoryOptions.DATABASE, container.getDatabasseName()) + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build(); + } +} diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java new file mode 100644 index 00000000000..1638901226c --- /dev/null +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java @@ -0,0 +1,29 @@ +package org.testcontainers.containers; + +import com.google.auto.service.AutoService; +import io.r2dbc.mssql.MssqlConnectionFactoryProvider; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; +import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; + +@AutoService(R2DBCDatabaseContainerProvider.class) +public class MSSQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { + + static final String DRIVER = MssqlConnectionFactoryProvider.MSSQL_DRIVER; + + @Override + public boolean supports(ConnectionFactoryOptions options) { + return DRIVER.equals(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)); + } + + @Override + public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) { + String image = MSSQLServerContainer.IMAGE + ":" + options.getRequiredValue(IMAGE_TAG_OPTION); + MSSQLServerContainer container = new MSSQLServerContainer<>(image); + + if (Boolean.TRUE.equals(options.getValue(REUSABLE_OPTION))) { + container.withReuse(true); + } + return new MSSQLR2DBCDatabaseContainer(container); + } +} diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java new file mode 100644 index 00000000000..1fcf2dd293b --- /dev/null +++ b/modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java @@ -0,0 +1,22 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; + +public class MSSQLR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { + + @Override + protected ConnectionFactoryOptions getOptions(MSSQLServerContainer container) { + return MSSQLR2DBCDatabaseContainer.getOptions(container); + } + + @Override + protected String createR2DBCUrl() { + return "r2dbc:tc:sqlserver:///?TC_IMAGE_TAG=2017-CU12"; + } + + @Override + protected MSSQLServerContainer createContainer() { + return new MSSQLServerContainer<>(); + } +} diff --git a/modules/mssqlserver/src/test/resources/container-license-acceptance.txt b/modules/mssqlserver/src/test/resources/container-license-acceptance.txt new file mode 100644 index 00000000000..8a704b9c066 --- /dev/null +++ b/modules/mssqlserver/src/test/resources/container-license-acceptance.txt @@ -0,0 +1 @@ +mcr.microsoft.com/mssql/server:2017-CU12 diff --git a/modules/mssqlserver/src/test/resources/logback-test.xml b/modules/mssqlserver/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/mssqlserver/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index da609a1b535..10fd90b3c38 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -1,11 +1,20 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + compile project(':jdbc') + compileOnly project(':r2dbc') + compileOnly 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' + testCompile 'mysql:mysql-connector-java:8.0.19' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' + + testCompile testFixtures(project(':r2dbc')) + testCompile 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java new file mode 100644 index 00000000000..c43ffcca1b2 --- /dev/null +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java @@ -0,0 +1,33 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import org.testcontainers.lifecycle.Startable; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; + +@RequiredArgsConstructor +public class MySQLR2DBCDatabaseContainer implements R2DBCDatabaseContainer { + + @Delegate(types = Startable.class) + private final MySQLContainer container; + + public static ConnectionFactoryOptions getOptions(MySQLContainer container) { + ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + .option(ConnectionFactoryOptions.DRIVER, MySQLR2DBCDatabaseContainerProvider.DRIVER) + .build(); + + return new MySQLR2DBCDatabaseContainer(container).configure(options); + } + + @Override + public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { + return options.mutate() + .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MySQLContainer.MYSQL_PORT)) + .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build(); + } +} diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java new file mode 100644 index 00000000000..3a01616caba --- /dev/null +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java @@ -0,0 +1,30 @@ +package org.testcontainers.containers; + +import com.google.auto.service.AutoService; +import dev.miku.r2dbc.mysql.MySqlConnectionFactoryProvider; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; +import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; + +@AutoService(R2DBCDatabaseContainerProvider.class) +public class MySQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { + + static final String DRIVER = MySqlConnectionFactoryProvider.MYSQL_DRIVER; + + @Override + public boolean supports(ConnectionFactoryOptions options) { + return DRIVER.equals(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)); + } + + @Override + public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) { + String image = MySQLContainer.IMAGE + ":" + options.getRequiredValue(IMAGE_TAG_OPTION); + MySQLContainer container = new MySQLContainer<>(image) + .withDatabaseName(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)); + + if (Boolean.TRUE.equals(options.getValue(REUSABLE_OPTION))) { + container.withReuse(true); + } + return new MySQLR2DBCDatabaseContainer(container); + } +} diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java new file mode 100644 index 00000000000..19edc3dbca4 --- /dev/null +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java @@ -0,0 +1,23 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; + +public class MySQLR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { + + @Override + protected ConnectionFactoryOptions getOptions(MySQLContainer container) { + return MySQLR2DBCDatabaseContainer.getOptions(container); + } + + @Override + protected String createR2DBCUrl() { + return "r2dbc:tc:mysql:///db?TC_IMAGE_TAG=5.7.22"; + } + + @Override + protected MySQLContainer createContainer() { + return new MySQLContainer<>(); + } + +} diff --git a/modules/mysql/src/test/resources/logback-test.xml b/modules/mysql/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/mysql/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 89d40fe6923..c629c1c5a13 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -1,9 +1,17 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + compile project(':jdbc') + compileOnly project(':r2dbc') + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' testCompile 'org.postgresql:postgresql:42.2.12' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' + + testCompile testFixtures(project(':r2dbc')) + testCompile 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java new file mode 100644 index 00000000000..9bfb9fdee05 --- /dev/null +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java @@ -0,0 +1,33 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import org.testcontainers.lifecycle.Startable; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; + +@RequiredArgsConstructor +public final class PostgreSQLR2DBCDatabaseContainer implements R2DBCDatabaseContainer { + + @Delegate(types = Startable.class) + private final PostgreSQLContainer container; + + public static ConnectionFactoryOptions getOptions(PostgreSQLContainer container) { + ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + .option(ConnectionFactoryOptions.DRIVER, PostgreSQLR2DBCDatabaseContainerProvider.DRIVER) + .build(); + + return new PostgreSQLR2DBCDatabaseContainer(container).configure(options); + } + + @Override + public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { + return options.mutate() + .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.PORT, container.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT)) + .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build(); + } +} diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java new file mode 100644 index 00000000000..5e9da980b8e --- /dev/null +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java @@ -0,0 +1,30 @@ +package org.testcontainers.containers; + +import com.google.auto.service.AutoService; +import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.r2dbc.R2DBCDatabaseContainer; +import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; + +@AutoService(R2DBCDatabaseContainerProvider.class) +public final class PostgreSQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { + + static final String DRIVER = PostgresqlConnectionFactoryProvider.POSTGRESQL_DRIVER; + + @Override + public boolean supports(ConnectionFactoryOptions options) { + return DRIVER.equals(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)); + } + + @Override + public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) { + String image = PostgreSQLContainer.IMAGE + ":" + options.getRequiredValue(IMAGE_TAG_OPTION); + PostgreSQLContainer container = new PostgreSQLContainer<>(image) + .withDatabaseName(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)); + + if (Boolean.TRUE.equals(options.getValue(REUSABLE_OPTION))) { + container.withReuse(true); + } + return new PostgreSQLR2DBCDatabaseContainer(container); + } +} diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java new file mode 100644 index 00000000000..505b37859ba --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java @@ -0,0 +1,27 @@ +package org.testcontainers.containers; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; + +public class PostgreSQLR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { + + @Override + protected PostgreSQLContainer createContainer() { + return new PostgreSQLContainer<>(); + } + + @Override + protected ConnectionFactoryOptions getOptions(PostgreSQLContainer container) { + // get_options { + ConnectionFactoryOptions options = PostgreSQLR2DBCDatabaseContainer.getOptions( + container + ); + // } + + return options; + } + + protected String createR2DBCUrl() { + return "r2dbc:tc:postgresql:///db?TC_IMAGE_TAG=10-alpine"; + } +} diff --git a/modules/postgresql/src/test/resources/logback-test.xml b/modules/postgresql/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/postgresql/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle new file mode 100644 index 00000000000..a7388ebc6d2 --- /dev/null +++ b/modules/r2dbc/build.gradle @@ -0,0 +1,20 @@ +plugins { + id "java-test-fixtures" +} + +description = "Testcontainers :: R2DBC" + +dependencies { + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + + compile project(':testcontainers') + compile 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE' + + testCompile 'org.assertj:assertj-core:3.14.0' + testCompile 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' + testCompile project(':postgresql') + + testFixturesCompile 'io.projectreactor:reactor-core:3.3.4.RELEASE' + testFixturesCompile 'org.assertj:assertj-core:3.14.0' +} diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java new file mode 100644 index 00000000000..e64d19a9f49 --- /dev/null +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java @@ -0,0 +1,23 @@ +package org.testcontainers.r2dbc; + +import org.reactivestreams.Subscription; + +import java.util.concurrent.atomic.AtomicBoolean; + +class CancellableSubscription implements Subscription { + + private final AtomicBoolean cancelled = new AtomicBoolean(); + + @Override + public void request(long n) { + } + + @Override + public void cancel() { + cancelled.set(true); + } + + public boolean isCancelled() { + return cancelled.get(); + } +} diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java new file mode 100644 index 00000000000..489d545429d --- /dev/null +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java @@ -0,0 +1,161 @@ +package org.testcontainers.r2dbc; + +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.ConnectionFactory; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +/** + * Design notes: + * - ConnectionPublisher is Mono-like (0..1), the request amount is ignored + * - given the testing nature, the performance requirements are less strict + * - "synchronized" is used to avoid races + * - Reactive Streams spec violations are not checked (e.g. non-positive request) + */ +class ConnectionPublisher implements Publisher { + + private final Supplier> futureSupplier; + + ConnectionPublisher(Supplier> futureSupplier) { + this.futureSupplier = futureSupplier; + } + + @Override + public void subscribe(Subscriber actual) { + actual.onSubscribe(new StateMachineSubscription(actual)); + } + + private class StateMachineSubscription implements Subscription { + + private final Subscriber actual; + + Subscription subscriptionState; + + StateMachineSubscription(Subscriber actual) { + this.actual = actual; + subscriptionState = new WaitRequestSubscriptionState(); + } + + @Override + public synchronized void request(long n) { + subscriptionState.request(n); + } + + @Override + public synchronized void cancel() { + subscriptionState.cancel(); + } + + synchronized void transitionTo(SubscriptionState newState) { + subscriptionState = newState; + newState.enter(); + } + + abstract class SubscriptionState implements Subscription { + void enter() { + } + } + + class WaitRequestSubscriptionState extends SubscriptionState { + + @Override + public void request(long n) { + transitionTo(new WaitFutureCompletionSubscriptionState()); + } + + @Override + public void cancel() { + } + } + + class WaitFutureCompletionSubscriptionState extends SubscriptionState { + + private CompletableFuture future; + + @Override + void enter() { + this.future = futureSupplier.get(); + + future.whenComplete((connectionFactory, e) -> { + if (e != null) { + actual.onSubscribe(EmptySubscription.INSTANCE); + actual.onError(e); + return; + } + + Publisher publisher = connectionFactory.create(); + transitionTo(new ProxySubscriptionState(publisher)); + }); + } + + @Override + public void request(long n) { + } + + @Override + public void cancel() { + future.cancel(true); + } + } + + class ProxySubscriptionState extends SubscriptionState implements Subscriber { + + private final Publisher publisher; + + private Subscription s; + + private boolean cancelled = false; + + ProxySubscriptionState(Publisher publisher) { + this.publisher = publisher; + } + + @Override + void enter() { + publisher.subscribe(this); + } + + @Override + public void request(long n) { + // Ignore + } + + @Override + public synchronized void cancel() { + cancelled = true; + if (s != null) { + s.cancel(); + } + } + + @Override + public synchronized void onSubscribe(Subscription s) { + this.s = s; + if (!cancelled) { + s.request(1); + } else { + s.cancel(); + } + } + + @Override + public void onNext(Connection connection) { + actual.onNext(connection); + } + + @Override + public void onError(Throwable t) { + actual.onError(t); + } + + @Override + public void onComplete() { + actual.onComplete(); + } + } + } +} diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java new file mode 100644 index 00000000000..7828d121c6f --- /dev/null +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java @@ -0,0 +1,17 @@ +package org.testcontainers.r2dbc; + +import org.reactivestreams.Subscription; + +enum EmptySubscription implements Subscription { + INSTANCE; + + @Override + public void request(long n) { + + } + + @Override + public void cancel() { + + } +} diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java new file mode 100644 index 00000000000..f642a60d67c --- /dev/null +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java @@ -0,0 +1,73 @@ +package org.testcontainers.r2dbc; + +import com.google.auto.service.AutoService; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryOptions; +import io.r2dbc.spi.ConnectionFactoryProvider; + +/** + * Hide inner classes that must be public due to the way {@link java.util.ServiceLoader} works + */ +class Hidden { + + @AutoService(ConnectionFactoryProvider.class) + public static final class TestcontainersR2DBCConnectionFactoryProvider implements ConnectionFactoryProvider { + + public static final String DRIVER = "tc"; + + @Override + public ConnectionFactory create(ConnectionFactoryOptions options) { + options = sanitize(options); + options = removeProxying(options); + + return new TestcontainersR2DBCConnectionFactory(options); + } + + private ConnectionFactoryOptions sanitize(ConnectionFactoryOptions options) { + ConnectionFactoryOptions.Builder builder = options.mutate(); + + Object reusable = options.getValue(R2DBCDatabaseContainerProvider.REUSABLE_OPTION); + if (reusable instanceof String) { + builder.option(R2DBCDatabaseContainerProvider.REUSABLE_OPTION, Boolean.valueOf((String) reusable)); + } + return builder.build(); + } + + private ConnectionFactoryOptions removeProxying(ConnectionFactoryOptions options) { + // To delegate to the next factory provider, inspect the PROTOCOL and convert it to the next DRIVER and PROTOCOL values. + // + // example: + // | Property | Input | Output | + // |----------|-----------------|--------------| + // | DRIVER | tc | postgres | + // | PROTOCOL | postgres | | + + String protocol = options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL); + if (protocol.trim().length() == 0) { + throw new IllegalArgumentException("Invalid protocol: " + protocol); + } + String[] protocols = protocol.split(":", 2); + String driverDelegate = protocols[0]; + + // when protocol does NOT contain COLON, the length becomes 1 + String protocolDelegate = protocols.length == 2 ? protocols[1] : ""; + + return ConnectionFactoryOptions.builder() + .from(options) + .option(ConnectionFactoryOptions.DRIVER, driverDelegate) + .option(ConnectionFactoryOptions.PROTOCOL, protocolDelegate) + .build(); + } + + @Override + public boolean supports(ConnectionFactoryOptions options) { + return DRIVER.equals(options.getValue(ConnectionFactoryOptions.DRIVER)); + } + + @Override + public String getDriver() { + return DRIVER; + } + + } +} diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java new file mode 100644 index 00000000000..a303cbafff8 --- /dev/null +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java @@ -0,0 +1,9 @@ +package org.testcontainers.r2dbc; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.lifecycle.Startable; + +public interface R2DBCDatabaseContainer extends Startable { + + ConnectionFactoryOptions configure(ConnectionFactoryOptions options); +} diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java new file mode 100644 index 00000000000..2eabc0d521b --- /dev/null +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java @@ -0,0 +1,15 @@ +package org.testcontainers.r2dbc; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import io.r2dbc.spi.Option; + +public interface R2DBCDatabaseContainerProvider { + + Option REUSABLE_OPTION = Option.valueOf("TC_REUSABLE"); + + Option IMAGE_TAG_OPTION = Option.valueOf("TC_IMAGE_TAG"); + + boolean supports(ConnectionFactoryOptions options); + + R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options); +} diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java new file mode 100644 index 00000000000..1a0fc57ad8c --- /dev/null +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java @@ -0,0 +1,104 @@ +package org.testcontainers.r2dbc; + +import io.r2dbc.spi.Closeable; +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryMetadata; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.reactivestreams.Publisher; +import org.testcontainers.lifecycle.Startable; + +import java.util.ServiceLoader; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.StreamSupport; + +class TestcontainersR2DBCConnectionFactory implements ConnectionFactory, Closeable { + + private static final AtomicLong THREAD_COUNT = new AtomicLong(); + + private static final Executor EXECUTOR = Executors.newCachedThreadPool(r -> { + Thread thread = new Thread(r); + thread.setName("testcontainers-r2dbc-" + THREAD_COUNT.getAndIncrement()); + thread.setDaemon(true); + return thread; + }); + + private final ConnectionFactoryOptions options; + + private final R2DBCDatabaseContainerProvider containerProvider; + + private CompletableFuture future; + + TestcontainersR2DBCConnectionFactory(ConnectionFactoryOptions options) { + this.options = options; + + containerProvider = StreamSupport.stream(ServiceLoader.load(R2DBCDatabaseContainerProvider.class).spliterator(), false) + .filter(it -> it.supports(options)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Missing provider for " + options)); + } + + @Override + public Publisher create() { + return new ConnectionPublisher( + () -> { + if (future == null) { + synchronized (this) { + if (future == null) { + future = CompletableFuture.supplyAsync(() -> { + R2DBCDatabaseContainer container = containerProvider.createContainer(options); + container.start(); + return container; + }, EXECUTOR); + } + } + } + return future.thenApply(it -> { + return ConnectionFactories.find( + it.configure(options) + ); + }); + } + ); + } + + @Override + public ConnectionFactoryMetadata getMetadata() { + // TODO check whether it is fine to call it without setting the host/port and other values + return ConnectionFactories.find(options).getMetadata(); + } + + @Override + public Publisher close() { + return s -> { + CompletableFuture futureRef; + synchronized (this) { + futureRef = this.future; + this.future = null; + } + + CancellableSubscription subscription = new CancellableSubscription(); + s.onSubscribe(subscription); + + if (futureRef == null) { + if (!subscription.isCancelled()) { + s.onComplete(); + } + } else { + futureRef.thenAcceptAsync(Startable::stop, EXECUTOR); + + EXECUTOR.execute(() -> { + futureRef.cancel(true); + if (!subscription.isCancelled()) { + s.onComplete(); + } + }); + } + }; + } + +} diff --git a/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java b/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java new file mode 100644 index 00000000000..6fad93f0e2a --- /dev/null +++ b/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java @@ -0,0 +1,79 @@ +package org.testcontainers.r2dbc; + +import io.r2dbc.postgresql.api.PostgresqlException; +import io.r2dbc.spi.Closeable; +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.Result; +import org.assertj.core.api.Assertions; +import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestcontainersR2DBCConnectionFactoryTest { + + @Test + public void failsOnUnknownProvider() { + String nonExistingProvider = UUID.randomUUID().toString(); + Assertions + .assertThatThrownBy(() -> { + ConnectionFactories.get(String.format("r2dbc:tc:%s:///db", nonExistingProvider)); + }) + .hasMessageContaining("Missing provider") + .hasMessageContaining(nonExistingProvider); + } + + @Test + public void reusesUntilConnectionFactoryIsClosed() { + String url = "r2dbc:tc:postgresql:///db?TC_IMAGE_TAG=10-alpine"; + ConnectionFactory connectionFactory = ConnectionFactories.get(url); + + Integer updated = Flux + .usingWhen( + connectionFactory.create(), + connection -> { + return Mono + .from(connection.createStatement("CREATE TABLE test(id integer PRIMARY KEY)").execute()) + .thenMany(connection.createStatement("INSERT INTO test(id) VALUES(123)").execute()) + .flatMap(Result::getRowsUpdated); + }, + Connection::close + ) + .blockFirst(); + + assertThat(updated).isEqualTo(1); + + Flux select = Flux + .usingWhen( + Flux.defer(connectionFactory::create), + connection -> { + return Flux + .from(connection.createStatement("SELECT COUNT(*) FROM test").execute()) + .flatMap(it -> it.map((row, meta) -> (Long) row.get(0))); + }, + Connection::close + ); + + Long rows = select.blockFirst(); + + assertThat(rows).isEqualTo(1); + + close(connectionFactory); + + Assertions + .assertThatThrownBy(select::blockFirst) + .isInstanceOf(PostgresqlException.class) + // relation "X" does not exists + // https://github.com/postgres/postgres/blob/REL_10_0/src/backend/utils/errcodes.txt#L349 + .returns("42P01", e -> ((PostgresqlException) e).getErrorDetails().getCode()); + } + + private static void close(ConnectionFactory connectionFactory) { + Mono.from(((Closeable) connectionFactory).close()).block(); + } +} diff --git a/modules/r2dbc/src/test/resources/logback-test.xml b/modules/r2dbc/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/r2dbc/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java b/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java new file mode 100644 index 00000000000..7f14ecca2a7 --- /dev/null +++ b/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java @@ -0,0 +1,64 @@ +package org.testcontainers.r2dbc; + +import io.r2dbc.spi.Closeable; +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class AbstractR2DBCDatabaseContainerTest> { + + protected abstract ConnectionFactoryOptions getOptions(T container); + + protected abstract String createR2DBCUrl(); + + protected String createTestQuery(int result) { + return String.format("SELECT %d", result); + } + + @Test + public final void testGetOptions() { + try (T container = createContainer()) { + container.start(); + + ConnectionFactory connectionFactory = ConnectionFactories.get(getOptions(container)); + runTestQuery(connectionFactory); + } + } + + @Test + public final void testUrlSupport() { + ConnectionFactory connectionFactory = ConnectionFactories.get(createR2DBCUrl()); + runTestQuery(connectionFactory); + } + + protected abstract T createContainer(); + + protected void runTestQuery(ConnectionFactory connectionFactory) { + try { + int expected = 42; + Number result = Flux + .usingWhen( + connectionFactory.create(), + connection -> connection.createStatement(createTestQuery(expected)).execute(), + Connection::close + ) + .flatMap(it -> it.map((row, meta) -> (Number) row.get(0))) + .blockFirst(); + + assertThat(result) + .isNotNull() + .returns(expected, Number::intValue); + } finally { + if (connectionFactory instanceof Closeable) { + Mono.from(((Closeable) connectionFactory).close()).block(); + } + } + } +} From 8dede0455827f89c03e753ee75dc70326303de68 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Apr 2020 19:58:19 +0200 Subject: [PATCH 0590/4969] fix the shading exclusion list --- core/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/core/build.gradle b/core/build.gradle index 01575f0d351..84a20425cc5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -50,6 +50,7 @@ shadowJar { 'META-INF/services/javax.ws.rs.ext.*', 'META-INF/services/java.security.Provider', 'mozilla/public-suffix-list.txt', + 'module-info.class', ].each { exclude(it) } project.afterEvaluate { From 631a3f46971156e65f3f9843624acd4188768b71 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Sun, 12 Apr 2020 20:08:18 +0200 Subject: [PATCH 0591/4969] Support VNC recording with BrowserWebdriverContainer in Spock-Extension (#2548) Initially done as part of the Hackergarten at Gr8ConfEU 2018. Thanks to Tamer Shahin, Marcin Erdmann and Dawid Kublik for working on this! Fixes #631. --- modules/spock/build.gradle | 2 + .../spock/SpockTestDescription.groovy | 36 ++++++++ .../spock/TestcontainersExtension.groovy | 17 +++- .../TestcontainersMethodInterceptor.groovy | 25 +++++- .../spock/BrowserVncRecordingIT.groovy | 88 +++++++++++++++++++ 5 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy create mode 100644 modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 2bcf7431808..d091ce068dc 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -8,8 +8,10 @@ dependencies { compile project(':testcontainers') compile 'org.spockframework:spock-core:1.3-groovy-2.5' + testCompile project(':selenium') testCompile project(':mysql') testCompile project(':postgresql') + testCompile 'com.zaxxer:HikariCP:3.4.2' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy new file mode 100644 index 00000000000..85b58724000 --- /dev/null +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy @@ -0,0 +1,36 @@ +package org.testcontainers.spock + +import groovy.transform.PackageScope +import org.spockframework.runtime.extension.IMethodInvocation +import org.testcontainers.lifecycle.TestDescription + +/** + * Spock specific implementation of a Testcontainers TestDescription. + * + * Filesystem friendly name is based on Specification and Feature. + */ +@PackageScope +class SpockTestDescription implements TestDescription { + + String specName + String featureName + + static SpockTestDescription fromTestDescription(IMethodInvocation invocation) { + return new SpockTestDescription([ + specName: invocation.spec.name, + featureName: invocation.feature.name + ]) + } + + @Override + String getTestId() { + return getFilesystemFriendlyName() + } + + @Override + String getFilesystemFriendlyName() { + return [specName, featureName].collect { + URLEncoder.encode(it, 'UTF-8') + }.join('-') + } +} diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy index 9f26cf95451..1f66fd8f596 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy @@ -1,17 +1,32 @@ package org.testcontainers.spock +import org.spockframework.runtime.AbstractRunListener import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension +import org.spockframework.runtime.model.ErrorInfo import org.spockframework.runtime.model.SpecInfo class TestcontainersExtension extends AbstractAnnotationDrivenExtension { @Override void visitSpecAnnotation(Testcontainers annotation, SpecInfo spec) { - def interceptor = new TestcontainersMethodInterceptor(spec) + def listener = new ErrorListener() + def interceptor = new TestcontainersMethodInterceptor(spec, listener) spec.addSetupSpecInterceptor(interceptor) spec.addCleanupSpecInterceptor(interceptor) spec.addSetupInterceptor(interceptor) spec.addCleanupInterceptor(interceptor) + + spec.addListener(listener) + + } + + private class ErrorListener extends AbstractRunListener { + List errors = [] + + @Override + void error(ErrorInfo error) { + errors.add(error) + } } } diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy index d4b6f3ccc9d..a70ec0d6e53 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy @@ -6,13 +6,17 @@ import org.spockframework.runtime.model.FieldInfo import org.spockframework.runtime.model.SpecInfo import org.testcontainers.containers.DockerComposeContainer import org.testcontainers.containers.GenericContainer +import org.testcontainers.lifecycle.TestLifecycleAware +import org.testcontainers.spock.TestcontainersExtension.ErrorListener class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { private final SpecInfo spec + private final ErrorListener errorListener - TestcontainersMethodInterceptor(SpecInfo spec) { + TestcontainersMethodInterceptor(SpecInfo spec, ErrorListener errorListener) { this.spec = spec + this.errorListener = errorListener } @Override @@ -50,6 +54,13 @@ class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { @Override void interceptCleanupMethod(IMethodInvocation invocation) throws Throwable { + findAllTestLifecycleAwareContainers(invocation).each { + // we assume first error is the one we want + def maybeException = Optional.ofNullable(errorListener.errors[0]?.exception) + def testDescription = SpockTestDescription.fromTestDescription(invocation) + it.afterTest(testDescription, maybeException) + } + def containers = findAllContainers(false) stopContainers(containers, invocation) @@ -65,6 +76,14 @@ class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { } } + private List findAllTestLifecycleAwareContainers(IMethodInvocation invocation) { + spec.allFields.findAll { FieldInfo f -> + TestLifecycleAware.isAssignableFrom(f.type) + }.collect { + it.readValue(invocation.instance) as TestLifecycleAware + } + } + private List findAllComposeContainers(boolean shared) { spec.allFields.findAll { FieldInfo f -> DockerComposeContainer.isAssignableFrom(f.type) && f.shared == shared @@ -90,14 +109,14 @@ class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { private static void startComposeContainers(List compose, IMethodInvocation invocation) { compose.each { FieldInfo f -> DockerComposeContainer c = f.readValue(invocation.instance) as DockerComposeContainer - c.starting(null) + c.start() } } private static void stopComposeContainers(List compose, IMethodInvocation invocation) { compose.each { FieldInfo f -> DockerComposeContainer c = f.readValue(invocation.instance) as DockerComposeContainer - c.finished(null) + c.stop() } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy new file mode 100644 index 00000000000..794032a58c4 --- /dev/null +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy @@ -0,0 +1,88 @@ +package org.testcontainers.spock + +import org.intellij.lang.annotations.Language +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification +import spock.lang.Unroll +import spock.util.EmbeddedSpecRunner + +import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL +import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_FAILING + +class BrowserVncRecordingIT extends Specification { + + @Rule + TemporaryFolder temp + + String recordingDir + + def setup() { + recordingDir = temp.getRoot().getAbsolutePath() + } + + @Unroll("For recording mode #recordingMode and failing test is #fails records video file named '#videoFileName'") + def "retains all recordings for RECORD_ALL if successful"() { + given: + + //noinspection GrPackage + @Language("groovy") + String myTest = """ +package org.testcontainers.spock + +import org.openqa.selenium.chrome.ChromeOptions +import org.openqa.selenium.remote.RemoteWebDriver +import org.testcontainers.containers.BrowserWebDriverContainer +import spock.lang.Specification + +import java.util.concurrent.TimeUnit + +import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode + +@Testcontainers +class BrowserWebdriverContainerIT extends Specification { + + BrowserWebDriverContainer browserContainer = new BrowserWebDriverContainer() + .withCapabilities(new ChromeOptions()) + .withRecordingMode("$recordingMode" as VncRecordingMode, new File("$recordingDir")) + + RemoteWebDriver driver + + def setup() { + driver = browserContainer.getWebDriver() + driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS) + } + + def "should record"() { + when: + driver.get("http://en.wikipedia.org/wiki/Randomness") + + then: + driver.findElementByPartialLinkText("pattern").isDisplayed() == !$fails + } + +} + + +""" + + when: + EmbeddedSpecRunner runner = new EmbeddedSpecRunner(throwFailure: false) + runner.run(myTest) + + then: + def videoDir = temp.getRoot().list() + if (videoFileName.isEmpty()) { + videoDir.length == 0 + } else { + videoDir.find { it.contains(videoFileName) } + } + + where: + recordingMode | fails | videoFileName + RECORD_ALL | false | 'BrowserWebdriverContainerIT-should+record' + RECORD_FAILING | false | '' + RECORD_FAILING | true | 'BrowserWebdriverContainerIT-should+record' + } + +} From c6e0cd9faf83a160bf1cb4b3f0b6b7b9535daad2 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Apr 2020 20:23:51 +0200 Subject: [PATCH 0592/4969] Rewrite Couchbase module. closes #2447 (#2491) * Rewrite couchbase module. closes #2447 This changeset completely reworks the couchbase module and hopefully greatly improve the out-of-the-box experience. Note that this is a breaking change over the previous code because by intention it does NOT depend on SDK 2 so you can test SDK 2 and 3 with it at the same time. Highlights: - Removed the need for a SDK, so both 2 and 3 can be used with it. - Updated to 6.5.0 baseline and using alternate addresses for "proper" port exposure without having to rely on the socat proxy container like the previous version had to. - Allows to define which services should be exposed and handles states automatically (i.e. will not try to create the primary index if the query service is not enabled). Note that a bunch of tests have been removed since they are not adequate anymore. A side effect of the alternate address change is that older servers cannot be used. 6.5.0 is available in both CE and EE, and Couchbase in general allows EE versions to be used in development and testing so we should use it if we can. * Wait until query respsonds with 200 * fixes * add `getBootstrap*DirectPort()` methods, review fixes * Restore `getConnectionString()` * Apply suggestions from code review Co-Authored-By: Kevin Wittek * Update docs * Update docs (2) Co-authored-by: Michael Nitschinger Co-authored-by: Kevin Wittek --- docs/modules/databases/couchbase.md | 78 +- modules/couchbase/build.gradle | 3 +- .../couchbase/AbstractCouchbaseTest.java | 72 -- .../couchbase/BucketDefinition.java | 69 ++ .../couchbase/CouchbaseContainer.java | 683 +++++++++--------- .../CouchbaseQueryServiceWaitStrategy.java | 55 -- .../couchbase/CouchbaseService.java | 44 ++ .../couchbase/BaseCouchbaseContainerTest.java | 82 --- .../couchbase/Couchbase4_6Test.java | 14 - .../couchbase/Couchbase5_1Test.java | 14 - .../couchbase/Couchbase5_5Test.java | 14 - .../couchbase/CouchbaseCommunity5_1Test.java | 32 - .../couchbase/CouchbaseContainerTest.java | 78 +- 13 files changed, 530 insertions(+), 708 deletions(-) delete mode 100644 modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java create mode 100644 modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java delete mode 100644 modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseQueryServiceWaitStrategy.java create mode 100644 modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java delete mode 100644 modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java delete mode 100644 modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java delete mode 100644 modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java delete mode 100644 modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java delete mode 100644 modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java diff --git a/docs/modules/databases/couchbase.md b/docs/modules/databases/couchbase.md index f6d014a42d4..b71ee5de327 100644 --- a/docs/modules/databases/couchbase.md +++ b/docs/modules/databases/couchbase.md @@ -8,65 +8,25 @@ Testcontainers module for Couchbase. [Couchbase](https://www.couchbase.com/) is Running Couchbase as a stand-in in a test: -### Create your own bucket - -```java -public class SomeTest { - - @Rule - public CouchbaseContainer couchbase = new CouchbaseContainer() - .withClusterAdmin("admin", "secret") - .withNewBucket(DefaultBucketSettings.builder() - .enableFlush(true) - .name("bucket-name") - .password("secret") - .quota(100) - .type(BucketType.COUCHBASE) - .build()); - - @Test - public void someTestMethod() { - Bucket bucket = couchbase.getCouchbaseCluster().openBucket("bucket-name"); - - // ... interact with client as if using Couchbase normally - } -} -``` - -### Use preconfigured default bucket - -Bucket is cleared after each test - -```java -public class SomeTest extends AbstractCouchbaseTest { - - @Test - public void someTestMethod() { - Bucket bucket = getBucket(); - - // ... interact with client as if using Couchbase normally - } -} -``` - -### Special consideration - -Couchbase container is configured to use random available [ports](https://developer.couchbase.com/documentation/server/current/install/install-ports.html) for some ports only, as [Couchbase Java SDK](https://developer.couchbase.com/documentation/server/current/sdk/java/start-using-sdk.html) permit to configure only some ports: - -- **8091** : REST/HTTP traffic ([bootstrapHttpDirectPort](http://docs.couchbase.com/sdk-api/couchbase-java-client-2.4.6/com/couchbase/client/java/env/DefaultCouchbaseEnvironment.Builder.html#bootstrapCarrierDirectPort-int-)) -- **18091** : REST/HTTP traffic with SSL ([bootstrapHttpSslPort](http://docs.couchbase.com/sdk-api/couchbase-java-client-2.4.6/com/couchbase/client/java/env/DefaultCouchbaseEnvironment.Builder.html#bootstrapCarrierSslPort-int-)) -- **11210** : memcached ([bootstrapCarrierDirectPort](http://docs.couchbase.com/sdk-api/couchbase-java-client-2.4.6/com/couchbase/client/java/env/DefaultCouchbaseEnvironment.Builder.html#bootstrapCarrierDirectPort-int-)) -- **11207** : memcached SSL ([bootstrapCarrierSslPort](http://docs.couchbase.com/sdk-api/couchbase-java-client-2.4.6/com/couchbase/client/java/env/DefaultCouchbaseEnvironment.Builder.html#bootstrapCarrierSslPort-int-)) - -All other ports cannot be changed by Java SDK, there are sadly fixed: - -- **8092** : Queries, views, XDCR -- **8093** : REST/HTTP Query service -- **8094** : REST/HTTP Search Service -- **8095** : REST/HTTP Analytic service - -So if you disable Query, Search and Analytic service, you can run multiple instance of this container, otherwise, you're stuck with one instance, for now. - +1. Define a bucket: + + [Bucket Definition](../../../modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java) inside_block:bucket_definition + + +2. define a container: + + [Container definition](../../../modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java) inside_block:container_definition + + +3. create an environment & cluster: + + [Cluster creation](../../../modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java) inside_block:cluster_creation + + +4. authenticate: + + [Authentication](../../../modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java) inside_block:auth + ## Adding this module to your project dependencies diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 66f29fc4718..095f8828aac 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,7 +2,6 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - compile 'com.couchbase.client:java-client:2.7.13' - testCompile project(':test-support') + testCompile 'com.couchbase.client:java-client:2.7.13' } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java deleted file mode 100644 index 7fd99ca9fbc..00000000000 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/AbstractCouchbaseTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.testcontainers.couchbase; - -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.CouchbaseCluster; -import com.couchbase.client.java.bucket.BucketType; -import com.couchbase.client.java.cluster.BucketSettings; -import com.couchbase.client.java.cluster.DefaultBucketSettings; -import com.couchbase.client.java.query.N1qlParams; -import com.couchbase.client.java.query.N1qlQuery; -import com.couchbase.client.java.query.consistency.ScanConsistency; -import org.junit.After; - -import java.util.concurrent.TimeUnit; - -/** - * Basic class that can be used for couchbase tests. It will clear the database after every test. - */ -public abstract class AbstractCouchbaseTest { - - public static final String TEST_BUCKET = "test"; - - public static final String DEFAULT_PASSWORD = "password"; - - Bucket bucket; - - @After - public void clear() { - try { - if (getCouchbaseContainer().isIndex() && getCouchbaseContainer().isQuery() && getCouchbaseContainer().isPrimaryIndex()) { - getBucket().query( - N1qlQuery.simple(String.format("DELETE FROM `%s`", getBucket().name()), - N1qlParams.build().consistency(ScanConsistency.STATEMENT_PLUS))); - } else { - getBucket().bucketManager().flush(); - } - } finally { - bucket.close(60, TimeUnit.SECONDS); - bucket = null; - } - } - - protected abstract CouchbaseContainer getCouchbaseContainer(); - - protected static CouchbaseContainer initCouchbaseContainer(String imageName) { - CouchbaseContainer couchbaseContainer = (imageName == null) ? new CouchbaseContainer() : new CouchbaseContainer(imageName); - couchbaseContainer.withNewBucket(getDefaultBucketSettings()); - return couchbaseContainer; - } - - protected static BucketSettings getDefaultBucketSettings() { - return DefaultBucketSettings.builder() - .enableFlush(true) - .name(TEST_BUCKET) - .password(DEFAULT_PASSWORD) - .quota(100) - .replicas(0) - .type(BucketType.COUCHBASE) - .build(); - } - - protected synchronized Bucket getBucket() { - if (bucket == null) { - bucket = openBucket(TEST_BUCKET, DEFAULT_PASSWORD); - } - return bucket; - } - - private Bucket openBucket(String bucketName, String password) { - CouchbaseCluster cluster = getCouchbaseContainer().getCouchbaseCluster(); - return cluster.openBucket(bucketName, password); - } -} diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java new file mode 100644 index 00000000000..8c2b11403ad --- /dev/null +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Couchbase, Inc. + * + * 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.testcontainers.couchbase; + +/** + * Allows to configure the properties of a bucket that should be created. + */ +public class BucketDefinition { + + private final String name; + private boolean queryPrimaryIndex = true; + private int quota = 100; + + public BucketDefinition(final String name) { + this.name = name; + } + + /** + * Sets a custom bucket quota (100MB by default). + * + * @param quota the quota to set for the bucket. + * @return this {@link BucketDefinition} for chaining purposes. + */ + public BucketDefinition withQuota(final int quota) { + if (quota < 100) { + throw new IllegalArgumentException("Bucket quota cannot be less than 100MB!"); + } + this.quota = quota; + return this; + } + + /** + * Allows to disable creating a primary index for this bucket (enabled by default). + * + * @param create if false, a primary index will not be created. + * @return this {@link BucketDefinition} for chaining purposes. + */ + public BucketDefinition withPrimaryIndex(final boolean create) { + this.queryPrimaryIndex = create; + return this; + } + + public String getName() { + return name; + } + + public boolean hasPrimaryIndex() { + return queryPrimaryIndex; + } + + public int getQuota() { + return quota; + } + +} diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index e43cf8f652d..14e5744bb6d 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Couchbase, Inc. + * Copyright (c) 2020 Couchbase, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,447 +15,424 @@ */ package org.testcontainers.couchbase; -import com.couchbase.client.core.utils.Base64; -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.CouchbaseCluster; -import com.couchbase.client.java.cluster.*; -import com.couchbase.client.java.env.CouchbaseEnvironment; -import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; -import com.couchbase.client.java.query.Index; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.command.InspectContainerResponse; -import com.google.common.collect.Lists; -import lombok.*; -import org.apache.commons.compress.utils.Sets; -import org.apache.commons.io.IOUtils; -import org.jetbrains.annotations.NotNull; +import com.github.dockerjava.api.model.ContainerNetwork; +import okhttp3.Credentials; +import okhttp3.FormBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.Network; -import org.testcontainers.containers.SocatContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; -import org.testcontainers.images.builder.Transferable; -import org.testcontainers.utility.ThrowingFunction; +import org.testcontainers.containers.wait.strategy.WaitAllStrategy; -import java.io.DataOutputStream; import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static java.net.HttpURLConnection.HTTP_OK; -import static org.testcontainers.couchbase.CouchbaseContainer.CouchbasePort.*; /** - * Based on Laurent Doguin version, + * The couchbase container initializes and configures a Couchbase Server single node cluster. *

- * optimized by Tayeb Chlyah + * Note that it does not depend on a specific couchbase SDK, so it can be used with both the Java SDK 2 and 3 as well + * as the Scala SDK 1 or newer. We recommend using the latest and greatest SDKs for the best experience. */ -@AllArgsConstructor public class CouchbaseContainer extends GenericContainer { - public static final String VERSION = "5.5.1"; - public static final String DOCKER_IMAGE_NAME = "couchbase/server:"; - public static final ObjectMapper MAPPER = new ObjectMapper(); - public static final String STATIC_CONFIG = "/opt/couchbase/etc/couchbase/static_config"; - public static final String CAPI_CONFIG = "/opt/couchbase/etc/couchdb/default.d/capi.ini"; + private static final int MGMT_PORT = 8091; + + private static final int MGMT_SSL_PORT = 18091; + + private static final int VIEW_PORT = 8092; - private static final int REQUIRED_DEFAULT_PASSWORD_LENGTH = 6; + private static final int VIEW_SSL_PORT = 18092; - private String memoryQuota = "300"; + private static final int QUERY_PORT = 8093; - private String indexMemoryQuota = "300"; + private static final int QUERY_SSL_PORT = 18093; - private String clusterUsername = "Administrator"; + private static final int SEARCH_PORT = 8094; - private String clusterPassword = "password"; + private static final int SEARCH_SSL_PORT = 18094; - private boolean keyValue = true; + private static final int KV_PORT = 11210; - @Getter - private boolean query = true; + private static final int KV_SSL_PORT = 11207; - @Getter - private boolean index = true; + private static final String DOCKER_IMAGE_NAME = "couchbase/server"; - @Getter - private boolean primaryIndex = true; + private static final String VERSION = "6.5.0"; - @Getter - private boolean fts = false; + private static final ObjectMapper MAPPER = new ObjectMapper(); - @Getter(lazy = true) - private final CouchbaseEnvironment couchbaseEnvironment = createCouchbaseEnvironment(); + private static final OkHttpClient HTTP_CLIENT = new OkHttpClient(); - @Getter(lazy = true) - private final CouchbaseCluster couchbaseCluster = createCouchbaseCluster(); + private String username = "Administrator"; - private List newBuckets = new ArrayList<>(); + private String password = "password"; - private String urlBase; + private Set enabledServices = EnumSet.allOf(CouchbaseService.class); - private SocatContainer proxy; + private final List buckets = new ArrayList<>(); + /** + * Creates a new couchbase container with the default image and version. + */ public CouchbaseContainer() { - this(DOCKER_IMAGE_NAME + VERSION); + this(DOCKER_IMAGE_NAME + ":" + VERSION); } - public CouchbaseContainer(String imageName) { + /** + * Creates a new couchbase container with a custom image name. + * + * @param imageName the image name that should be used. + */ + public CouchbaseContainer(final String imageName) { super(imageName); - - withNetwork(Network.SHARED); - setWaitStrategy(new HttpWaitStrategy().forPath("/ui/index.html")); } - @Override - public Set getLivenessCheckPortNumbers() { - return Sets.newHashSet(getMappedPort(REST)); + /** + * Set custom username and password for the admin user. + * + * @param username the admin username to use. + * @param password the password for the admin user. + * @return this {@link CouchbaseContainer} for chaining purposes. + */ + public CouchbaseContainer withCredentials(final String username, final String password) { + checkNotRunning(); + this.username = username; + this.password = password; + return this; } - @Override - protected void configure() { - if (clusterPassword.length() < REQUIRED_DEFAULT_PASSWORD_LENGTH) { - logger().warn("The provided cluster admin password length is less then the default password policy length. " + - "Cluster start will fail if configured password requirements are not met."); - } + public CouchbaseContainer withBucket(final BucketDefinition bucketDefinition) { + checkNotRunning(); + this.buckets.add(bucketDefinition); + return this; } - @Override - @SneakyThrows - protected void doStart() { - startProxy(getNetworkAliases().get(0)); - try { - super.doStart(); - } catch (Throwable e) { - proxy.stop(); - throw e; - } + public CouchbaseContainer withEnabledServices(final CouchbaseService... enabled) { + checkNotRunning(); + this.enabledServices = EnumSet.copyOf(Arrays.asList(enabled)); + return this; } - @SneakyThrows - private void startProxy(String networkAlias) { - proxy = new SocatContainer().withNetwork(getNetwork()); - - for (CouchbasePort port : CouchbasePort.values()) { - if (port.isDynamic()) { - proxy.withTarget(port.getOriginalPort(), networkAlias); - } else { - proxy.addExposedPort(port.getOriginalPort()); - } - } - - proxy.setWaitStrategy(null); - proxy.start(); - - ExecCreateCmdResponse createCmdResponse = dockerClient - .execCreateCmd(proxy.getContainerId()) - .withCmd( - "sh", - "-c", - Stream.of(CouchbasePort.values()) - .map(port -> { - return "/usr/bin/socat " + - "TCP-LISTEN:" + port.getOriginalPort() + ",fork,reuseaddr " + - "TCP:" + networkAlias + ":" + getMappedPort(port); - }) - .collect(Collectors.joining(" & ", "true", "")) - ) - .exec(); - - dockerClient.execStartCmd(createCmdResponse.getId()) - .start() - .awaitCompletion(10, TimeUnit.SECONDS); + public final String getUsername() { + return username; } - @Override - public List getExposedPorts() { - return proxy.getExposedPorts(); + public final String getPassword() { + return password; } - @Override - public String getContainerIpAddress() { - return proxy.getContainerIpAddress(); + public int getBootstrapCarrierDirectPort() { + return getMappedPort(KV_PORT); } - @Override - public Integer getMappedPort(int originalPort) { - return proxy.getMappedPort(originalPort); + public int getBootstrapHttpDirectPort() { + return getMappedPort(MGMT_PORT); } - protected Integer getMappedPort(CouchbasePort port) { - return getMappedPort(port.getOriginalPort()); + public String getConnectionString() { + return String.format("couchbase://%s:%d", getContainerIpAddress(), getBootstrapCarrierDirectPort()); } @Override - public List getBoundPortNumbers() { - return proxy.getBoundPortNumbers(); - } - - @Override - @SuppressWarnings({"unchecked", "ConstantConditions"}) - public void stop() { - try { - stopCluster(); - ((AtomicReference) (Object) couchbaseEnvironment).set(null); - ((AtomicReference) (Object) couchbaseCluster).set(null); - } finally { - Stream.of(super::stop, proxy::stop).parallel().forEach(Runnable::run); + protected void configure() { + super.configure(); + + WaitAllStrategy waitStrategy = new WaitAllStrategy(); + + // Makes sure that all nodes in the cluster are healthy. + waitStrategy = waitStrategy.withStrategy( + new HttpWaitStrategy() + .forPath("/pools/default") + .forPort(MGMT_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + .forResponsePredicate(response -> { + try { + return Optional.of(MAPPER.readTree(response)) + .map(n -> n.at("/nodes/0/status")) + .map(JsonNode::asText) + .map("healthy"::equals) + .orElse(false); + } catch (IOException e) { + logger().error("Unable to parse response {}", response); + return false; + } + }) + ); + + if (enabledServices.contains(CouchbaseService.QUERY)) { + waitStrategy = waitStrategy.withStrategy( + new HttpWaitStrategy() + .forPath("/admin/ping") + .forPort(QUERY_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + ); } - } - - private void stopCluster() { - getCouchbaseCluster().disconnect(); - getCouchbaseEnvironment().shutdown(); - } - - public CouchbaseContainer withNewBucket(BucketSettings bucketSettings) { - newBuckets.add(new BucketAndUserSettings(bucketSettings)); - return self(); - } - public CouchbaseContainer withNewBucket(BucketSettings bucketSettings, UserSettings userSettings) { - newBuckets.add(new BucketAndUserSettings(bucketSettings, userSettings)); - return self(); + waitingFor(waitStrategy); } - @SneakyThrows - public void initCluster() { - urlBase = String.format("http://%s:%s", getContainerIpAddress(), getMappedPort(REST)); - String poolURL = "/pools/default"; - String poolPayload = "memoryQuota=" + URLEncoder.encode(memoryQuota, "UTF-8") + "&indexMemoryQuota=" + URLEncoder.encode(indexMemoryQuota, "UTF-8"); - - String setupServicesURL = "/node/controller/setupServices"; - StringBuilder servicePayloadBuilder = new StringBuilder(); - if (keyValue) { - servicePayloadBuilder.append("kv,"); - } - if (query) { - servicePayloadBuilder.append("n1ql,"); - } - if (index) { - servicePayloadBuilder.append("index,"); - } - if (fts) { - servicePayloadBuilder.append("fts,"); + @Override + protected void containerIsStarting(final InspectContainerResponse containerInfo) { + logger().debug("Couchbase container is starting, performing configuration."); + + waitUntilNodeIsOnline(); + renameNode(); + initializeServices(); + configureAdminUser(); + configureExternalPorts(); + if (enabledServices.contains(CouchbaseService.INDEX)) { + configureIndexer(); } - String setupServiceContent = "services=" + URLEncoder.encode(servicePayloadBuilder.toString(), "UTF-8"); - - String webSettingsURL = "/settings/web"; - String webSettingsContent = "username=" + URLEncoder.encode(clusterUsername, "UTF-8") + "&password=" + URLEncoder.encode(clusterPassword, "UTF-8") + "&port=8091"; - - callCouchbaseRestAPI(poolURL, poolPayload); - callCouchbaseRestAPI(setupServicesURL, setupServiceContent); - callCouchbaseRestAPI(webSettingsURL, webSettingsContent); - - createNodeWaitStrategy().waitUntilReady(this); - callCouchbaseRestAPI("/settings/indexes", "indexerThreads=0&logLevel=info&maxRollbackPoints=5&storageMode=memory_optimized"); } - @NotNull - private HttpWaitStrategy createNodeWaitStrategy() { - return new HttpWaitStrategy() - .forPath("/pools/default/") - .withBasicCredentials(clusterUsername, clusterPassword) - .forStatusCode(HTTP_OK) - .forResponsePredicate(response -> { - try { - return Optional.of(MAPPER.readTree(response)) - .map(n -> n.at("/nodes/0/status")) - .map(JsonNode::asText) - .map("healthy"::equals) - .orElse(false); - } catch (IOException e) { - logger().error("Unable to parse response {}", response); - return false; - } - }); - } - - public void createBucket(BucketSettings bucketSetting, UserSettings userSettings, boolean primaryIndex) { - ClusterManager clusterManager = getCouchbaseCluster().clusterManager(clusterUsername, clusterPassword); - // Insert Bucket - BucketSettings bucketSettings = clusterManager.insertBucket(bucketSetting); - try { - // Insert Bucket user - clusterManager.upsertUser(AuthDomain.LOCAL, bucketSetting.name(), userSettings); - } catch (Exception e) { - logger().warn("Unable to insert user '" + bucketSetting.name() + "', maybe you are using older version"); - } - if (index) { - Bucket bucket = getCouchbaseCluster().openBucket(bucketSettings.name(), bucketSettings.password()); - new CouchbaseQueryServiceWaitStrategy(bucket).waitUntilReady(this); - if (primaryIndex) { - bucket.query(Index.createPrimaryIndex().on(bucketSetting.name())); + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + createBuckets(); + logger().info("Couchbase container is ready! UI available at http://{}:{}", getContainerIpAddress(), getMappedPort(MGMT_PORT)); + } + + /** + * Before we can start configuring the host, we need to wait until the cluster manager is listening. + */ + private void waitUntilNodeIsOnline() { + new HttpWaitStrategy() + .forPort(MGMT_PORT) + .forPath("/pools") + .forStatusCode(200) + .waitUntilReady(this); + } + + /** + * Rebinds/renames the internal hostname. + *

+ * To make sure the internal hostname is different from the external (alternate) address and the SDK can pick it + * up automatically, we bind the internal hostname to the internal IP address. + */ + private void renameNode() { + logger().debug("Renaming Couchbase Node from localhost to {}", getContainerIpAddress()); + + Response response = doHttpRequest(MGMT_PORT, "/node/controller/rename", "POST", new FormBody.Builder() + .add("hostname", getInternalIpAddress()) + .build(), false + ); + + checkSuccessfulResponse(response, "Could not rename couchbase node"); + } + + /** + * Initializes services based on the configured enabled services. + */ + private void initializeServices() { + logger().debug("Initializing couchbase services on host: {}", enabledServices); + + final String services = enabledServices.stream().map(s -> { + switch (s) { + case KV: return "kv"; + case QUERY: return "n1ql"; + case INDEX: return "index"; + case SEARCH: return "fts"; + default: throw new IllegalStateException("Unknown service!"); } + }).collect(Collectors.joining(",")); + + Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder() + .add("services", services) + .build(), false + ); + + checkSuccessfulResponse(response, "Could not enable couchbase services"); + } + + /** + * Configures the admin user on the couchbase node. + *

+ * After this stage, all subsequent API calls need to have the basic auth header set. + */ + private void configureAdminUser() { + logger().debug("Configuring couchbase admin user with username: \"{}\"", username); + + Response response = doHttpRequest(MGMT_PORT, "/settings/web", "POST", new FormBody.Builder() + .add("username", username) + .add("password", password) + .add("port", Integer.toString(MGMT_PORT)) + .build(), false); + + checkSuccessfulResponse(response, "Could not configure couchbase admin user"); + } + + /** + * Configures the external ports for SDK access. + *

+ * Since the internal ports are not accessible from outside the container, this code configures the "external" + * hostname and services to align with the mapped ports. The SDK will pick it up and then automatically connect + * to those ports. Note that for all services non-ssl and ssl ports are configured. + */ + private void configureExternalPorts() { + logger().debug("Mapping external ports to the alternate address configuration"); + + final FormBody.Builder builder = new FormBody.Builder(); + builder.add("hostname", getContainerIpAddress()); + builder.add("mgmt", Integer.toString(getMappedPort(MGMT_PORT))); + builder.add("mgmtSSL", Integer.toString(getMappedPort(MGMT_SSL_PORT))); + + if (enabledServices.contains(CouchbaseService.KV)) { + builder.add("kv", Integer.toString(getMappedPort(KV_PORT))); + builder.add("kvSSL", Integer.toString(getMappedPort(KV_SSL_PORT))); + builder.add("capi", Integer.toString(getMappedPort(VIEW_PORT))); + builder.add("capiSSL", Integer.toString(getMappedPort(VIEW_SSL_PORT))); } - } - public void callCouchbaseRestAPI(String url, String payload) throws IOException { - String fullUrl = urlBase + url; - @Cleanup("disconnect") - HttpURLConnection httpConnection = (HttpURLConnection) ((new URL(fullUrl).openConnection())); - httpConnection.setDoOutput(true); - httpConnection.setRequestMethod("POST"); - httpConnection.setRequestProperty("Content-Type", - "application/x-www-form-urlencoded"); - String encoded = Base64.encode((clusterUsername + ":" + clusterPassword).getBytes("UTF-8")); - httpConnection.setRequestProperty("Authorization", "Basic " + encoded); - @Cleanup - DataOutputStream out = new DataOutputStream(httpConnection.getOutputStream()); - out.writeBytes(payload); - out.flush(); - httpConnection.getResponseCode(); - } + if (enabledServices.contains(CouchbaseService.QUERY)) { + builder.add("n1ql", Integer.toString(getMappedPort(QUERY_PORT))); + builder.add("n1qlSSL", Integer.toString(getMappedPort(QUERY_SSL_PORT))); + } - @Override - protected void containerIsCreated(String containerId) { - patchConfig(STATIC_CONFIG, this::addMappedPorts); - // capi needs a special configuration, see https://developer.couchbase.com/documentation/server/current/install/install-ports.html - patchConfig(CAPI_CONFIG, this::replaceCapiPort); - } + if (enabledServices.contains(CouchbaseService.SEARCH)) { + builder.add("fts", Integer.toString(getMappedPort(SEARCH_PORT))); + builder.add("ftsSSL", Integer.toString(getMappedPort(SEARCH_SSL_PORT))); + } - private void patchConfig(String configLocation, ThrowingFunction patchFunction) { - String patchedConfig = copyFileFromContainer(configLocation, - inputStream -> patchFunction.apply(IOUtils.toString(inputStream, StandardCharsets.UTF_8))); - copyFileToContainer(Transferable.of(patchedConfig.getBytes(StandardCharsets.UTF_8)), configLocation); - } + final Response response = doHttpRequest( + MGMT_PORT, + "/node/controller/setupAlternateAddresses/external", + "PUT", + builder.build(), + true + ); - private String addMappedPorts(String originalConfig) { - String portConfig = Stream.of(CouchbasePort.values()) - .filter(port -> !port.isDynamic()) - .map(port -> String.format("{%s, %d}.", port.name, getMappedPort(port))) - .collect(Collectors.joining("\n")); - return String.format("%s\n%s", originalConfig, portConfig); + checkSuccessfulResponse(response, "Could not configure external ports"); } - private String replaceCapiPort(String originalConfig) { - return Arrays.stream(originalConfig.split("\n")) - .map(s -> (s.matches("port\\s*=\\s*" + CAPI.getOriginalPort())) ? "port = " + getMappedPort(CAPI) : s) - .collect(Collectors.joining("\n")); - } + /** + * Configures the indexer service so that indexes can be created later on the bucket. + */ + private void configureIndexer() { + logger().debug("Configuring the indexer service"); - @Override - protected void containerIsStarted(InspectContainerResponse containerInfo) { - if (!newBuckets.isEmpty()) { - for (BucketAndUserSettings bucket : newBuckets) { - createBucket(bucket.getBucketSettings(), bucket.getUserSettings(), primaryIndex); - } - } - } + Response response = doHttpRequest(MGMT_PORT, "/settings/indexes", "POST", new FormBody.Builder() + .add("storageMode", "memory_optimized") + .build(), true + ); - private CouchbaseCluster createCouchbaseCluster() { - return CouchbaseCluster.create(getCouchbaseEnvironment(), getContainerIpAddress()); + checkSuccessfulResponse(response, "Could not configure the indexing service"); } - private DefaultCouchbaseEnvironment createCouchbaseEnvironment() { - initCluster(); - return DefaultCouchbaseEnvironment.builder() - .kvTimeout(10000) - .bootstrapCarrierDirectPort(getMappedPort(MEMCACHED)) - .bootstrapCarrierSslPort(getMappedPort(MEMCACHED_SSL)) - .bootstrapHttpDirectPort(getMappedPort(REST)) - .bootstrapHttpSslPort(getMappedPort(REST_SSL)) - .build(); - } + /** + * Based on the user-configured bucket definitions, creating buckets and corresponding indexes if needed. + */ + private void createBuckets() { + logger().debug("Creating " + buckets.size() + " buckets (and corresponding indexes)."); - public CouchbaseContainer withMemoryQuota(String memoryQuota) { - this.memoryQuota = memoryQuota; - return self(); - } + for (BucketDefinition bucket : buckets) { + logger().debug("Creating bucket \"" + bucket.getName() + "\""); - public CouchbaseContainer withIndexMemoryQuota(String indexMemoryQuota) { - this.indexMemoryQuota = indexMemoryQuota; - return self(); - } + Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder() + .add("name", bucket.getName()) + .add("ramQuotaMB", Integer.toString(bucket.getQuota())) + .build(), true); - public CouchbaseContainer withClusterAdmin(String username, String password) { - this.clusterUsername = username; - this.clusterPassword = password; - return self(); - } + checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName()); - public CouchbaseContainer withKeyValue(boolean keyValue) { - this.keyValue = keyValue; - return self(); - } + new HttpWaitStrategy() + .forPath("/pools/default/buckets/" + bucket.getName()) + .forPort(MGMT_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + .waitUntilReady(this); - public CouchbaseContainer withQuery(boolean query) { - this.query = query; - return self(); - } + if (bucket.hasPrimaryIndex()) { + if (enabledServices.contains(CouchbaseService.QUERY)) { + Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() + .add("statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`") + .build(), true); - public CouchbaseContainer withIndex(boolean index) { - this.index = index; - return self(); + checkSuccessfulResponse(queryResponse, "Could not create primary index for bucket " + bucket.getName()); + } else { + logger().info("Primary index creation for bucket " + bucket.getName() + " ignored, since QUERY service is not present."); + } + } + } } - public CouchbaseContainer withPrimaryIndex(boolean primaryIndex) { - this.primaryIndex = primaryIndex; - return self(); + /** + * Helper method to extract the internal IP address based on the network configuration. + */ + private String getInternalIpAddress() { + return getContainerInfo().getNetworkSettings().getNetworks().values().stream() + .findFirst() + .map(ContainerNetwork::getIpAddress) + .orElseThrow(() -> new IllegalStateException("No network available to extract the internal IP from!")); } - public CouchbaseContainer withFts(boolean fts) { - this.fts = fts; - return self(); + /** + * Helper method to check if the response is successful and release the body if needed. + * + * @param response the response to check. + * @param message the message that should be part of the exception of not successful. + */ + private void checkSuccessfulResponse(final Response response, final String message) { + try { + if (!response.isSuccessful()) { + throw new IllegalStateException(message + ": " + response.toString()); + } + } finally { + if (response.body() != null) { + response.body().close(); + } + } } - @Getter - @RequiredArgsConstructor - protected enum CouchbasePort { - REST("rest_port", 8091, true), - CAPI("capi_port", 8092, false), - QUERY("query_port", 8093, false), - FTS("fts_http_port", 8094, false), - CBAS("cbas_http_port", 8095, false), - EVENTING("eventing_http_port", 8096, false), - MEMCACHED_SSL("memcached_ssl_port", 11207, false), - MEMCACHED("memcached_port", 11210, false), - REST_SSL("ssl_rest_port", 18091, true), - CAPI_SSL("ssl_capi_port", 18092, false), - QUERY_SSL("ssl_query_port", 18093, false), - FTS_SSL("fts_ssl_port", 18094, false), - CBAS_SSL("cbas_ssl_port", 18095, false), - EVENTING_SSL("eventing_ssl_port", 18096, false); - - final String name; - - final int originalPort; - - final boolean dynamic; + /** + * Checks if already running and if so raises an exception to prevent too-late setters. + */ + private void checkNotRunning() { + if (isRunning()) { + throw new IllegalStateException("Setter can only be called before the container is running"); + } } - @Value - @AllArgsConstructor - private class BucketAndUserSettings { + /** + * Helper method to perform a request against a couchbase server HTTP endpoint. + * + * @param port the (unmapped) original port that should be used. + * @param path the relative http path. + * @param method the http method to use. + * @param body if present, will be part of the payload. + * @param auth if authentication with the admin user and password should be used. + * @return the response of the request. + */ + private Response doHttpRequest(final int port, final String path, final String method, final RequestBody body, + final boolean auth) { + try { + Request.Builder requestBuilder = new Request.Builder() + .url("http://" + getContainerIpAddress() + ":" + getMappedPort(port) + path); - private final BucketSettings bucketSettings; - private final UserSettings userSettings; + if (auth) { + requestBuilder = requestBuilder.header("Authorization", Credentials.basic(username, password)); + } - public BucketAndUserSettings(final BucketSettings bucketSettings) { - this.bucketSettings = bucketSettings; - this.userSettings = UserSettings.build() - .password(bucketSettings.password()) - .roles(getDefaultAdminRoles(bucketSettings.name())); - } + if (body == null) { + requestBuilder = requestBuilder.get(); + } else { + requestBuilder = requestBuilder.method(method, body); + } - private List getDefaultAdminRoles(String bucketName) { - return Lists.newArrayList( - new UserRole("bucket_admin", bucketName), - new UserRole("views_admin", bucketName), - new UserRole("query_manage_index", bucketName), - new UserRole("query_update", bucketName), - new UserRole("query_select", bucketName), - new UserRole("query_insert", bucketName), - new UserRole("query_delete", bucketName) - ); + return HTTP_CLIENT.newCall(requestBuilder.build()).execute(); + } catch (Exception ex) { + throw new RuntimeException("Could not perform request against couchbase HTTP endpoint ", ex); } - } } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseQueryServiceWaitStrategy.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseQueryServiceWaitStrategy.java deleted file mode 100644 index 853dd7d8eb7..00000000000 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseQueryServiceWaitStrategy.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.testcontainers.couchbase; - -import com.couchbase.client.core.message.cluster.GetClusterConfigRequest; -import com.couchbase.client.core.message.cluster.GetClusterConfigResponse; -import com.couchbase.client.core.service.ServiceType; -import com.couchbase.client.java.Bucket; -import lombok.extern.slf4j.Slf4j; -import org.rnorth.ducttape.TimeoutException; -import org.testcontainers.containers.ContainerLaunchException; -import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; - -import static org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess; - -/** - * @author ctayeb - * Created on 06/06/2017 - */ -@Slf4j -public class CouchbaseQueryServiceWaitStrategy extends AbstractWaitStrategy { - - private final Bucket bucket; - - public CouchbaseQueryServiceWaitStrategy(Bucket bucket) { - this.bucket = bucket; - startupTimeout = Duration.ofSeconds(120); - } - - @Override - protected void waitUntilReady() { - log.info("Waiting for {} seconds for QUERY service", startupTimeout.getSeconds()); - - // try to connect to the URL - try { - retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> { - getRateLimiter().doWhenReady(() -> { - GetClusterConfigResponse clusterConfig = bucket.core() - .send(new GetClusterConfigRequest()) - .toBlocking().single(); - boolean queryServiceEnabled = clusterConfig.config() - .bucketConfig(bucket.name()) - .serviceEnabled(ServiceType.QUERY); - if (!queryServiceEnabled) { - throw new ContainerLaunchException("Query service not ready yet"); - } - }); - return true; - }); - } catch (TimeoutException e) { - throw new ContainerLaunchException("Timed out waiting for QUERY service"); - } - } -} diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java new file mode 100644 index 00000000000..d284c660709 --- /dev/null +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Couchbase, Inc. + * + * 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.testcontainers.couchbase; + +/** + * Describes the different services that should be exposed on the container. + */ +public enum CouchbaseService { + + /** + * Key-Value service. + */ + KV, + + /** + * Query (N1QL) service. + */ + QUERY, + + /** + * Search (FTS) service. + */ + SEARCH, + + /** + * Indexing service (needed if QUERY is also used!). + */ + INDEX + +} diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java deleted file mode 100644 index ef2f0925c48..00000000000 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/BaseCouchbaseContainerTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.testcontainers.couchbase; - -import com.couchbase.client.java.document.RawJsonDocument; -import com.couchbase.client.java.query.N1qlQuery; -import com.couchbase.client.java.query.N1qlQueryResult; -import com.couchbase.client.java.query.N1qlQueryRow; -import com.couchbase.client.java.view.DefaultView; -import com.couchbase.client.java.view.DesignDocument; -import com.couchbase.client.java.view.View; -import com.google.common.collect.Lists; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.Description; -import org.testcontainers.containers.FailureDetectingExternalResource; -import org.testcontainers.testsupport.Flaky; -import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; - -import java.util.List; - -public abstract class BaseCouchbaseContainerTest extends AbstractCouchbaseTest { - - private static final String VIEW_NAME = "testview"; - private static final String VIEW_FUNCTION = "function (doc, meta) {\n" + - " emit(meta.id, null);\n" + - "}"; - - - private static final String ID = "toto"; - - private static final String DOCUMENT = "{\"name\":\"toto\"}"; - - @Rule - public RuleChain ruleChain = RuleChain.emptyRuleChain() - .around(new FlakyTestJUnit4RetryRule()) - .around(new FailureDetectingExternalResource() { - @Override - protected void starting(Description description) { - getCouchbaseContainer().start(); - } - - @Override - protected void failed(Throwable e, Description description) { - getCouchbaseContainer().stop(); - } - }); - - @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2020-03-01") - public void shouldInsertDocument() { - RawJsonDocument expected = RawJsonDocument.create(ID, DOCUMENT); - getBucket().upsert(expected); - RawJsonDocument result = getBucket().get(ID, RawJsonDocument.class); - Assert.assertEquals(expected.content(), result.content()); - } - - @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2020-03-01") - public void shouldExecuteN1ql() { - getBucket().query(N1qlQuery.simple("INSERT INTO " + TEST_BUCKET + " (KEY, VALUE) VALUES ('" + ID + "', " + DOCUMENT + ")")); - - N1qlQueryResult query = getBucket().query(N1qlQuery.simple("SELECT * FROM " + TEST_BUCKET + " USE KEYS '" + ID + "'")); - Assert.assertTrue(query.parseSuccess()); - Assert.assertTrue(query.finalSuccess()); - List n1qlQueryRows = query.allRows(); - Assert.assertEquals(1, n1qlQueryRows.size()); - Assert.assertEquals(DOCUMENT, n1qlQueryRows.get(0).value().get(TEST_BUCKET).toString()); - } - - @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1453", reviewDate = "2020-03-01") - public void shouldCreateView() { - View view = DefaultView.create(VIEW_NAME, VIEW_FUNCTION); - DesignDocument document = DesignDocument.create(VIEW_NAME, Lists.newArrayList(view)); - getBucket().bucketManager().insertDesignDocument(document); - DesignDocument result = getBucket().bucketManager().getDesignDocument(VIEW_NAME); - Assert.assertEquals(1, result.views().size()); - View resultView = result.views().get(0); - Assert.assertEquals(VIEW_NAME, resultView.name()); - } -} diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java deleted file mode 100644 index c43d3c981ba..00000000000 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase4_6Test.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.testcontainers.couchbase; - -import org.junit.Rule; - -public class Couchbase4_6Test extends BaseCouchbaseContainerTest { - - @Rule - public CouchbaseContainer container = initCouchbaseContainer("couchbase/server:4.6.5"); - - @Override - public CouchbaseContainer getCouchbaseContainer() { - return container; - } -} diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java deleted file mode 100644 index 2c3dbf3c901..00000000000 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_1Test.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.testcontainers.couchbase; - -import org.junit.Rule; - -public class Couchbase5_1Test extends BaseCouchbaseContainerTest { - - @Rule - public CouchbaseContainer container = initCouchbaseContainer("couchbase/server:5.1.1"); - - @Override - public CouchbaseContainer getCouchbaseContainer() { - return container; - } -} diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java deleted file mode 100644 index 47bc020ef03..00000000000 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/Couchbase5_5Test.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.testcontainers.couchbase; - -import org.junit.Rule; - -public class Couchbase5_5Test extends BaseCouchbaseContainerTest { - - @Rule - public CouchbaseContainer container = initCouchbaseContainer("couchbase/server:5.5.1"); - - @Override - public CouchbaseContainer getCouchbaseContainer() { - return container; - } -} diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java deleted file mode 100644 index 30be62bc2bd..00000000000 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseCommunity5_1Test.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.testcontainers.couchbase; - -import java.util.Collections; - -import org.junit.ClassRule; - -import com.couchbase.client.java.cluster.UserRole; -import com.couchbase.client.java.cluster.UserSettings; -import org.junit.Rule; - -public class CouchbaseCommunity5_1Test extends BaseCouchbaseContainerTest { - - @Rule - public CouchbaseContainer container = initCouchbaseContainer(); - - private static CouchbaseContainer initCouchbaseContainer() { - CouchbaseContainer couchbaseContainer = new CouchbaseContainer("couchbase/server:community-5.1.1"); - - final UserSettings communityAdminUserSettings = - UserSettings.build() - .password(getDefaultBucketSettings().password()) - .roles(Collections.singletonList(new UserRole("admin"))); - - couchbaseContainer.withNewBucket(getDefaultBucketSettings(), communityAdminUserSettings); - return couchbaseContainer; - } - - @Override - public CouchbaseContainer getCouchbaseContainer() { - return container; - } -} diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index 6e9afe96865..27ad0f6265a 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -1,22 +1,78 @@ +/* + * Copyright (c) 2020 Couchbase, Inc. + * + * 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.testcontainers.couchbase; -import org.junit.Assert; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.document.JsonDocument; +import com.couchbase.client.java.document.json.JsonObject; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import org.junit.Test; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class CouchbaseContainerTest { @Test - public void shouldUseCorrectDockerImage() { - CouchbaseContainer couchbaseContainer = new CouchbaseContainer().withClusterAdmin("admin", "foobar"); + public void testBasicContainerUsage() { + // bucket_definition { + BucketDefinition bucketDefinition = new BucketDefinition("mybucket"); + // } - Assert.assertEquals(CouchbaseContainer.DOCKER_IMAGE_NAME + CouchbaseContainer.VERSION, - couchbaseContainer.getDockerImageName()); - } + try ( + // container_definition { + CouchbaseContainer container = new CouchbaseContainer() + .withBucket(bucketDefinition) + // } + ) { + container.start(); - @Test - public void shouldStopWithoutThrowingException() { - CouchbaseContainer couchbaseContainer = new CouchbaseContainer(); - couchbaseContainer.start(); - couchbaseContainer.stop(); + // cluster_creation { + CouchbaseEnvironment environment = DefaultCouchbaseEnvironment + .builder() + .bootstrapCarrierDirectPort(container.getBootstrapCarrierDirectPort()) + .bootstrapHttpDirectPort(container.getBootstrapHttpDirectPort()) + .build(); + + Cluster cluster = CouchbaseCluster.create( + environment, + container.getContainerIpAddress() + ); + // } + + try { + // auth { + cluster.authenticate(container.getUsername(), container.getPassword()); + // } + + Bucket bucket = cluster.openBucket(bucketDefinition.getName()); + + bucket.upsert(JsonDocument.create("foo", JsonObject.empty())); + + assertTrue(bucket.exists("foo")); + assertNotNull(cluster.clusterManager().getBucket(bucketDefinition.getName())); + } finally { + cluster.disconnect(); + environment.shutdown(); + } + } } + } From 34b8d7e03de1fafb50a4c3b37388ae4d40059736 Mon Sep 17 00:00:00 2001 From: Stefan Rempfer Date: Sun, 12 Apr 2020 20:32:41 +0200 Subject: [PATCH 0593/4969] Using LogMessageWaitStrategy for VncRecordingContainer (#2063) (#2547) Co-authored-by: Stefan Rempfer Co-authored-by: Richard North Co-authored-by: Sergei Egorov --- .../containers/VncRecordingContainer.java | 47 +++---------------- 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index 298593a116b..fd48dd01f92 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -1,24 +1,21 @@ package org.testcontainers.containers; -import com.github.dockerjava.api.model.Frame; import lombok.Getter; import lombok.NonNull; import lombok.SneakyThrows; import lombok.ToString; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.rnorth.ducttape.TimeoutException; -import org.rnorth.ducttape.unreliables.Unreliables; -import org.testcontainers.containers.output.FrameConsumerResultCallback; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.TestcontainersConfiguration; -import java.io.Closeable; import java.io.File; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.StandardCopyOption; +import java.time.Duration; import java.util.Base64; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; + +import static java.time.temporal.ChronoUnit.SECONDS; /** * 'Sidekick container' with the sole purpose of recording the VNC screen output from another container. @@ -59,39 +56,9 @@ public VncRecordingContainer(@NonNull Network network, @NonNull String targetNet this.targetNetworkAlias = targetNetworkAlias; withNetwork(network); - - waitingFor(new AbstractWaitStrategy() { - - @Override - protected void waitUntilReady() { - try { - Unreliables.retryUntilTrue((int) startupTimeout.toMillis(), TimeUnit.MILLISECONDS, () -> { - CountDownLatch latch = new CountDownLatch(1); - - FrameConsumerResultCallback callback = new FrameConsumerResultCallback() { - @Override - public void onNext(Frame frame) { - if (frame != null && new String(frame.getPayload()).contains("Connected")) { - latch.countDown(); - } - } - }; - - try ( - Closeable __ = dockerClient.logContainerCmd(getContainerId()) - .withFollowStream(true) - .withSince(0) - .withStdErr(true) - .exec(callback) - ) { - return latch.await(1, TimeUnit.SECONDS); - } - }); - } catch (TimeoutException e) { - throw new ContainerLaunchException("Timed out waiting for log output", e); - } - } - }); + waitingFor(new LogMessageWaitStrategy() + .withRegEx(".*Connected.*") + .withStartupTimeout(Duration.of(15, SECONDS))); } public VncRecordingContainer withVncPassword(@NonNull String vncPassword) { From 95c828d01eaa8532a4878a89587d0116e413ebd4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Apr 2020 20:41:30 +0200 Subject: [PATCH 0594/4969] Include image name in RemoteDockerImage#toString (#2558) * clean up imports in GenericContainer * include image name in RemoteDockerImage.toString() to fix #2443 * test RemoteDockerImage directly * handle failures getting the image name * use completeExceptionally instead of mocking * tweak assertions * more assertion tweaks * add isDone check to RemoteDockerImage.toString -- still figuring out why test fails * go back to using lombok @ToString, exclude dockerClient while we're at it * use `Futures.lazyTransform` that also proxies `isDone` * `imageNameToString` should not be public * Include the message on error Co-authored-by: Byron David Co-authored-by: David Byron --- .../images/RemoteDockerImage.java | 30 ++++++++---- .../containers/GenericContainerTest.java | 1 - .../images/RemoteDockerImageTest.java | 47 +++++++++++++++++++ 3 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index 4975f536384..d0e1313edf6 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.exception.InternalServerErrorException; +import com.google.common.util.concurrent.Futures; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NonNull; @@ -28,11 +29,13 @@ public class RemoteDockerImage extends LazyFuture { private static final Duration PULL_RETRY_TIME_LIMIT = Duration.ofMinutes(2); + @ToString.Exclude private Future imageNameFuture; @Wither private ImagePullPolicy imagePullPolicy = PullPolicy.defaultPolicy(); + @ToString.Exclude private DockerClient dockerClient = DockerClientFactory.lazyClient(); public RemoteDockerImage(String dockerImageName) { @@ -44,19 +47,13 @@ public RemoteDockerImage(@NonNull String repository, @NonNull String tag) { } public RemoteDockerImage(@NonNull Future imageFuture) { - this.imageNameFuture = new LazyFuture() { - @Override - @SneakyThrows({InterruptedException.class, ExecutionException.class}) - protected DockerImageName resolve() { - return new DockerImageName(imageFuture.get()); - } - }; + this.imageNameFuture = Futures.lazyTransform(imageFuture, DockerImageName::new); } @Override @SneakyThrows({InterruptedException.class, ExecutionException.class}) protected final String resolve() { - final DockerImageName imageName = imageNameFuture.get(); + final DockerImageName imageName = getImageName(); Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); try { if (!imagePullPolicy.shouldPull(imageName)) { @@ -95,4 +92,21 @@ protected final String resolve() { throw new ContainerFetchException("Failed to get Docker client for " + imageName, e); } } + + private DockerImageName getImageName() throws InterruptedException, ExecutionException { + return imageNameFuture.get(); + } + + @ToString.Include(name = "imageName", rank = 1) + private String imageNameToString() { + if (!imageNameFuture.isDone()) { + return ""; + } + + try { + return getImageName().toString(); + } catch (InterruptedException | ExecutionException e) { + return e.getMessage(); + } + } } diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index c29f6f37c36..78a7a3b1bef 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -2,7 +2,6 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse.ContainerState; -import com.github.dockerjava.api.model.HostConfig; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; diff --git a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java new file mode 100644 index 00000000000..c62f15653b3 --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java @@ -0,0 +1,47 @@ +package org.testcontainers.images; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.testcontainers.utility.Base58; + +import java.util.concurrent.CompletableFuture; + +public class RemoteDockerImageTest { + + @Test + public void toStringContainsOnlyImageName() { + String imageName = Base58.randomString(8).toLowerCase(); + RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageName); + assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); + } + + @Test + public void toStringWithExceptionContainsOnlyImageNameFuture() { + CompletableFuture imageNameFuture = new CompletableFuture<>(); + imageNameFuture.completeExceptionally(new RuntimeException("arbitrary")); + + RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture); + assertThat(remoteDockerImage.toString(), containsString("imageName=java.lang.RuntimeException: arbitrary")); + } + + @Test(timeout=5000L) + public void toStringDoesntResolveImageNameFuture() { + CompletableFuture imageNameFuture = new CompletableFuture<>(); + + // verify that we've set up the test properly + assertFalse(imageNameFuture.isDone()); + + RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture); + assertThat(remoteDockerImage.toString(), containsString("imageName=")); + + // Make sure the act of calling toString doesn't resolve the imageNameFuture + assertFalse(imageNameFuture.isDone()); + + String imageName = Base58.randomString(8).toLowerCase(); + imageNameFuture.complete(imageName); + assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); + } +} From 6adb23b5ab860280fc6d3ffbc3186709d4c848cc Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 13 Apr 2020 16:54:30 +0200 Subject: [PATCH 0595/4969] Fix Spock's `TestLifecycleAware` integration (#2563) * Fix Spock's `TestLifecycleAware` integration * Small cleanups Co-authored-by: Kevin Wittek --- .../TestcontainersMethodInterceptor.groovy | 31 ++++--- .../spock/BrowserVncRecordingIT.groovy | 88 ------------------- .../TestLifecycleAwareContainerMock.java | 42 +++++++++ .../spock/TestLifecycleAwareIT.groovy | 55 ++++++++++++ 4 files changed, 112 insertions(+), 104 deletions(-) delete mode 100644 modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy create mode 100644 modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java create mode 100644 modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy index a70ec0d6e53..16be002aeb1 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy @@ -30,6 +30,7 @@ class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { invocation.proceed() } + @Override void interceptCleanupSpecMethod(IMethodInvocation invocation) throws Throwable { def containers = findAllContainers(true) stopContainers(containers, invocation) @@ -54,13 +55,6 @@ class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { @Override void interceptCleanupMethod(IMethodInvocation invocation) throws Throwable { - findAllTestLifecycleAwareContainers(invocation).each { - // we assume first error is the one we want - def maybeException = Optional.ofNullable(errorListener.errors[0]?.exception) - def testDescription = SpockTestDescription.fromTestDescription(invocation) - it.afterTest(testDescription, maybeException) - } - def containers = findAllContainers(false) stopContainers(containers, invocation) @@ -76,14 +70,6 @@ class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { } } - private List findAllTestLifecycleAwareContainers(IMethodInvocation invocation) { - spec.allFields.findAll { FieldInfo f -> - TestLifecycleAware.isAssignableFrom(f.type) - }.collect { - it.readValue(invocation.instance) as TestLifecycleAware - } - } - private List findAllComposeContainers(boolean shared) { spec.allFields.findAll { FieldInfo f -> DockerComposeContainer.isAssignableFrom(f.type) && f.shared == shared @@ -96,12 +82,25 @@ class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { if(!container.isRunning()){ container.start() } + + if (container instanceof TestLifecycleAware) { + def testDescription = SpockTestDescription.fromTestDescription(invocation) + (container as TestLifecycleAware).beforeTest(testDescription) + } } } - private static void stopContainers(List containers, IMethodInvocation invocation) { + private void stopContainers(List containers, IMethodInvocation invocation) { containers.each { FieldInfo f -> GenericContainer container = readContainerFromField(f, invocation) + + if (container instanceof TestLifecycleAware) { + // we assume first error is the one we want + def maybeException = Optional.ofNullable(errorListener.errors[0]?.exception) + def testDescription = SpockTestDescription.fromTestDescription(invocation) + (container as TestLifecycleAware).afterTest(testDescription, maybeException) + } + container.stop() } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy deleted file mode 100644 index 794032a58c4..00000000000 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/BrowserVncRecordingIT.groovy +++ /dev/null @@ -1,88 +0,0 @@ -package org.testcontainers.spock - -import org.intellij.lang.annotations.Language -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification -import spock.lang.Unroll -import spock.util.EmbeddedSpecRunner - -import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL -import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_FAILING - -class BrowserVncRecordingIT extends Specification { - - @Rule - TemporaryFolder temp - - String recordingDir - - def setup() { - recordingDir = temp.getRoot().getAbsolutePath() - } - - @Unroll("For recording mode #recordingMode and failing test is #fails records video file named '#videoFileName'") - def "retains all recordings for RECORD_ALL if successful"() { - given: - - //noinspection GrPackage - @Language("groovy") - String myTest = """ -package org.testcontainers.spock - -import org.openqa.selenium.chrome.ChromeOptions -import org.openqa.selenium.remote.RemoteWebDriver -import org.testcontainers.containers.BrowserWebDriverContainer -import spock.lang.Specification - -import java.util.concurrent.TimeUnit - -import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode - -@Testcontainers -class BrowserWebdriverContainerIT extends Specification { - - BrowserWebDriverContainer browserContainer = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()) - .withRecordingMode("$recordingMode" as VncRecordingMode, new File("$recordingDir")) - - RemoteWebDriver driver - - def setup() { - driver = browserContainer.getWebDriver() - driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS) - } - - def "should record"() { - when: - driver.get("http://en.wikipedia.org/wiki/Randomness") - - then: - driver.findElementByPartialLinkText("pattern").isDisplayed() == !$fails - } - -} - - -""" - - when: - EmbeddedSpecRunner runner = new EmbeddedSpecRunner(throwFailure: false) - runner.run(myTest) - - then: - def videoDir = temp.getRoot().list() - if (videoFileName.isEmpty()) { - videoDir.length == 0 - } else { - videoDir.find { it.contains(videoFileName) } - } - - where: - recordingMode | fails | videoFileName - RECORD_ALL | false | 'BrowserWebdriverContainerIT-should+record' - RECORD_FAILING | false | '' - RECORD_FAILING | true | 'BrowserWebdriverContainerIT-should+record' - } - -} diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java new file mode 100644 index 00000000000..43be6d32ca4 --- /dev/null +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java @@ -0,0 +1,42 @@ +package org.testcontainers.spock; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.lifecycle.TestDescription; +import org.testcontainers.lifecycle.TestLifecycleAware; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class TestLifecycleAwareContainerMock extends GenericContainer implements TestLifecycleAware { + + static final String BEFORE_TEST = "beforeTest"; + static final String AFTER_TEST = "afterTest"; + + final List lifecycleMethodCalls = new ArrayList<>(); + final List lifecycleFilesystemFriendlyNames = new ArrayList<>(); + + Throwable capturedThrowable; + + @Override + public void beforeTest(TestDescription description) { + lifecycleMethodCalls.add(BEFORE_TEST); + lifecycleFilesystemFriendlyNames.add(description.getFilesystemFriendlyName()); + } + + @Override + public void afterTest(TestDescription description, Optional throwable) { + lifecycleMethodCalls.add(AFTER_TEST); + throwable.ifPresent(capturedThrowable -> this.capturedThrowable = capturedThrowable); + } + + @Override + public void start() { + // Do nothing + } + + @Override + public void stop() { + // Do nothing + } +} diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy new file mode 100644 index 00000000000..18f7517ea3f --- /dev/null +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy @@ -0,0 +1,55 @@ +package org.testcontainers.spock + +import org.intellij.lang.annotations.Language +import spock.lang.Specification +import spock.lang.Unroll +import spock.util.EmbeddedSpecRunner + +class TestLifecycleAwareIT extends Specification { + + @Unroll("When failing test is #fails, afterTest receives '#filesystemFriendlyNames' and throwable starting with message '#errorMessageStartsWith'") + def "lifecycle awareness"() { + given: + + @Language("groovy") + String myTest = """ +import org.testcontainers.spock.Testcontainers +import org.testcontainers.containers.GenericContainer +import spock.lang.Specification + +@Testcontainers +class TestLifecycleAwareIT extends Specification { + + GenericContainer container = System.properties["org.testcontainers.container"] as GenericContainer + + def "perform test"() { + expect: + !System.properties["org.testcontainers.shouldFail"] + } +} +""" + and: + def container = new TestLifecycleAwareContainerMock() + System.properties["org.testcontainers.container"] = container + System.properties["org.testcontainers.shouldFail"] = fails + + when: "executing the test" + def runner = new EmbeddedSpecRunner(throwFailure: false) + runner.run(myTest) + + then: "mock container received lifecycle calls as expected" + container.lifecycleMethodCalls == ["beforeTest", "afterTest"] + container.lifecycleFilesystemFriendlyNames.join(",") == filesystemFriendlyNames + if (errorMessageStartsWith) { + assert container.capturedThrowable.message.startsWith(errorMessageStartsWith) + } else { + assert container.capturedThrowable == null + } + + where: + fails | filesystemFriendlyNames | errorMessageStartsWith + false | 'TestLifecycleAwareIT-perform+test' | null + true | 'TestLifecycleAwareIT-perform+test' | "Condition not satisfied:" + } + +} From d33f6475a9792b62c772d8f38a8c7a78ff1edf69 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 13 Apr 2020 17:39:01 +0200 Subject: [PATCH 0596/4969] Make default file recording directory of BrowserWebDriverContainer platform independent (#2562) Co-authored-by: Sergei Egorov --- .../containers/BrowserWebDriverContainer.java | 13 +++++++++++- ...ChromeRecordingWebDriverContainerTest.java | 20 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 9e1a2733a2e..22a4b9d47a5 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -28,8 +28,10 @@ import org.testcontainers.lifecycle.TestLifecycleAware; import java.io.File; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Files; import java.time.Duration; import java.util.Optional; import java.util.Set; @@ -52,6 +54,7 @@ public class BrowserWebDriverContainer Date: Mon, 13 Apr 2020 20:51:04 +0100 Subject: [PATCH 0597/4969] Bump tomcat-jdbc from 9.0.33 to 9.0.34 in /modules/mysql (#2542) Bumps tomcat-jdbc from 9.0.33 to 9.0.34. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 10fd90b3c38..606aeefe813 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.19' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.34' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' From fbda419042d5de2b223b33a018269c714eefa78e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:51:20 +0100 Subject: [PATCH 0598/4969] =?UTF-8?q?Bump=20junit-jupiter-engine=20from=20?= =?UTF-8?q?5.6.0=20to=205.6.2=20in=20/modules/junit=E2=80=A6=20(#2553)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.6.0 to 5.6.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.6.0...r5.6.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index bf52b25913c..f7cbb476260 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.12' testRuntime 'mysql:mysql-connector-java:8.0.19' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.0' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' } test { From f18775801e71f32f1c962dab0e2435ca4727f9fc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:51:31 +0100 Subject: [PATCH 0599/4969] =?UTF-8?q?Bump=20aws-java-sdk-logs=20from=201.1?= =?UTF-8?q?1.759=20to=201.11.762=20in=20/modules/lo=E2=80=A6=20(#2541)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.759 to 1.11.762. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.759...1.11.762) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 1e9e3cd9121..c8bf561b6d1 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,5 +6,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.759' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.762' } From f822865e5738535f9ce6ed502dac679337a141ca Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:51:38 +0100 Subject: [PATCH 0600/4969] =?UTF-8?q?Bump=20r2dbc-postgresql=20from=200.8.?= =?UTF-8?q?1.RELEASE=20to=200.8.2.RELEASE=20in=20/m=E2=80=A6=20(#2561)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.1.RELEASE to 0.8.2.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-postgresql/blob/v0.8.2.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.1.RELEASE...v0.8.2.RELEASE) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index c629c1c5a13..9893ec28bd1 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -6,7 +6,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.2.RELEASE' testCompile 'org.postgresql:postgresql:42.2.12' testCompile 'commons-dbutils:commons-dbutils:1.7' From a988cf8400408273d617c9c3bf259ff18b5746d4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:51:49 +0100 Subject: [PATCH 0601/4969] Bump tomcat-jdbc from 9.0.33 to 9.0.34 in /modules/mariadb (#2543) Bumps tomcat-jdbc from 9.0.33 to 9.0.34. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 93b2de2a716..730dae7c794 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.34' testCompile 'org.vibur:vibur-dbcp:25.0' testCompile testFixtures(project(':r2dbc')) From 3bf78155ce7006dce40123df2d610016e34d0c2a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:51:54 +0100 Subject: [PATCH 0602/4969] Bump cucumber-java from 5.5.0 to 5.6.0 in /examples (#2527) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 5.5.0 to 5.6.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v5.5.0...v5.6.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 52c59229350..6827bb7c683 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' testImplementation 'io.cucumber:cucumber-junit:5.5.0' - testImplementation 'io.cucumber:cucumber-java:5.5.0' + testImplementation 'io.cucumber:cucumber-java:5.6.0' testImplementation 'org.testcontainers:selenium' } From ba21115757507d6347548065afa52226f8eb9c0e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:52:25 +0100 Subject: [PATCH 0603/4969] =?UTF-8?q?Bump=20junit-jupiter-api=20from=205.6?= =?UTF-8?q?.0=20to=205.6.2=20in=20/modules/junit-ju=E2=80=A6=20(#2554)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.6.0 to 5.6.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.6.0...r5.6.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index f7cbb476260..950302715b5 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.6.0' + compile 'org.junit.jupiter:junit-jupiter-api:5.6.2' testCompile project(':mysql') testCompile project(':postgresql') From 83da2e25a9348a1ed7b321ac82d931bafdf90b8a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:52:42 +0100 Subject: [PATCH 0604/4969] =?UTF-8?q?Bump=20r2dbc-mssql=20from=200.8.1.REL?= =?UTF-8?q?EASE=20to=200.8.2.RELEASE=20in=20/module=E2=80=A6=20(#2559)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [r2dbc-mssql](https://github.com/r2dbc/r2dbc-mssql) from 0.8.1.RELEASE to 0.8.2.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-mssql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-mssql/blob/v0.8.2.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-mssql/compare/v0.8.1.RELEASE...v0.8.2.RELEASE) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 3c44df64eda..4a496e9eb35 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' + compileOnly 'io.r2dbc:r2dbc-mssql:0.8.2.RELEASE' testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' From 558988c1cf86976795cd28eacc9c6417bba6ea99 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:52:54 +0100 Subject: [PATCH 0605/4969] Bump java-client from 2.7.13 to 2.7.14 in /modules/couchbase (#2540) Bumps [java-client](https://github.com/couchbase/couchbase-java-client) from 2.7.13 to 2.7.14. - [Release notes](https://github.com/couchbase/couchbase-java-client/releases) - [Commits](https://github.com/couchbase/couchbase-java-client/compare/2.7.13...2.7.14) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 095f8828aac..9dd0856fd51 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - testCompile 'com.couchbase.client:java-client:2.7.13' + testCompile 'com.couchbase.client:java-client:2.7.14' } From 3645252cf7de3021abdf7bc1c7e86d22fad69551 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:53:13 +0100 Subject: [PATCH 0606/4969] =?UTF-8?q?Bump=20org.springframework.boot=20fro?= =?UTF-8?q?m=202.2.5.RELEASE=20to=202.2.6.RELEA=E2=80=A6=20(#2530)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.2.5.RELEASE to 2.2.6.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.5.RELEASE...v2.2.6.RELEASE) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/selenium-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index c9bed8d1467..edbe7d1fb68 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.5.RELEASE' + id 'org.springframework.boot' version '2.2.6.RELEASE' } apply plugin: 'io.spring.dependency-management' From 780359762c05c7b4153337686a3a6805bef3c864 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2020 20:53:45 +0100 Subject: [PATCH 0607/4969] Bump cucumber-junit from 5.5.0 to 5.6.0 in /examples (#2529) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 5.5.0 to 5.6.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v5.5.0...v5.6.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 6827bb7c683..53a50c374f5 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - testImplementation 'io.cucumber:cucumber-junit:5.5.0' + testImplementation 'io.cucumber:cucumber-junit:5.6.0' testImplementation 'io.cucumber:cucumber-java:5.6.0' testImplementation 'org.testcontainers:selenium' } From b5da9140f3c910e38c474b8614d23ea9308afb32 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 14 Apr 2020 11:00:53 +0100 Subject: [PATCH 0608/4969] Upgrade Gradle to 6.3 (#2551) For compatibility with recent JDKs --- build.gradle | 6 ----- gradle/wrapper/gradle-wrapper.properties | 5 ++-- gradlew | 29 ++++++++++-------------- settings.gradle | 8 +++++++ 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/build.gradle b/build.gradle index 4fbaf42c160..d9d374cb511 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,4 @@ plugins { - id 'com.gradle.build-scan' version '2.4.2' id 'io.franzbecker.gradle-lombok' version '3.1.0' id 'nebula.provided-base' version '3.0.3' id 'com.github.johnrengelman.shadow' version '5.1.0' @@ -133,8 +132,3 @@ subprojects { testCompile 'ch.qos.logback:logback-classic:1.2.3' } } - -buildScan { - termsOfServiceUrl = 'https://gradle.com/terms-of-service' - termsOfServiceAgree = 'yes' -} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ca9d62814a2..6fd47cc3de5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Sun Apr 05 19:28:23 BST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 83f2acfdc31..2fe81a7d95e 100755 --- a/gradlew +++ b/gradlew @@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +175,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/settings.gradle b/settings.gradle index e5432e08061..5ec35718ef6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,6 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.9.0" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.2.1" } configurations.classpath { @@ -16,6 +17,7 @@ buildscript { } apply plugin: 'ch.myniva.s3-build-cache' +apply plugin: 'com.gradle.enterprise' ext.isMasterBuild = (System.getenv("CIRCLE_BRANCH") ?: System.getenv("BUILD_SOURCEBRANCHNAME")) == "master" @@ -55,3 +57,9 @@ include ':docs:examples:spock:redis' include 'test-support' +gradleEnterprise { + buildScan { + termsOfServiceUrl = 'https://gradle.com/terms-of-service' + termsOfServiceAgree = 'yes' + } +} From 34c7aef429d0debf9c5b7268c210536089c71a53 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 14 Apr 2020 11:01:46 +0100 Subject: [PATCH 0609/4969] =?UTF-8?q?Bump=20junit-jupiter-params=20from=20?= =?UTF-8?q?5.6.0=20to=205.6.2=20in=20/modules/junit=E2=80=A6=20(#2571)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.6.0 to 5.6.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.6.0...r5.6.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 950302715b5..c1b713cdd86 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } - testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.0' + testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' testCompile 'org.assertj:assertj-core:3.14.0' testRuntime 'org.postgresql:postgresql:42.2.12' From c9a0b1f0b1d7f389bacdf8b89407968f45a73b65 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 14 Apr 2020 11:02:27 +0100 Subject: [PATCH 0610/4969] =?UTF-8?q?Bump=20assertj-core=20from=203.14.0?= =?UTF-8?q?=20to=203.15.0=20in=20/modules/junit-jupit=E2=80=A6=20(#2570)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.15.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index c1b713cdd86..86d9b30930e 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,8 +12,8 @@ dependencies { testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } + testCompile 'org.assertj:assertj-core:3.15.0' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' - testCompile 'org.assertj:assertj-core:3.14.0' testRuntime 'org.postgresql:postgresql:42.2.12' testRuntime 'mysql:mysql-connector-java:8.0.19' From 207d62df010109b93f632408c7b6b0f7fb5057fa Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 15 Apr 2020 15:03:55 +0200 Subject: [PATCH 0611/4969] Explicitly set ciMate's projectId in CircleCI (#2572) --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index c4302911f40..67e6546e220 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,8 @@ jobs: - run: &ciMate name: aggregate test reports with ciMate when: always + environment: + CIMATE_PROJECT_ID: 2348n4vl command: | wget -q https://get.cimate.io/release/linux/cimate chmod +x cimate From c3d37e4195470b7bace41d1556df7a50a6c56ea8 Mon Sep 17 00:00:00 2001 From: Stefan Rempfer Date: Thu, 16 Apr 2020 15:04:21 +0200 Subject: [PATCH 0612/4969] Regard specified VNC recording directory for BrowserWebDriverContainer again (#2574) Co-authored-by: Stefan Rempfer --- .../containers/BrowserWebDriverContainer.java | 15 ++++---- ...ChromeRecordingWebDriverContainerTest.java | 36 +++++++++++++++---- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 22a4b9d47a5..49218dfb990 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -143,12 +143,15 @@ protected void configure() { } if (recordingMode != VncRecordingMode.SKIP) { - try { - vncRecordingDirectory = Files.createTempDirectory(TC_TEMP_DIR_PREFIX).toFile(); - } catch (IOException e) { - // should never happen as per javadoc, since we use valid prefix - logger().error("Exception while trying to create temp directory " + vncRecordingDirectory.getAbsolutePath(), e); - throw new ContainerLaunchException("Exception while trying to create temp directory", e); + + if (vncRecordingDirectory == null) { + try { + vncRecordingDirectory = Files.createTempDirectory(TC_TEMP_DIR_PREFIX).toFile(); + } catch (IOException e) { + // should never happen as per javadoc, since we use valid prefix + logger().error("Exception while trying to create temp directory " + vncRecordingDirectory.getAbsolutePath(), e); + throw new ContainerLaunchException("Exception while trying to create temp directory", e); + } } if (getNetwork() == null) { diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java index 7e77f63a051..3872e3d8dd2 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java @@ -1,17 +1,19 @@ package org.testcontainers.junit; + +import com.google.common.io.PatternFilenameFilter; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.runners.Enclosed; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.openqa.selenium.chrome.ChromeOptions; import org.testcontainers.containers.BrowserWebDriverContainer; import org.testcontainers.containers.DefaultRecordingFileFactory; import org.testcontainers.lifecycle.TestDescription; -import java.io.File; import java.util.Optional; - +import static org.junit.Assert.assertTrue; import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; @RunWith(Enclosed.class) @@ -20,14 +22,34 @@ public class ChromeRecordingWebDriverContainerTest extends BaseWebDriverContaine public static class ChromeThatRecordsAllTests { @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, new File("./build/")) - .withRecordingFileFactory(new DefaultRecordingFileFactory()); + public TemporaryFolder vncRecordingDirectory = new TemporaryFolder(); @Test public void recordingTestThatShouldBeRecordedAndRetained() { - doSimpleExplore(chrome); + try ( + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() + .withCapabilities(new ChromeOptions()) + .withRecordingMode(RECORD_ALL, vncRecordingDirectory.getRoot()) + .withRecordingFileFactory(new DefaultRecordingFileFactory()) + ) { + chrome.start(); + + doSimpleExplore(chrome); + chrome.afterTest(new TestDescription() { + @Override + public String getTestId() { + return getFilesystemFriendlyName(); + } + + @Override + public String getFilesystemFriendlyName() { + return "ChromeThatRecordsAllTests-recordingTestThatShouldBeRecordedAndRetained"; + } + }, Optional.empty()); + + String[] files = vncRecordingDirectory.getRoot().list(new PatternFilenameFilter("PASSED-.*\\.flv")); + assertTrue("Recorded file not found", files.length == 1); + } } } From a6e6079bbd61383e68bcf464ba49eccb1262e844 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 16 Apr 2020 22:02:15 +0200 Subject: [PATCH 0613/4969] Add `type/enhancement` to the Release Drafter (#2580) --- .github/release-drafter.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index ed8939a3117..af82504717a 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -5,8 +5,10 @@ template: | $CHANGES categories: - - title: 🚀 Features - label: type/feature + - title: 🚀 Features & Enhancements + labels: + - type/feature + - type/enhancement - title: 🐛 Bug Fixes label: type/bug - title: 📖 Documentation From 4b5bfaef9345f9e4e9f4607e5c7fd185124e7915 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 17 Apr 2020 14:25:16 +0200 Subject: [PATCH 0614/4969] Update Gradle Shadow Plugin to 5.2.0 (#2582) Gradle Shadow Plugin supports Gradle Caching from 5.2.0 and should help avoiding this heavyweight task when not necessarily. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d9d374cb511..78958851963 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'io.franzbecker.gradle-lombok' version '3.1.0' id 'nebula.provided-base' version '3.0.3' - id 'com.github.johnrengelman.shadow' version '5.1.0' + id 'com.github.johnrengelman.shadow' version '5.2.0' id "com.jfrog.bintray" version "1.8.4" apply false } From b7cda9d81479c66f957435bccde72a4e66ae648e Mon Sep 17 00:00:00 2001 From: Lokesh Pant <7022317+KraTos5589@users.noreply.github.com> Date: Fri, 17 Apr 2020 18:17:36 +0530 Subject: [PATCH 0615/4969] Update CreateContainerCmd link to the latest release (#2583) * CreateContainerCmd Link was outdated. Replaced working link * Replaced with version 3.0.0 link * Updated to 3.2.1 --- docs/features/advanced_options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/advanced_options.md b/docs/features/advanced_options.md index a774dbddc06..8689ce46021 100644 --- a/docs/features/advanced_options.md +++ b/docs/features/advanced_options.md @@ -51,4 +51,4 @@ For example, this can be used to change the container hostname: It is recommended to use this sparingly, and follow changes to the `docker-java` API if you choose to use this. It is typically quite stable, though. -For what is possible, consult the [`docker-java CreateContainerCmd` source code](https://github.com/docker-java/docker-java/blob/master/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java). +For what is possible, consult the [`docker-java CreateContainerCmd` source code](https://github.com/docker-java/docker-java/blob/3.2.1/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java). From e354a7f51c62c40e26aa761be93eafcc2cd82bfe Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 18 Apr 2020 10:13:09 +0100 Subject: [PATCH 0616/4969] Reduce CircleCI build to a minimal subset of core (#2586) --- .circleci/config.yml | 89 ++------------------------------------------ 1 file changed, 3 insertions(+), 86 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 67e6546e220..8f700dba2b5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,15 +1,13 @@ version: 2 jobs: - core: + minimal_core: machine: enabled: true steps: - checkout - run: - command: ./gradlew testcontainers:build -x test -x check + command: ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' - run: - command: ./gradlew testcontainers:check --scan - - run: &ciMate name: aggregate test reports with ciMate when: always environment: @@ -28,89 +26,8 @@ jobs: path: ~/junit - store_artifacts: path: ~/junit - modules-no-jdbc-test-no-selenium: - machine: - enabled: true - steps: - - checkout - - run: - command: ./gradlew check -x testcontainers:check -x selenium:check -x jdbc-test:check - --scan - environment: - TZ: /usr/share/zoneinfo/ETC/UTC - - run: *ciMate - - run: - name: Save test results - command: | - mkdir -p ~/junit/ - find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/junit/ \; - when: always - - store_test_results: - path: ~/junit - - store_artifacts: - path: ~/junit - modules-jdbc-test: - machine: - enabled: true - steps: - - checkout - - run: - command: ./gradlew jdbc-test:check --scan - environment: - TZ: /usr/share/zoneinfo/ETC/UTC - - run: *ciMate - - run: - name: Save test results - command: | - mkdir -p ~/junit/ - find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/junit/ \; - when: always - - store_test_results: - path: ~/junit - - store_artifacts: - path: ~/junit - selenium: - machine: - enabled: true - steps: - - checkout - - run: - command: ./gradlew selenium:check --scan - - run: *ciMate - - run: - name: Save test results - command: | - mkdir -p ~/junit/ - find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/junit/ \; - when: always - - store_test_results: - path: ~/junit - - store_artifacts: - path: ~/junit - examples: - machine: - enabled: true - steps: - - checkout - - run: - command: cd examples && ./gradlew check - - run: *ciMate - - run: - name: Save test results - command: | - mkdir -p ~/junit/ - find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/junit/ \; - when: always - - store_test_results: - path: ~/junit - - store_artifacts: - path: ~/junit workflows: version: 2 test_all: jobs: - - core - - modules-no-jdbc-test-no-selenium - - modules-jdbc-test - - selenium - - examples + - minimal_core From 1ef6fac59c11c2898466c53f6ed63d5095b67f5a Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 18 Apr 2020 10:31:15 +0100 Subject: [PATCH 0617/4969] Generate GitHub Actions CI Jobs automatically (#2520) Co-Authored-By: Sergei Egorov Co-Authored-By: Richard North --- .github/workflows/ci-dind.yml | 28 ++++++++ .github/workflows/ci.yml | 68 +++++++++++++++++--- .github/workflows/scripts/check_ci_status.sh | 2 +- build.gradle | 6 +- gradle/ci-support.gradle | 37 +++++++++++ 5 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/ci-dind.yml create mode 100644 gradle/ci-support.gradle diff --git a/.github/workflows/ci-dind.yml b/.github/workflows/ci-dind.yml new file mode 100644 index 00000000000..15bd5ec76ee --- /dev/null +++ b/.github/workflows/ci-dind.yml @@ -0,0 +1,28 @@ +name: in-container + +on: + pull_request: {} + push: { branches: [ master ] } + +jobs: + in-docker_test: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: Build with Gradle + run: | + docker run -i --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v "$HOME:$HOME" \ + -v "$PWD:$PWD" \ + -w "$PWD" \ + openjdk:8-jdk-alpine \ + ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' + - name: aggregate test reports with ciMate + if: always() + env: + CIMATE_PROJECT_ID: 2348n4vl + run: | + wget -q https://get.cimate.io/release/linux/cimate + chmod +x cimate + ./cimate "**/TEST-*.xml" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a0a97d05f7..5f7dfb2c3dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,20 +5,68 @@ on: push: { branches: [ master ] } jobs: - in-docker_test: + find_gradle_jobs: runs-on: ubuntu-18.04 + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - name: Build with Gradle + - id: set-matrix run: | - docker run -i --rm \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v "$HOME:$HOME" \ - -v "$PWD:$PWD" \ - -w "$PWD" \ - openjdk:8-jdk-alpine \ - ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' - - name: aggregate test reports with ciMate + TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) + echo $TASKS + echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" + check: + needs: find_gradle_jobs + strategy: + matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '1.8' + - name: Cache Gradle Home files + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check- + ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check- + ${{ runner.os }}-gradle-home- + - name: Clear existing docker image cache + run: docker image prune -af + - name: Build and test with Gradle (${{matrix.gradle_args}}) + run: | + ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} + - name: Aggregate test reports with ciMate + if: always() + env: + CIMATE_PROJECT_ID: 2348n4vl + run: | + wget -q https://get.cimate.io/release/linux/cimate + chmod +x cimate + ./cimate "**/TEST-*.xml" + examples: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '1.8' + - name: Cache Gradle Home files + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-home-examples-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle-home-examples- + - name: Build and test Examples with Gradle + working-directory: ./examples/ + run: | + ./gradlew --no-daemon --scan --info check + - name: Aggregate test reports with ciMate if: always() env: CIMATE_PROJECT_ID: 2348n4vl diff --git a/.github/workflows/scripts/check_ci_status.sh b/.github/workflows/scripts/check_ci_status.sh index bc5c0b138a2..29ef1d939a8 100755 --- a/.github/workflows/scripts/check_ci_status.sh +++ b/.github/workflows/scripts/check_ci_status.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash set -o errexit set -o nounset set -o pipefail diff --git a/build.gradle b/build.gradle index 78958851963..382ecdf161e 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,8 @@ plugins { id "com.jfrog.bintray" version "1.8.4" apply false } +apply from: "$rootDir/gradle/ci-support.gradle" + subprojects { apply plugin: 'nebula.provided-base' apply plugin: 'java' @@ -45,10 +47,12 @@ subprojects { apply from: "$rootDir/gradle/publishing.gradle" apply from: "$rootDir/gradle/bintray.gradle" + jar.archiveClassifier.set("original") + publishing { publications { mavenJava(MavenPublication) { publication -> - artifacts.removeAll { it.classifier == null } + artifacts.removeAll { it.classifier == jar.archiveClassifier.get() } artifact project.tasks.shadowJar } } diff --git a/gradle/ci-support.gradle b/gradle/ci-support.gradle new file mode 100644 index 00000000000..7c3408068b3 --- /dev/null +++ b/gradle/ci-support.gradle @@ -0,0 +1,37 @@ +import groovy.json.JsonOutput + +// Emit a JSON-formatted list of check tasks to be run in CI +task testMatrix { + project.afterEvaluate { + def checkTasks = subprojects.collect { + it.tasks.findByName("check") + }.findAll { it != null } + + dependsOn(checkTasks) + doLast { + // Obtain a list of check tasks that are not up-to-date, i.e. + // the ones which Gradle cannot find a cached output for. + def checkTaskPaths = checkTasks + .findAll { !it.state.upToDate } + .collect { it.path } + + println(JsonOutput.toJson(checkTaskPaths)) + } + } +} + +// If we're executing the `taskMatrix` task, disable tests and other slow tasks +// so that we can get a result quickly. +gradle.taskGraph.whenReady { + if (it.hasTask(tasks.testMatrix)) { + for (subproject in subprojects) { + subproject.tasks.withType(Test).all { + testExecuter([execute: { spec, processor -> }, stopNow:{}] as org.gradle.api.internal.tasks.testing.TestExecuter) + } + subproject.tasks.findByName("shadowJar").enabled = false + subproject.tasks.findByName("javadoc").enabled = false + subproject.tasks.findByName("delombok").enabled = false + subproject.tasks.findByName("japicmp")?.enabled = false + } + } +} From e7230c282e76ac54ea1d0d941e71876ba6e45d49 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 18 Apr 2020 14:22:57 +0100 Subject: [PATCH 0618/4969] Exclude multi-module `module-info.class` from shaded JAR (#2588) --- core/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/core/build.gradle b/core/build.gradle index 84a20425cc5..b116a1f85f2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -44,6 +44,7 @@ shadowJar { 'META-INF/DEPENDENCIES', 'META-INF/maven/', 'META-INF/proguard/', + 'META-INF/versions/*/module-info.class', 'META-INF/services/README.md', 'META-INF/services/com.fasterxml.jackson.core.*', 'META-INF/services/com.github.dockerjava.api.command.*', From 374c559d9bca054f06fdd69cd0f95b024af425bc Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 18 Apr 2020 16:07:28 +0100 Subject: [PATCH 0619/4969] Add gradle caching to find_gradle_jobs build (#2589) --- .github/workflows/ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f7dfb2c3dc..84b3d9a5197 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,17 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '1.8' + - name: Cache Gradle Home files + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle-home-testmatrix- + ${{ runner.os }}-gradle-home- - id: set-matrix run: | TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) From f6728616872ec7011ef3b3c75fab9c4bc1982fe5 Mon Sep 17 00:00:00 2001 From: Sudharaka Palamakumbura Date: Sat, 18 Apr 2020 08:17:35 -0700 Subject: [PATCH 0620/4969] Update Copyright for 2020 in Documentation (#2566) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index af2bf79f0c9..8b3ffda05d2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -131,6 +131,6 @@ This project was initially inspired by a [gist](https://gist.github.com/mosheesh ## Copyright -Copyright (c) 2015-2019 Richard North and other authors. +Copyright (c) 2015-2020 Richard North and other authors. See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/AUTHORS) for contributors. From d2fe97bc47c65cd87a28cd11576bee944c07a848 Mon Sep 17 00:00:00 2001 From: Sudharaka Palamakumbura Date: Sat, 18 Apr 2020 08:18:24 -0700 Subject: [PATCH 0621/4969] Update latest _version tag in Documentation Code Samples (#2568) --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index c2d39bc9d2c..e3cae4c5da8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,4 +88,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.13.0 + latest_version: 1.14.0 From 3530e63d1d33801b4851acbe606d1282ebbd4298 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 19 Apr 2020 11:11:35 +0200 Subject: [PATCH 0622/4969] delegate `getMetadata()` to `R2DBCDatabaseContainerProvider` (#2577) Apparently, R2DBC ConnectionFactories perform early validation of options, and it fails because the original options (when specified as `r2dbc://mysql:///db`) miss some required options like host/port/username/password. After talking to Mark from R2DBC, it seems that the checks will stay, so we need to workaround it somehow. I ended up with the delegation to `R2DBCDatabaseContainerProvider`, because these provides should know which options they add and which are required. --- .../containers/MariaDBContainer.java | 8 ++++++-- ...MariaDBR2DBCDatabaseContainerProvider.java | 16 ++++++++++++++++ .../MSSQLR2DBCDatabaseContainerProvider.java | 16 ++++++++++++++++ .../containers/MSSQLServerContainer.java | 10 +++++++--- .../containers/MySQLContainer.java | 8 ++++++-- .../MySQLR2DBCDatabaseContainerProvider.java | 16 ++++++++++++++++ .../containers/PostgreSQLContainer.java | 5 +++++ ...tgreSQLR2DBCDatabaseContainerProvider.java | 16 ++++++++++++++++ .../r2dbc/R2DBCDatabaseContainerProvider.java | 19 +++++++++++++++++++ .../TestcontainersR2DBCConnectionFactory.java | 3 +-- .../AbstractR2DBCDatabaseContainerTest.java | 8 ++++++++ 11 files changed, 116 insertions(+), 9 deletions(-) diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index e402bc24e0e..fc876713dda 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -11,10 +11,14 @@ public class MariaDBContainer> extends JdbcD public static final String IMAGE = "mariadb"; public static final String DEFAULT_TAG = "10.3.6"; + static final String DEFAULT_USER = "test"; + + static final String DEFAULT_PASSWORD = "test"; + static final Integer MARIADB_PORT = 3306; private String databaseName = "test"; - private String username = "test"; - private String password = "test"; + private String username = DEFAULT_USER; + private String password = DEFAULT_PASSWORD; private static final String MARIADB_ROOT_USER = "root"; private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF"; diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java index 79cb627f8a9..36a201f85bb 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerProvider.java @@ -1,11 +1,14 @@ package org.testcontainers.containers; import com.google.auto.service.AutoService; +import io.r2dbc.spi.ConnectionFactoryMetadata; import io.r2dbc.spi.ConnectionFactoryOptions; import org.mariadb.r2dbc.MariadbConnectionFactoryProvider; import org.testcontainers.r2dbc.R2DBCDatabaseContainer; import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; +import javax.annotation.Nullable; + @AutoService(R2DBCDatabaseContainerProvider.class) public class MariaDBR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { @@ -27,4 +30,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) } return new MariaDBR2DBCDatabaseContainer(container); } + + @Nullable + @Override + public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) { + ConnectionFactoryOptions.Builder builder = options.mutate(); + if (!options.hasOption(ConnectionFactoryOptions.USER)) { + builder.option(ConnectionFactoryOptions.USER, MariaDBContainer.DEFAULT_USER); + } + if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) { + builder.option(ConnectionFactoryOptions.PASSWORD, MariaDBContainer.DEFAULT_PASSWORD); + } + return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build()); + } } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java index 1638901226c..d72ab8e8419 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java @@ -2,10 +2,13 @@ import com.google.auto.service.AutoService; import io.r2dbc.mssql.MssqlConnectionFactoryProvider; +import io.r2dbc.spi.ConnectionFactoryMetadata; import io.r2dbc.spi.ConnectionFactoryOptions; import org.testcontainers.r2dbc.R2DBCDatabaseContainer; import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; +import javax.annotation.Nullable; + @AutoService(R2DBCDatabaseContainerProvider.class) public class MSSQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { @@ -26,4 +29,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) } return new MSSQLR2DBCDatabaseContainer(container); } + + @Nullable + @Override + public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) { + ConnectionFactoryOptions.Builder builder = options.mutate(); + if (!options.hasOption(ConnectionFactoryOptions.USER)) { + builder.option(ConnectionFactoryOptions.USER, MSSQLServerContainer.DEFAULT_USER); + } + if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) { + builder.option(ConnectionFactoryOptions.PASSWORD, MSSQLServerContainer.DEFAULT_PASSWORD); + } + return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build()); + } } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index afe3f5b8651..2219a5aaf61 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -15,8 +15,12 @@ public class MSSQLServerContainer> exten public static final String DEFAULT_TAG = "2017-CU12"; public static final Integer MS_SQL_SERVER_PORT = 1433; - private String username = "SA"; - private String password = "A_Str0ng_Required_Password"; + + static final String DEFAULT_USER = "SA"; + + static final String DEFAULT_PASSWORD = "A_Str0ng_Required_Password"; + + private String password = DEFAULT_PASSWORD; private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240; private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 240; @@ -63,7 +67,7 @@ public String getJdbcUrl() { @Override public String getUsername() { - return username; + return DEFAULT_USER; } @Override diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index a8549672ff3..54f3ab08524 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -14,11 +14,15 @@ public class MySQLContainer> extends JdbcDatab public static final String IMAGE = "mysql"; public static final String DEFAULT_TAG = "5.7.22"; + static final String DEFAULT_USER = "test"; + + static final String DEFAULT_PASSWORD = "test"; + private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF"; public static final Integer MYSQL_PORT = 3306; private String databaseName = "test"; - private String username = "test"; - private String password = "test"; + private String username = DEFAULT_USER; + private String password = DEFAULT_PASSWORD; private static final String MYSQL_ROOT_USER = "root"; public MySQLContainer() { diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java index 3a01616caba..ec3b6a4e41f 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerProvider.java @@ -2,10 +2,13 @@ import com.google.auto.service.AutoService; import dev.miku.r2dbc.mysql.MySqlConnectionFactoryProvider; +import io.r2dbc.spi.ConnectionFactoryMetadata; import io.r2dbc.spi.ConnectionFactoryOptions; import org.testcontainers.r2dbc.R2DBCDatabaseContainer; import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; +import javax.annotation.Nullable; + @AutoService(R2DBCDatabaseContainerProvider.class) public class MySQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { @@ -27,4 +30,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) } return new MySQLR2DBCDatabaseContainer(container); } + + @Nullable + @Override + public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) { + ConnectionFactoryOptions.Builder builder = options.mutate(); + if (!options.hasOption(ConnectionFactoryOptions.USER)) { + builder.option(ConnectionFactoryOptions.USER, MySQLContainer.DEFAULT_USER); + } + if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) { + builder.option(ConnectionFactoryOptions.PASSWORD, MySQLContainer.DEFAULT_PASSWORD); + } + return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build()); + } } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 0fae3a16f4a..06cdd7ebc8d 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -19,6 +19,11 @@ public class PostgreSQLContainer> extends public static final String DEFAULT_TAG = "9.6.12"; public static final Integer POSTGRESQL_PORT = 5432; + + static final String DEFAULT_USER = "test"; + + static final String DEFAULT_PASSWORD = "test"; + private String databaseName = "test"; private String username = "test"; private String password = "test"; diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java index 5e9da980b8e..971b4cd3758 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerProvider.java @@ -2,10 +2,13 @@ import com.google.auto.service.AutoService; import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider; +import io.r2dbc.spi.ConnectionFactoryMetadata; import io.r2dbc.spi.ConnectionFactoryOptions; import org.testcontainers.r2dbc.R2DBCDatabaseContainer; import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider; +import javax.annotation.Nullable; + @AutoService(R2DBCDatabaseContainerProvider.class) public final class PostgreSQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider { @@ -27,4 +30,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) } return new PostgreSQLR2DBCDatabaseContainer(container); } + + @Nullable + @Override + public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) { + ConnectionFactoryOptions.Builder builder = options.mutate(); + if (!options.hasOption(ConnectionFactoryOptions.USER)) { + builder.option(ConnectionFactoryOptions.USER, PostgreSQLContainer.DEFAULT_USER); + } + if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) { + builder.option(ConnectionFactoryOptions.PASSWORD, PostgreSQLContainer.DEFAULT_PASSWORD); + } + return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build()); + } } diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java index 2eabc0d521b..287407dc15e 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java @@ -1,8 +1,13 @@ package org.testcontainers.r2dbc; +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryMetadata; import io.r2dbc.spi.ConnectionFactoryOptions; import io.r2dbc.spi.Option; +import javax.annotation.Nullable; + public interface R2DBCDatabaseContainerProvider { Option REUSABLE_OPTION = Option.valueOf("TC_REUSABLE"); @@ -12,4 +17,18 @@ public interface R2DBCDatabaseContainerProvider { boolean supports(ConnectionFactoryOptions options); R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options); + + @Nullable + default ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) { + ConnectionFactoryOptions.Builder builder = options.mutate(); + if (!options.hasOption(ConnectionFactoryOptions.HOST)) { + builder.option(ConnectionFactoryOptions.HOST, "localhost"); + } + if (!options.hasOption(ConnectionFactoryOptions.PORT)) { + builder.option(ConnectionFactoryOptions.PORT, 65535); + } + + ConnectionFactory connectionFactory = ConnectionFactories.find(builder.build()); + return connectionFactory != null ? connectionFactory.getMetadata() : null; + } } diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java index 1a0fc57ad8c..691775a94f8 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java @@ -68,8 +68,7 @@ public Publisher create() { @Override public ConnectionFactoryMetadata getMetadata() { - // TODO check whether it is fine to call it without setting the host/port and other values - return ConnectionFactories.find(options).getMetadata(); + return containerProvider.getMetadata(options); } @Override diff --git a/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java b/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java index 7f14ecca2a7..c21c7078410 100644 --- a/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java +++ b/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java @@ -4,6 +4,7 @@ import io.r2dbc.spi.Connection; import io.r2dbc.spi.ConnectionFactories; import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryMetadata; import io.r2dbc.spi.ConnectionFactoryOptions; import org.junit.Test; import org.testcontainers.containers.GenericContainer; @@ -38,6 +39,13 @@ public final void testUrlSupport() { runTestQuery(connectionFactory); } + @Test + public final void testGetMetadata() { + ConnectionFactory connectionFactory = ConnectionFactories.get(createR2DBCUrl()); + ConnectionFactoryMetadata metadata = connectionFactory.getMetadata(); + assertThat(metadata).isNotNull(); + } + protected abstract T createContainer(); protected void runTestQuery(ConnectionFactory connectionFactory) { From add6eb431525c3fd51c8709441c502f1657529ad Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:12:12 +0200 Subject: [PATCH 0623/4969] Bump testcontainers from 1.12.5 to 1.14.0 in /core (#2569) Bumps [testcontainers](https://github.com/testcontainers/testcontainers-java) from 1.12.5 to 1.14.0. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.12.5...1.14.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b116a1f85f2..09a6c590242 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -110,7 +110,7 @@ if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { } dependencies { - baseline 'org.testcontainers:testcontainers:1.12.5', { + baseline 'org.testcontainers:testcontainers:1.14.0', { exclude group: "*", module: "*" } From 84f422b5c6e23c39698b32ff3cbc3a5d64f70177 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 19 Apr 2020 16:19:40 +0200 Subject: [PATCH 0624/4969] GHA: disable fail-fast matrix strategy (#2591) See https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategyfail-fast --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84b3d9a5197..3dbcc4c41fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,7 @@ jobs: check: needs: find_gradle_jobs strategy: + fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} runs-on: ubuntu-18.04 steps: From b6cd9c80eddca65c9e2718b66c91b6b76f181371 Mon Sep 17 00:00:00 2001 From: Chason Choate Date: Sun, 19 Apr 2020 09:20:17 -0500 Subject: [PATCH 0625/4969] Make ImageData class public for custom image pull policies (#2585) * Making imagedata public so it can be used to create custom image pull policies. Adding test to ensure it works as expected. * Ensuring we don't do unnecessary pulls and using the default generic container image for the out of package pull policy test. Co-authored-by: Chason Choate Co-authored-by: Richard North --- .../org/testcontainers/images/ImageData.java | 2 +- .../test/java/alt/testcontainers/README.md | 1 + .../OutOfPackageImagePullPolicyTest.java | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/alt/testcontainers/README.md create mode 100644 core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java diff --git a/core/src/main/java/org/testcontainers/images/ImageData.java b/core/src/main/java/org/testcontainers/images/ImageData.java index bef0c56c245..54b07d5acf2 100644 --- a/core/src/main/java/org/testcontainers/images/ImageData.java +++ b/core/src/main/java/org/testcontainers/images/ImageData.java @@ -10,7 +10,7 @@ @Value @Builder -class ImageData { +public class ImageData { @NonNull Instant createdAt; diff --git a/core/src/test/java/alt/testcontainers/README.md b/core/src/test/java/alt/testcontainers/README.md new file mode 100644 index 00000000000..0a08ff91ba5 --- /dev/null +++ b/core/src/test/java/alt/testcontainers/README.md @@ -0,0 +1 @@ +Useful place for running tests that need to be outside of the `org.testcontainers` package. diff --git a/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java b/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java new file mode 100644 index 00000000000..2da41a8344e --- /dev/null +++ b/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java @@ -0,0 +1,27 @@ +package alt.testcontainers.images; + +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.images.AbstractImagePullPolicy; +import org.testcontainers.images.ImageData; +import org.testcontainers.utility.DockerImageName; + +public class OutOfPackageImagePullPolicyTest { + @Test + public void shouldSupportCustomPoliciesOutOfTestContainersPackage() { + try ( + GenericContainer container = new GenericContainer<>() + .withImagePullPolicy(new AbstractImagePullPolicy() { + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + return false; + } + }) + ) { + container.withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + container.start(); + } + } + +} From c9692006f1e774eda0981e9820f7331cab662196 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 19 Apr 2020 15:22:17 +0100 Subject: [PATCH 0626/4969] Reduce AZP build to a minimal subset of core, except when running on Windows (#2587) --- azure-pipelines.yml | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c56ae9fde36..5780a01bb83 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,24 +1,29 @@ jobs: -- job: core + +- job: azure_pipeline_tests steps: + + # Run a minimal set of tests in normal Linux pipeline builds - task: Gradle@2 - displayName: Build & test + condition: eq(variables['Agent.OS'], 'Linux') + displayName: Build & test (Linux - minimal core) env: AWS_ACCESS_KEY_ID: $(aws.accessKeyId) AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' - options: '--no-daemon --continue' - tasks: 'testcontainers:check' + options: "--no-daemon --continue" + tasks: "testcontainers:test --tests GenericContainerRuleTest" publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" condition: and(succeededOrFailed(),eq(variables['Agent.OS'], 'Linux')) -- job: jdbc - steps: + + # Run all tests when running the Windows CI tests - task: Gradle@2 - displayName: Build & test + condition: eq(variables['Agent.OS'], 'Windows_NT') + displayName: Build & test (Windows - all modules) env: AWS_ACCESS_KEY_ID: $(aws.accessKeyId) AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) @@ -26,24 +31,6 @@ jobs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' options: '--no-daemon --continue' - tasks: 'jdbc-test:check' - publishJUnitResults: true - testResultsFiles: '**/TEST-*.xml' - - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: and(succeededOrFailed(), eq(variables['Agent.OS'], 'Linux')) -- job: modules - steps: - - task: Gradle@2 - displayName: Build & test - env: - AWS_ACCESS_KEY_ID: $(aws.accessKeyId) - AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) - inputs: - gradleWrapperFile: 'gradlew' - jdkVersionOption: '1.11' - options: '--continue -x testcontainers:check -x jdbc-test:check -PpostCheckCommand="docker image prune -af"' tasks: 'check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: and(succeededOrFailed(), eq(variables['Agent.OS'], 'Linux')) From f631023576288234e7aacdce867520200b2dcfda Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 19 Apr 2020 19:57:42 +0100 Subject: [PATCH 0627/4969] Support ImageFromDockerfile authenticated image pulls (#2573) Co-Authored-By: David Byron --- .../images/builder/ImageFromDockerfile.java | 49 ++++++--- .../utility/AuthenticatedImagePullTest.java | 103 ++++++++++++++---- 2 files changed, 112 insertions(+), 40 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 1140247960a..11a7e2f4cb6 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -83,16 +83,6 @@ protected final String resolve() { DockerClient dockerClient = DockerClientFactory.instance().client(); - dependencyImageNames.forEach(imageName -> { - try { - log.info("Pre-emptively checking local images for '{}', referenced via a Dockerfile. If not available, it will be pulled.", imageName); - DockerClientFactory.instance().checkAndPullImage(dockerClient, imageName); - } catch (Exception e) { - log.warn("Unable to pre-fetch an image ({}) depended upon by Dockerfile - image build will continue but may fail. Exception message was: {}", imageName, e.getMessage()); - } - }); - - try { if (deleteOnExit) { ResourceReaper.instance().registerImageForCleanup(dockerImageName); @@ -118,6 +108,8 @@ public void onNext(BuildResponseItem item) { BuildImageCmd buildImageCmd = dockerClient.buildImageCmd(in); configure(buildImageCmd); + prePullDependencyImages(dependencyImageNames); + BuildImageResultCallback exec = buildImageCmd.exec(resultCallback); long bytesToDockerDaemon = 0; @@ -154,11 +146,30 @@ protected void configure(BuildImageCmd buildImageCmd) { this.dockerfile.ifPresent(p -> { buildImageCmd.withDockerfile(p.toFile()); dependencyImageNames = new ParsedDockerfile(p).getDependencyImageNames(); + + if (dependencyImageNames.size() > 0) { + // if we'll be pre-pulling images, disable the built-in pull as it is not necessary and will fail for + // authenticated registries + buildImageCmd.withPull(false); + } }); this.buildArgs.forEach(buildImageCmd::withBuildArg); } + private void prePullDependencyImages(Set imagesToPull) { + final DockerClient dockerClient = DockerClientFactory.instance().client(); + + imagesToPull.forEach(imageName -> { + try { + log.info("Pre-emptively checking local images for '{}', referenced via a Dockerfile. If not available, it will be pulled.", imageName); + DockerClientFactory.instance().checkAndPullImage(dockerClient, imageName); + } catch (Exception e) { + log.warn("Unable to pre-fetch an image ({}) depended upon by Dockerfile - image build will continue but may fail. Exception message was: {}", imageName, e.getMessage()); + } + }); + } + public ImageFromDockerfile withBuildArg(final String key, final String value) { this.buildArgs.put(key, value); return this; @@ -171,19 +182,23 @@ public ImageFromDockerfile withBuildArgs(final Map args) { /** * Sets the Dockerfile to be used for this image. - * @deprecated It is recommended to use {@link #withDockerfile} instead because it honors - * .dockerignore files and therefore will be more efficient - * @param relativePathFromBuildRoot + * + * @param relativePathFromBuildContextDirectory relative path to the Dockerfile, relative to the image build context directory + * @deprecated It is recommended to use {@link #withDockerfile} instead because it honors .dockerignore files and + * will therefore be more efficient. Additionally, using {@link #withDockerfile} supports Dockerfiles that depend + * upon images from authenticated private registries. */ @Deprecated - public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildRoot) { - this.dockerFilePath = Optional.of(relativePathFromBuildRoot); + public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildContextDirectory) { + this.dockerFilePath = Optional.of(relativePathFromBuildContextDirectory); return this; } /** - * Sets the Dockerfile to be used for this image. - * @param dockerfile + * Sets the Dockerfile to be used for this image. Honors .dockerignore files for efficiency. + * Additionally, supports Dockerfiles that depend upon images from authenticated private registries. + * + * @param dockerfile path to Dockerfile on the test host. */ public ImageFromDockerfile withDockerfile(Path dockerfile) { this.dockerfile = Optional.of(dockerfile); diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 78b54798cd1..56945643a88 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -1,19 +1,27 @@ package org.testcontainers.utility; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.model.AuthConfig; -import com.github.dockerjava.core.command.PullImageResultCallback; -import com.github.dockerjava.core.command.PushImageResultCallback; +import org.intellij.lang.annotations.Language; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.mockito.Mockito; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.ContainerState; +import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.images.builder.ImageFromDockerfile; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.concurrent.TimeUnit; import static org.mockito.ArgumentMatchers.any; @@ -25,14 +33,17 @@ * This test checks the integration between Testcontainers and an authenticated registry, but uses * a mock instance of {@link RegistryAuthLocator} - the purpose of the test is solely to ensure that * the auth locator is utilised, and that the credentials it provides flow through to the registry. - * + *

* {@link RegistryAuthLocatorTest} covers actual credential scenarios at a lower level, which are * impractical to test end-to-end. */ public class AuthenticatedImagePullTest { + /** + * Containerised docker image registry, with simple hardcoded credentials + */ @ClassRule - public static GenericContainer authenticatedRegistry = new GenericContainer(new ImageFromDockerfile() + public static GenericContainer authenticatedRegistry = new GenericContainer<>(new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder.from("registry:2") .run("htpasswd -Bbn testuser notasecret > /htpasswd") @@ -46,28 +57,17 @@ public class AuthenticatedImagePullTest { private static RegistryAuthLocator originalAuthLocatorSingleton; private static DockerClient client; - private static String testRegistryAddress; private static String testImageName; private static String testImageNameWithTag; @BeforeClass - public static void setUp() { + public static void setUp() throws InterruptedException { originalAuthLocatorSingleton = RegistryAuthLocator.instance(); client = DockerClientFactory.instance().client(); - testRegistryAddress = authenticatedRegistry.getContainerIpAddress() + ":" + authenticatedRegistry.getFirstMappedPort(); + String testRegistryAddress = authenticatedRegistry.getContainerIpAddress() + ":" + authenticatedRegistry.getFirstMappedPort(); testImageName = testRegistryAddress + "/alpine"; testImageNameWithTag = testImageName + ":latest"; - } - - @AfterClass - public static void tearDown() { - RegistryAuthLocator.setInstance(originalAuthLocatorSingleton); - client.removeImageCmd(testImageNameWithTag).withForce(true).exec(); - } - - @Test - public void testThatAuthLocatorIsUsed() throws Exception { final DockerImageName expectedName = new DockerImageName(testImageNameWithTag); final AuthConfig authConfig = new AuthConfig() @@ -83,9 +83,23 @@ public void testThatAuthLocatorIsUsed() throws Exception { // a push will use the auth locator for authentication, although that isn't the goal of this test putImageInRegistry(); + } + + @Before + public void removeImageFromLocalDocker() { + // remove the image tag from local docker so that it must be pulled before use + client.removeImageCmd(testImageNameWithTag).withForce(true).exec(); + } + @AfterClass + public static void tearDown() { + RegistryAuthLocator.setInstance(originalAuthLocatorSingleton); + } + + @Test + public void testThatAuthLocatorIsUsedForContainerCreation() { // actually start a container, which will require an authenticated pull - try (final GenericContainer container = new GenericContainer<>(testImageNameWithTag) + try (final GenericContainer container = new GenericContainer<>(testImageNameWithTag) .withCommand("/bin/sh", "-c", "sleep 10")) { container.start(); @@ -93,7 +107,53 @@ public void testThatAuthLocatorIsUsed() throws Exception { } } - private void putImageInRegistry() throws InterruptedException { + @Test + public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { + // Prepare a simple temporary Dockerfile which requires our custom private image + Path tempContext = Files.createTempDirectory(Paths.get("."), this.getClass().getSimpleName() + "-test-"); + Path tempFile = Files.createTempFile(tempContext, "test", ".Dockerfile"); + String dockerFileContent = "FROM " + testImageNameWithTag; + Files.write(tempFile, dockerFileContent.getBytes()); + + // Start a container built from a derived image, which will require an authenticated pull + try (final GenericContainer container = new GenericContainer<>( + new ImageFromDockerfile() + .withDockerfile(tempFile) + ) + .withCommand("/bin/sh", "-c", "sleep 10")) { + container.start(); + + assertTrue("container started following an authenticated pull", container.isRunning()); + } + } + + @Test + public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { + // Prepare a simple temporary Docker Compose manifest which requires our custom private image + Path tempContext = Files.createTempDirectory(Paths.get("."), this.getClass().getSimpleName() + "-test-"); + Path tempFile = Files.createTempFile(tempContext, "test", ".docker-compose.yml"); + @Language("yaml") String composeFileContent = + "version: '2.0'\n" + + "services:\n" + + " privateservice:\n" + + " command: /bin/sh -c 'sleep 60'\n" + + " image: " + testImageNameWithTag; + Files.write(tempFile, composeFileContent.getBytes()); + + // Start the docker compose project, which will require an authenticated pull + try (final DockerComposeContainer compose = new DockerComposeContainer<>(tempFile.toFile())) { + compose.start(); + + assertTrue("container started following an authenticated pull", + compose + .getContainerByServiceName("privateservice_1") + .map(ContainerState::isRunning) + .orElse(false) + ); + } + } + + private static void putImageInRegistry() throws InterruptedException { // It doesn't matter which image we use for this test, but use one that's likely to have been pulled already final String dummySourceImage = TestcontainersConfiguration.getInstance().getRyukImage(); @@ -109,10 +169,7 @@ private void putImageInRegistry() throws InterruptedException { client.tagImageCmd(id, testImageName, "latest").exec(); client.pushImageCmd(testImageNameWithTag) - .exec(new PushImageResultCallback()) + .exec(new ResultCallback.Adapter<>()) .awaitCompletion(1, TimeUnit.MINUTES); - - // remove the image tag from local docker so that it must be pulled before use - client.removeImageCmd(testImageNameWithTag).withForce(true).exec(); } } From d604f3ec45c9c61574b1728b801b70dba35eaa18 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 20 Apr 2020 10:18:14 +0200 Subject: [PATCH 0628/4969] Fix regression introduced in #2473 (missing `this` constructor call) (#2596) --- .../java/org/testcontainers/containers/MariaDBContainer.java | 2 +- .../main/java/org/testcontainers/containers/MySQLContainer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index fc876713dda..fb21dd9a1a9 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -23,7 +23,7 @@ public class MariaDBContainer> extends JdbcD private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF"; public MariaDBContainer() { - super(IMAGE + ":" + DEFAULT_TAG); + this(IMAGE + ":" + DEFAULT_TAG); } public MariaDBContainer(String dockerImageName) { diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 54f3ab08524..b8bbe225617 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -26,7 +26,7 @@ public class MySQLContainer> extends JdbcDatab private static final String MYSQL_ROOT_USER = "root"; public MySQLContainer() { - super(IMAGE + ":" + DEFAULT_TAG); + this(IMAGE + ":" + DEFAULT_TAG); } public MySQLContainer(String dockerImageName) { From 9c4756f73dde77b3df1e4b77aeccaa3de818e935 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 21 Apr 2020 10:52:14 +0200 Subject: [PATCH 0629/4969] Push Gradle Cache from GHA (#2597) * Push Gradle Cache from GHA * Update ci.yml --- .github/workflows/ci.yml | 4 ++++ settings.gradle | 14 +++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dbcc4c41fd..d488542d8a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,10 @@ jobs: ${{ runner.os }}-gradle-home-testmatrix- ${{ runner.os }}-gradle-home- - id: set-matrix + env: + # Since we override the tests executor, + # we should not push empty results to the cache + READ_ONLY_REMOTE_GRADLE_CACHE: true run: | TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) echo $TASKS diff --git a/settings.gradle b/settings.gradle index 5ec35718ef6..4321c4ac4a4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,21 +5,17 @@ buildscript { } } dependencies { - classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.9.0" + classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.2.1" } - - configurations.classpath { - resolutionStrategy { - force 'com.amazonaws:aws-java-sdk-s3:1.11.582' - } - } } apply plugin: 'ch.myniva.s3-build-cache' apply plugin: 'com.gradle.enterprise' -ext.isMasterBuild = (System.getenv("CIRCLE_BRANCH") ?: System.getenv("BUILD_SOURCEBRANCHNAME")) == "master" +ext.isMasterBuild = false || + (System.getenv("GITHUB_REF") == "refs/heads/master") || + (System.getenv("BUILD_SOURCEBRANCHNAME") == "master") buildCache { local { @@ -31,7 +27,7 @@ buildCache { region = 'fra1' bucket = 'testcontainers' path = 'cache' - push = isMasterBuild + push = !(System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") || !isMasterBuild) headers = [ 'x-amz-acl': 'public-read' ] From 3f3f4b25381713ccd76459ab329d3c28b740dd5e Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 22 Apr 2020 17:17:54 +0200 Subject: [PATCH 0630/4969] Set custom ciMate key (#2601) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d488542d8a2..df6fc96ea44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,7 @@ jobs: if: always() env: CIMATE_PROJECT_ID: 2348n4vl + CIMATE_CI_KEY: "CI / ${{ runner.os }} / ${{matrix.gradle_args}}" run: | wget -q https://get.cimate.io/release/linux/cimate chmod +x cimate @@ -86,6 +87,7 @@ jobs: if: always() env: CIMATE_PROJECT_ID: 2348n4vl + CIMATE_CI_KEY: examples run: | wget -q https://get.cimate.io/release/linux/cimate chmod +x cimate From 4d17308fda95947eaac1449551e47b619df0396b Mon Sep 17 00:00:00 2001 From: Fernando Mouco Date: Thu, 23 Apr 2020 13:02:27 +0100 Subject: [PATCH 0631/4969] CircleCI docs: fix invalid executor key (#2607) executorType is no longer a valid executor definition. The simplest form to designate using machine executor is `machine: true` --- .../continuous_integration/circle_ci.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/continuous_integration/circle_ci.md b/docs/supported_docker_environment/continuous_integration/circle_ci.md index 1ec2a32b4cd..64e7ea131f2 100644 --- a/docs/supported_docker_environment/continuous_integration/circle_ci.md +++ b/docs/supported_docker_environment/continuous_integration/circle_ci.md @@ -9,7 +9,7 @@ Here is a sample CircleCI configuration that does a checkout of a project and ru # Check https://circleci.com/docs/2.0/language-java/ for more details # version: 2 -executorType: machine +machine: true jobs: build: steps: From 2c20417ac07b11e3255d7ce13dd5d83f3908df10 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2020 13:03:06 +0100 Subject: [PATCH 0632/4969] Bump mongo-java-driver from 3.12.1 to 3.12.3 in /core (#2594) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.1 to 3.12.3. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.1...r3.12.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 09a6c590242..d99ca8c3676 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -157,7 +157,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.2.0' testCompile 'com.rabbitmq:amqp-client:5.8.0' - testCompile 'org.mongodb:mongo-java-driver:3.12.1' + testCompile 'org.mongodb:mongo-java-driver:3.12.3' testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } From 12de2b407238835bdc06169a6ac4b7bdcc98e028 Mon Sep 17 00:00:00 2001 From: Vladimir Orany Date: Thu, 23 Apr 2020 14:43:45 +0200 Subject: [PATCH 0633/4969] Allow using LocalStackContainer with AWS SDK v2 #1442 (#2579) Closes #1442 --- docs/modules/localstack.md | 14 +++ modules/localstack/build.gradle | 1 + .../localstack/LocalStackContainer.java | 118 ++++++++++++++++-- .../localstack/LocalstackContainerTest.java | 41 ++++-- 4 files changed, 152 insertions(+), 22 deletions(-) diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index bf520b1fac6..4ff46233b05 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -13,6 +13,7 @@ public LocalStackContainer localstack = new LocalStackContainer() @Test public void someTestMethod() { + // AWS SDK v1 AmazonS3 s3 = AmazonS3ClientBuilder .standard() .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) @@ -21,6 +22,19 @@ public void someTestMethod() { s3.createBucket("foo"); s3.putObject("foo", "bar", "baz"); + + // AWS SDK v2 + S3Client s3 = S3Client + .builder() + .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3)) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create( + localstack.getAccessKey(), localstack.getSecretKey() + ))) + .region(Region.of(localstack.getRegion())) + .build(); + + s3.createBucket(b -> b.bucket("foo")); + s3.putObject(b -> b.bucket("foo").key("bar"), RequestBody.fromBytes("baz".getBytes())); ``` Environment variables listed in [Localstack's README](https://github.com/localstack/localstack#configurations) may be used to customize Localstack's configuration. diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c8bf561b6d1..cd6f3d9f86c 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,4 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.762' + testCompile 'software.amazon.awssdk:s3:2.11.10' } diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 0d8c3627f6c..c649d322ead 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -13,6 +13,8 @@ import org.testcontainers.utility.TestcontainersConfiguration; import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -90,7 +92,16 @@ public LocalStackContainer withServices(Service... services) { .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); - * + * or for AWS SDK v2 + *

S3Client s3 = S3Client
+             .builder()
+             .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+             .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+                localstack.getAccessKey(), localstack.getSecretKey()
+             )))
+             .region(Region.of(localstack.getRegion()))
+             .build()
+     
*

Please note that this method is only intended to be used for configuring AWS SDK clients * that are running on the test host. If other containers need to call this one, they should be configured * specifically to do so using a Docker network and appropriate addressing.

@@ -99,20 +110,41 @@ public LocalStackContainer withServices(Service... services) { * @return an {@link AwsClientBuilder.EndpointConfiguration} */ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service service) { - final String address = getContainerIpAddress(); - String ipAddress = address; + return new AwsClientBuilder.EndpointConfiguration(getEndpointOverride(service).toString(), getRegion()); + } + + /** + * Provides an endpoint override that is preconfigured to communicate with a given simulated service. + * The provided endpoint override should be set in the AWS Java SDK v2 when building a client, e.g.: + *
S3Client s3 = S3Client
+             .builder()
+             .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+             .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+             localstack.getAccessKey(), localstack.getSecretKey()
+             )))
+             .region(Region.of(localstack.getRegion()))
+             .build()
+             
+ *

Please note that this method is only intended to be used for configuring AWS SDK clients + * that are running on the test host. If other containers need to call this one, they should be configured + * specifically to do so using a Docker network and appropriate addressing.

+ * + * @param service the service that is to be accessed + * @return an {@link URI} endpoint override + */ + public URI getEndpointOverride(Service service) { try { + final String address = getContainerIpAddress(); + String ipAddress = address; // resolve IP address and use that as the endpoint so that path-style access is automatically used for S3 ipAddress = InetAddress.getByName(address).getHostAddress(); - } catch (UnknownHostException ignored) { - - } - - return new AwsClientBuilder.EndpointConfiguration( - "http://" + + return new URI("http://" + ipAddress + ":" + - getMappedPort(service.getPort()), "us-east-1"); + getMappedPort(service.getPort())); + } catch (UnknownHostException | URISyntaxException e) { + throw new IllegalStateException("Cannot obtain endpoint URL", e); + } } /** @@ -124,10 +156,74 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service s .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); + * or for AWS SDK v2 you can use {@link #getAccessKey()}, {@link #getSecretKey()} directly: + *
S3Client s3 = S3Client
+             .builder()
+             .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+             .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+             localstack.getAccessKey(), localstack.getSecretKey()
+             )))
+             .region(Region.of(localstack.getRegion()))
+             .build()
+     
* @return an {@link AWSCredentialsProvider} */ public AWSCredentialsProvider getDefaultCredentialsProvider() { - return new AWSStaticCredentialsProvider(new BasicAWSCredentials("accesskey", "secretkey")); + return new AWSStaticCredentialsProvider(new BasicAWSCredentials(getAccessKey(), getSecretKey())); + } + + /** + * Provides a default access key that is preconfigured to communicate with a given simulated service. + * The access key can be used to construct AWS SDK v2 clients: + *
S3Client s3 = S3Client
+             .builder()
+             .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+             .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+             localstack.getAccessKey(), localstack.getSecretKey()
+             )))
+             .region(Region.of(localstack.getRegion()))
+             .build()
+     
+ * @return a default access key + */ + public String getAccessKey() { + return "accesskey"; + } + + /** + * Provides a default secret key that is preconfigured to communicate with a given simulated service. + * The secret key can be used to construct AWS SDK v2 clients: + *
S3Client s3 = S3Client
+             .builder()
+             .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+             .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+             localstack.getAccessKey(), localstack.getSecretKey()
+             )))
+             .region(Region.of(localstack.getRegion()))
+             .build()
+     
+ * @return a default secret key + */ + public String getSecretKey() { + return "secretkey"; + } + + /** + * Provides a default region that is preconfigured to communicate with a given simulated service. + * The region can be used to construct AWS SDK v2 clients: + *
S3Client s3 = S3Client
+             .builder()
+             .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+             .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+             localstack.getAccessKey(), localstack.getSecretKey()
+             )))
+             .region(Region.of(localstack.getRegion()))
+             .build()
+     
+ * @return a default region + */ + public String getRegion() { + return "us-east-1"; } @RequiredArgsConstructor diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index 034ff2f0914..ee5945d0aff 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -4,8 +4,6 @@ import com.amazonaws.services.logs.AWSLogs; import com.amazonaws.services.logs.AWSLogsClientBuilder; import com.amazonaws.services.logs.model.CreateLogGroupRequest; -import com.amazonaws.services.logs.model.CreateLogGroupResult; -import com.amazonaws.services.logs.model.DescribeLogGroupsRequest; import com.amazonaws.services.logs.model.LogGroup; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; @@ -19,7 +17,6 @@ import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.ClassRule; -import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; @@ -27,10 +24,15 @@ import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.Network; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; import java.io.IOException; import java.nio.charset.Charset; import java.util.List; +import java.util.Optional; import static org.hamcrest.CoreMatchers.containsString; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; @@ -67,24 +69,41 @@ public void s3TestOverBridgeNetwork() throws IOException { .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); - s3.createBucket("foo"); - s3.putObject("foo", "bar", "baz"); + final String bucketName = "foo"; + s3.createBucket(bucketName); + s3.putObject(bucketName, "bar", "baz"); final List buckets = s3.listBuckets(); - assertEquals("The created bucket is present", 1, buckets.size()); - final Bucket bucket = buckets.get(0); + final Optional maybeBucket = buckets.stream().filter(b -> b.getName().equals(bucketName)).findFirst(); + assertTrue("The created bucket is present", maybeBucket.isPresent()); + final Bucket bucket = maybeBucket.get(); - assertEquals("The created bucket has the right name", "foo", bucket.getName()); - assertEquals("The created bucket has the right name", "foo", bucket.getName()); + assertEquals("The created bucket has the right name", bucketName, bucket.getName()); - final ObjectListing objectListing = s3.listObjects("foo"); + final ObjectListing objectListing = s3.listObjects(bucketName); assertEquals("The created bucket has 1 item in it", 1, objectListing.getObjectSummaries().size()); - final S3Object object = s3.getObject("foo", "bar"); + final S3Object object = s3.getObject(bucketName, "bar"); final String content = IOUtils.toString(object.getObjectContent(), Charset.forName("UTF-8")); assertEquals("The object can be retrieved", "baz", content); } + @Test + public void s3TestUsingAwsSdkV2() { + S3Client s3 = S3Client + .builder() + .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3)) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create( + localstack.getAccessKey(), localstack.getSecretKey() + ))) + .region(Region.of(localstack.getRegion())) + .build(); + + final String bucketName = "foov2"; + s3.createBucket(b -> b.bucket(bucketName)); + assertTrue("New bucket was created", s3.listBuckets().buckets().stream().anyMatch(b -> b.name().equals(bucketName))); + } + @Test public void sqsTestOverBridgeNetwork() { AmazonSQS sqs = AmazonSQSClientBuilder.standard() From 1e803b8f96272f463715f8560736cc4596b23a52 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 23 Apr 2020 13:45:07 +0100 Subject: [PATCH 0634/4969] Use relative path for temp dirs in test (#2604) --- .../utility/AuthenticatedImagePullTest.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 56945643a88..5f4417f218b 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -110,8 +110,7 @@ public void testThatAuthLocatorIsUsedForContainerCreation() { @Test public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { // Prepare a simple temporary Dockerfile which requires our custom private image - Path tempContext = Files.createTempDirectory(Paths.get("."), this.getClass().getSimpleName() + "-test-"); - Path tempFile = Files.createTempFile(tempContext, "test", ".Dockerfile"); + Path tempFile = getLocalTempFile(".Dockerfile"); String dockerFileContent = "FROM " + testImageNameWithTag; Files.write(tempFile, dockerFileContent.getBytes()); @@ -130,8 +129,7 @@ public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { @Test public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { // Prepare a simple temporary Docker Compose manifest which requires our custom private image - Path tempContext = Files.createTempDirectory(Paths.get("."), this.getClass().getSimpleName() + "-test-"); - Path tempFile = Files.createTempFile(tempContext, "test", ".docker-compose.yml"); + Path tempFile = getLocalTempFile(".docker-compose.yml"); @Language("yaml") String composeFileContent = "version: '2.0'\n" + "services:\n" + @@ -153,6 +151,18 @@ public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { } } + private Path getLocalTempFile(String s) throws IOException { + Path projectRoot = Paths.get("."); + Path tempDirectory = Files.createTempDirectory(projectRoot, this.getClass().getSimpleName() + "-test-"); + Path relativeTempDirectory = projectRoot.relativize(tempDirectory); + Path tempFile = Files.createTempFile(relativeTempDirectory, "test", s); + + tempDirectory.toFile().deleteOnExit(); + tempFile.toFile().deleteOnExit(); + + return tempFile; + } + private static void putImageInRegistry() throws InterruptedException { // It doesn't matter which image we use for this test, but use one that's likely to have been pulled already final String dummySourceImage = TestcontainersConfiguration.getInstance().getRyukImage(); From 5fbf102a6532cb9e14c87cb15d4577c30fac026f Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 23 Apr 2020 16:19:52 +0100 Subject: [PATCH 0635/4969] Update version --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index e3cae4c5da8..708fbe06883 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,4 +88,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.14.0 + latest_version: 1.14.1 From 2281f8ff697b8e74f558412f814b5247d13d6759 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2020 05:23:36 +0000 Subject: [PATCH 0636/4969] Bump influxdb-java from 2.17 to 2.18 in /modules/influxdb (#2592) --- modules/influxdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index d349e06da12..02af2e924a9 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { compile project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.17' + compileOnly 'org.influxdb:influxdb-java:2.18' testCompile 'org.influxdb:influxdb-java:2.17' } From fdad5ce673bfd11a35f627bbd08fbc9af08e090c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 25 Apr 2020 01:31:52 +0000 Subject: [PATCH 0637/4969] Bump s3 from 2.11.10 to 2.13.2 in /modules/localstack (#2610) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index cd6f3d9f86c..4e882514e81 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.762' - testCompile 'software.amazon.awssdk:s3:2.11.10' + testCompile 'software.amazon.awssdk:s3:2.13.2' } From d5a79f6f777ebc134559046b5f16dbf500ab6884 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2020 14:58:35 +0100 Subject: [PATCH 0638/4969] Bump ipcsocket from 1.0.0 to 1.0.1 in /core (#2525) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d99ca8c3676..78e7b553606 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -133,7 +133,7 @@ dependencies { compile "net.java.dev.jna:jna-platform:5.5.0" - shaded ('org.scala-sbt.ipcsocket:ipcsocket:1.0.0') { + shaded ('org.scala-sbt.ipcsocket:ipcsocket:1.0.1') { exclude(group: "net.java.dev.jna") } From 4740cbe4b32667cec9b8d3028bb10319c718b062 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2020 15:07:39 +0100 Subject: [PATCH 0639/4969] Bump pulsar-client from 2.5.0 to 2.5.1 in /modules/pulsar (#2609) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 88d783fc221..4f459d9a97e 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.1' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.15.0' } From be41d15f5b9bcd133be58bd8ddd6a9a2b99e8a66 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2020 15:08:17 +0100 Subject: [PATCH 0640/4969] Bump aws-java-sdk-logs from 1.11.762 to 1.11.768 in /modules/localstack (#2611) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 4e882514e81..cd7678ccbf5 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,6 +6,6 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.762' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.768' testCompile 'software.amazon.awssdk:s3:2.13.2' } From 8e096cc0d27cdab6f1b07c6a2488a26fea559a35 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 26 Apr 2020 15:08:32 +0100 Subject: [PATCH 0641/4969] Replace legacy orchardup/mysql with mysql:5.7.22 in docker compose test (#2602) --- core/src/test/resources/compose-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/resources/compose-test.yml b/core/src/test/resources/compose-test.yml index 7436db7d211..a79a4c0b25b 100644 --- a/core/src/test/resources/compose-test.yml +++ b/core/src/test/resources/compose-test.yml @@ -1,6 +1,6 @@ redis: image: redis db: - image: orchardup/mysql + image: mysql:5.7.22 environment: - MYSQL_DATABASE: wordpress + MYSQL_RANDOM_ROOT_PASSWORD: "true" From dbe4b0f3d56bebbb09089633b65772a4aa54842b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2020 15:10:20 +0100 Subject: [PATCH 0642/4969] Bump amqp-client from 5.8.0 to 5.9.0 in /core (#2593) --- core/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 78e7b553606..9df3a024192 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -156,8 +156,9 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.2.0' - testCompile 'com.rabbitmq:amqp-client:5.8.0' + testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.3' + testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } From b54f162a6578fa01c44c04381787b7b9103e64c1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 05:23:31 +0000 Subject: [PATCH 0643/4969] Bump kafka-clients from 2.4.1 to 2.5.0 in /modules/kafka (#2576) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index cd6745e1eae..355c44eab1a 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.4.1' + testCompile 'org.apache.kafka:kafka-clients:2.5.0' testCompile 'org.assertj:assertj-core:3.15.0' testCompile 'com.google.guava:guava:23.0' } From bc3a26680886410bc0c59186092406439ab9c4c3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 15:56:43 +0200 Subject: [PATCH 0644/4969] Bump mysql-connector-java from 8.0.19 to 8.0.20 in /modules/spock (#2624) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.19 to 8.0.20. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index d091ce068dc..40f765f255c 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testRuntime 'org.postgresql:postgresql:42.2.12' - testRuntime 'mysql:mysql-connector-java:8.0.19' + testRuntime 'mysql:mysql-connector-java:8.0.20' } sourceJar { From aefb82281dca4802d9aaedb48535a313938ec373 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 16:02:15 +0200 Subject: [PATCH 0645/4969] Bump HikariCP from 3.4.2 to 3.4.3 in /modules/spock (#2625) Bumps [HikariCP](https://github.com/brettwooldridge/HikariCP) from 3.4.2 to 3.4.3. - [Release notes](https://github.com/brettwooldridge/HikariCP/releases) - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-3.4.2...HikariCP-3.4.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 40f765f255c..7b1780391b5 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.2' + testCompile 'com.zaxxer:HikariCP:3.4.3' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testRuntime 'org.postgresql:postgresql:42.2.12' From 746ee1bc4a8a92bb1e66d9d819c69ef567ca97f0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 16:03:50 +0200 Subject: [PATCH 0646/4969] Bump HikariCP from 3.4.2 to 3.4.3 in /modules/junit-jupiter (#2622) Bumps [HikariCP](https://github.com/brettwooldridge/HikariCP) from 3.4.2 to 3.4.3. - [Release notes](https://github.com/brettwooldridge/HikariCP/releases) - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-3.4.2...HikariCP-3.4.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 86d9b30930e..efc65cf57db 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.2' + testCompile 'com.zaxxer:HikariCP:3.4.3' testCompile 'redis.clients:jedis:3.2.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.11' testCompile ('org.mockito:mockito-core:3.3.3') { From 89d77fb58bd90ab1879a24a268e0feac31b86c3d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2020 09:39:48 +0200 Subject: [PATCH 0647/4969] Bump s3 from 2.13.2 to 2.13.4 in /modules/localstack (#2630) Bumps s3 from 2.13.2 to 2.13.4. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index cd7678ccbf5..343895fee53 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.768' - testCompile 'software.amazon.awssdk:s3:2.13.2' + testCompile 'software.amazon.awssdk:s3:2.13.4' } From 8c3a9c932f46c292ee5995a03fb6f9c9fee82c2d Mon Sep 17 00:00:00 2001 From: Benedikt Ritter Date: Thu, 30 Apr 2020 09:53:33 +0200 Subject: [PATCH 0648/4969] Fix typo in jupiter docs (#2636) --- docs/test_framework_integration/junit_5.md | 2 +- .../java/org/testcontainers/junit/jupiter/Testcontainers.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/test_framework_integration/junit_5.md b/docs/test_framework_integration/junit_5.md index 371240a8d54..11798484b0f 100644 --- a/docs/test_framework_integration/junit_5.md +++ b/docs/test_framework_integration/junit_5.md @@ -19,7 +19,7 @@ methods (methods on the `Startable` interface). Containers declared as static fi methods. They will be started only once before any test method is executed and stopped after the last test method has executed. Containers declared as instance fields will be started and stopped for every test method. -**Note:** This extension has only be tested with sequential test execution. Using it with parallel test execution is +**Note:** This extension has only been tested with sequential test execution. Using it with parallel test execution is unsupported and may have unintended side effects. *Example:* diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java index 8e05dfdc576..db8273563a7 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java @@ -23,7 +23,7 @@ * the test hierarchy as well. All subclasses will automatically inherit * support for the extension.

* - *

Note: This extension has only be tested with sequential + *

Note: This extension has only been tested with sequential * test execution. Using it with parallel test execution is unsupported and * may have unintended side effects.

* From 2dac7ba4bba73b7c44d71856b20c9b1476f344ce Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 May 2020 18:52:44 +0100 Subject: [PATCH 0649/4969] Bump aws-java-sdk-logs from 1.11.768 to 1.11.773 in /modules/localstack (#2641) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 343895fee53..82cf5c1f841 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,6 +6,6 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.768' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.773' testCompile 'software.amazon.awssdk:s3:2.13.4' } From afa89ecf0888504673fa7c29dec80b3fd6096f23 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 May 2020 18:52:56 +0100 Subject: [PATCH 0650/4969] Bump mysql-connector-java from 8.0.19 to 8.0.20 in /modules/junit-jupiter (#2620) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index efc65cf57db..5046008c7fa 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' testRuntime 'org.postgresql:postgresql:42.2.12' - testRuntime 'mysql:mysql-connector-java:8.0.19' + testRuntime 'mysql:mysql-connector-java:8.0.20' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' } From f0e6e55b7550665402d0b7afeb656e80910be1a9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 May 2020 18:58:29 +0100 Subject: [PATCH 0651/4969] Bump okhttp from 3.14.7 to 3.14.8 in /examples (#2645) --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index e7bed23509d..96dd03c602b 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:3.14.7' + implementation 'com.squareup.okhttp3:okhttp:3.14.8' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.12' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 4b385cde15aaeb0a4c74065cd424ddebf1791c55 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 May 2020 18:58:47 +0100 Subject: [PATCH 0652/4969] Bump testcontainers from 1.14.0 to 1.14.1 in /core (#2623) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9df3a024192..bbf57a34a70 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -110,7 +110,7 @@ if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { } dependencies { - baseline 'org.testcontainers:testcontainers:1.14.0', { + baseline 'org.testcontainers:testcontainers:1.14.1', { exclude group: "*", module: "*" } From 6fb689f8938518a144640e4c690ef56cbe767870 Mon Sep 17 00:00:00 2001 From: Konstantin Lutovich Date: Fri, 1 May 2020 20:22:30 +0200 Subject: [PATCH 0653/4969] Add a getter for Toxiproxy exposed port (#2513) --- docs/modules/toxiproxy.md | 15 +++-- .../containers/ToxiproxyContainer.java | 16 +++++- .../containers/ToxiproxyTest.java | 55 +++++++++++++------ 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/docs/modules/toxiproxy.md b/docs/modules/toxiproxy.md index 9e09d8b387b..8ffb910d6c1 100644 --- a/docs/modules/toxiproxy.md +++ b/docs/modules/toxiproxy.md @@ -29,13 +29,21 @@ We do this as follows: [Starting proxying connections to a target container](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:obtainProxyObject -Then, to establish a connection via Toxiproxy, we obtain **Toxiproxy's** proxy host IP and port: +To establish a connection from the test code (on the host machine) to the target container via Toxiproxy, we obtain **Toxiproxy's** proxy host IP and port: -[Obtaining proxied host and port](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:obtainProxiedHostAndPort +[Obtaining proxied host and port for connections from the host machine](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:obtainProxiedHostAndPortForHostMachine -Code under test, or other containers, should connect to this proxied host IP and port. +Code under test should connect to this proxied host IP and port. + +To establish a connection from a different container on the same network to the target container via Toxiproxy, we use **Toxiproxy's** network alias and original port: + + +[Obtaining proxied host and port for connections from a different container](../../modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java) inside_block:obtainProxiedHostAndPortForDifferentContainer + + +Other containers should connect to this proxied host and port. Having done this, it is possible to trigger failure conditions ('Toxics') through the `proxy.toxics()` object: @@ -82,4 +90,3 @@ testCompile "org.testcontainers:toxiproxy:{{latest_version}}" This module was inspired by a [hotels.com blog post](https://medium.com/hotels-com-technology/i-dont-know-about-resilience-testing-and-so-can-you-b3c59d80012d). [toxiproxy-java](https://github.com/trekawek/toxiproxy-java) is used to help control failure conditions. - diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index df4bf6e688d..1b631fa9d6d 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -87,7 +87,8 @@ public ContainerProxy getProxy(String hostname, int port) { } final Proxy proxy = client.createProxy(upstream, "0.0.0.0:" + toxiPort, upstream); - return new ContainerProxy(proxy, getContainerIpAddress(), getMappedPort(toxiPort)); + final int mappedPort = getMappedPort(toxiPort); + return new ContainerProxy(proxy, getContainerIpAddress(), mappedPort, toxiPort); } catch (IOException e) { throw new RuntimeException("Proxy could not be created", e); } @@ -99,8 +100,21 @@ public static class ContainerProxy { private static final String CUT_CONNECTION_DOWNSTREAM = "CUT_CONNECTION_DOWNSTREAM"; private static final String CUT_CONNECTION_UPSTREAM = "CUT_CONNECTION_UPSTREAM"; private final Proxy toxi; + /** + * The IP address that this proxy container may be reached on from the host machine. + */ @Getter private final String containerIpAddress; + /** + * The mapped port of this proxy. This is a port of the host machine. It can be used to + * access the Toxiproxy container from the host machine. + */ @Getter private final int proxyPort; + /** + * The original (exposed) port of this proxy. This is a port of the Toxiproxy Docker + * container. It can be used to access this container from a different Docker container + * on the same network. + */ + @Getter private final int originalProxyPort; private boolean isCurrentlyCut; public ToxicList toxics() { diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index c96e2efd19e..366f425b5b5 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -1,10 +1,9 @@ package org.testcontainers.containers; import eu.rekawek.toxiproxy.model.ToxicDirection; +import java.time.Duration; import org.junit.Rule; import org.junit.Test; -import org.testcontainers.testsupport.Flaky; -import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; import redis.clients.jedis.Jedis; import redis.clients.jedis.exceptions.JedisConnectionException; @@ -15,12 +14,18 @@ public class ToxiproxyTest { + private static final Duration JEDIS_TIMEOUT = Duration.ofSeconds(10); + // creatingProxy { + // An alias that can be used to resolve the Toxiproxy container by name in the network it is connected to. + // It can be used as a hostname of the Toxiproxy container by other containers in the same network. + private static final String TOXIPROXY_NETWORK_ALIAS = "toxiproxy"; + // Create a common docker network so that containers can communicate @Rule public Network network = Network.newNetwork(); - // the target container - this could be anything + // The target container - this could be anything @Rule public GenericContainer redis = new GenericContainer("redis:5.0.4") .withExposedPorts(6379) @@ -29,15 +34,13 @@ public class ToxiproxyTest { // Toxiproxy container, which will be used as a TCP proxy @Rule public ToxiproxyContainer toxiproxy = new ToxiproxyContainer() - .withNetwork(network); + .withNetwork(network) + .withNetworkAliases(TOXIPROXY_NETWORK_ALIAS); // } - @Rule - public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); - @Test public void testDirect() { - final Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getFirstMappedPort()); + final Jedis jedis = createJedis(redis.getContainerIpAddress(), redis.getFirstMappedPort()); jedis.set("somekey", "somevalue"); final String s = jedis.get("somekey"); @@ -45,18 +48,17 @@ public void testDirect() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2020-03-01") public void testLatencyViaProxy() throws IOException { // obtainProxyObject { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); // } - // obtainProxiedHostAndPort { + // obtainProxiedHostAndPortForHostMachine { final String ipAddressViaToxiproxy = proxy.getContainerIpAddress(); final int portViaToxiproxy = proxy.getProxyPort(); // } - final Jedis jedis = new Jedis(ipAddressViaToxiproxy, portViaToxiproxy); + final Jedis jedis = createJedis(ipAddressViaToxiproxy, portViaToxiproxy); jedis.set("somekey", "somevalue"); checkCallWithLatency(jedis, "without interference", 0, 250); @@ -72,10 +74,9 @@ public void testLatencyViaProxy() throws IOException { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2020-03-01") public void testConnectionCut() { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy(redis, 6379); - final Jedis jedis = new Jedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); + final Jedis jedis = createJedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); jedis.set("somekey", "somevalue"); assertEquals("access to the container works OK before cutting the connection", "somevalue", jedis.get("somekey")); @@ -97,7 +98,6 @@ public void testConnectionCut() { } @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1769", reviewDate = "2020-03-01") public void testMultipleProxiesCanBeCreated() { try (GenericContainer secondRedis = new GenericContainer("redis:5.0.4") .withExposedPorts(6379) @@ -108,8 +108,8 @@ public void testMultipleProxiesCanBeCreated() { final ToxiproxyContainer.ContainerProxy firstProxy = toxiproxy.getProxy(redis, 6379); final ToxiproxyContainer.ContainerProxy secondProxy = toxiproxy.getProxy(secondRedis, 6379); - final Jedis firstJedis = new Jedis(firstProxy.getContainerIpAddress(), firstProxy.getProxyPort()); - final Jedis secondJedis = new Jedis(secondProxy.getContainerIpAddress(), secondProxy.getProxyPort()); + final Jedis firstJedis = createJedis(firstProxy.getContainerIpAddress(), firstProxy.getProxyPort()); + final Jedis secondJedis = createJedis(secondProxy.getContainerIpAddress(), secondProxy.getProxyPort()); firstJedis.set("somekey", "somevalue"); secondJedis.set("somekey", "somevalue"); @@ -125,6 +125,25 @@ public void testMultipleProxiesCanBeCreated() { } } + @Test + public void testOriginalAndMappedPorts() { + final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy("hostname", 7070); + // obtainProxiedHostAndPortForDifferentContainer { + final String hostViaToxiproxy = TOXIPROXY_NETWORK_ALIAS; + final int portViaToxiproxy = proxy.getOriginalProxyPort(); + // } + assertEquals("host is correct", TOXIPROXY_NETWORK_ALIAS, hostViaToxiproxy); + assertEquals("original port is correct", 8666, portViaToxiproxy); + + final ToxiproxyContainer.ContainerProxy proxy1 = toxiproxy.getProxy("hostname1", 8080); + assertEquals("original port is correct", 8667, proxy1.getOriginalProxyPort()); + assertEquals("mapped port is correct", toxiproxy.getMappedPort(proxy1.getOriginalProxyPort()), proxy1.getProxyPort()); + + final ToxiproxyContainer.ContainerProxy proxy2 = toxiproxy.getProxy("hostname2", 9090); + assertEquals("original port is correct", 8668, proxy2.getOriginalProxyPort()); + assertEquals("mapped port is correct", toxiproxy.getMappedPort(proxy2.getOriginalProxyPort()), proxy2.getProxyPort()); + } + private void checkCallWithLatency(Jedis jedis, final String description, int expectedMinLatency, long expectedMaxLatency) { final long start = System.currentTimeMillis(); String s = jedis.get("somekey"); @@ -135,4 +154,8 @@ private void checkCallWithLatency(Jedis jedis, final String description, int exp assertTrue(format("%s there is at least %dms latency", description, expectedMinLatency), duration >= expectedMinLatency); assertTrue(format("%s there is no more than %dms latency", description, expectedMaxLatency), duration < expectedMaxLatency); } + + private static Jedis createJedis(String host, int port) { + return new Jedis(host, port, Math.toIntExact(JEDIS_TIMEOUT.toMillis())); + } } From 88849acbec0d2d6511c8e112f053253eb384f4fd Mon Sep 17 00:00:00 2001 From: sumitanvekar <2293969+sumitanvekar@users.noreply.github.com> Date: Sat, 2 May 2020 00:13:32 +0530 Subject: [PATCH 0654/4969] Example and docs for ability to copy to and from container for #1164 (#1989) --- .../junit/CopyFileToContainerTest.java | 30 ++++++++++++++++--- docs/features/files.md | 16 ++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java index ed6ee561505..1e230ec605b 100644 --- a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java @@ -1,32 +1,54 @@ package org.testcontainers.junit; +import com.google.common.io.Files; +import com.google.common.io.Resources; import org.junit.Test; import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.SelinuxContext; import org.testcontainers.utility.MountableFile; +import java.io.File; import java.io.IOException; import java.util.Map; +import static org.junit.Assert.assertArrayEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class CopyFileToContainerTest { - private static String containerPath = "/tmp/mappable-resource/"; + public static final String destinationOnHost = "/tmp/test-resource-in-host.txt"; + private static String directoryInContainer = "/tmp/mappable-resource/"; private static String fileName = "test-resource.txt"; @Test public void checkFileCopied() throws IOException, InterruptedException { try ( + // copyToContainer { GenericContainer container = new GenericContainer() .withCommand("sleep", "3000") - .withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), containerPath) + // withCopyFileToContainer ensure that a file or directory will be copied to the container + // before starting. In this case, we map a classpath directory to a directory inside the container + .withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), directoryInContainer) + // } ) { container.start(); - String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); + + // at this point directoryInContainer should exist, and should contain copies of file(s) + String filesList = container.execInContainer("ls", directoryInContainer).getStdout(); assertTrue("file list contains the file", filesList.contains(fileName)); + + // ... + + // copyFromContainer { + container.copyFileFromContainer(directoryInContainer + fileName, destinationOnHost); + // } } + + assertArrayEquals( + Files.toByteArray(new File(destinationOnHost)), + Resources.toByteArray(CopyFileToContainerTest.class.getResource("/mappable-resource/" + fileName)) + ); } @Test @@ -34,7 +56,7 @@ public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { try ( GenericContainer container = new GenericContainer() .withCommand("sleep", "3000") - .withClasspathResourceMapping("/mappable-resource/", containerPath, BindMode.READ_ONLY) + .withClasspathResourceMapping("/mappable-resource/", directoryInContainer, BindMode.READ_ONLY) ) { container.start(); String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); diff --git a/docs/features/files.md b/docs/features/files.md index a74b1add134..47240f82cd2 100644 --- a/docs/features/files.md +++ b/docs/features/files.md @@ -9,3 +9,19 @@ new GenericContainer(...) "/etc/redis.conf", BindMode.READ_ONLY) ``` + +## Copying files to and from containers + +Files can be copied into the container before startup, or can be copied from the container after the container has started. + +### Copying to a container before startup + + +[Copying files to a container](../../core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java) inside_block:copyToContainer + + +### Copying a file from a running container + + +[Copying files from a container](../../core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java) inside_block:copyFromContainer + From cae51cd6fc97aeab8be8f645fbcc26dda9513823 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 2 May 2020 10:07:30 +0100 Subject: [PATCH 0655/4969] Tweak GHA CI configuration to enable Gradle remote cache push --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df6fc96ea44..b9c94223eb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,8 @@ jobs: # Since we override the tests executor, # we should not push empty results to the cache READ_ONLY_REMOTE_GRADLE_CACHE: true + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} run: | TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) echo $TASKS @@ -56,6 +58,9 @@ jobs: - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Aggregate test reports with ciMate if: always() env: @@ -83,6 +88,9 @@ jobs: working-directory: ./examples/ run: | ./gradlew --no-daemon --scan --info check + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Aggregate test reports with ciMate if: always() env: From 3d407196be6865fef0daaf3e4077b565e0aa0a19 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 2 May 2020 10:07:59 +0100 Subject: [PATCH 0656/4969] Simplify remote build cache boolean expression --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 4321c4ac4a4..150d79f89fe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,7 +27,7 @@ buildCache { region = 'fra1' bucket = 'testcontainers' path = 'cache' - push = !(System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") || !isMasterBuild) + push = isMasterBuild && !System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") headers = [ 'x-amz-acl': 'public-read' ] From e10c7eab23d84827c4e09e1e92312a2295626d71 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 2 May 2020 10:22:45 +0100 Subject: [PATCH 0657/4969] Pull up `env` to top level to be available to all jobs/steps --- .github/workflows/ci.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9c94223eb3..a6baaf7e92d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,10 @@ on: pull_request: {} push: { branches: [ master ] } +env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + jobs: find_gradle_jobs: runs-on: ubuntu-18.04 @@ -27,8 +31,6 @@ jobs: # Since we override the tests executor, # we should not push empty results to the cache READ_ONLY_REMOTE_GRADLE_CACHE: true - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} run: | TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) echo $TASKS @@ -58,9 +60,6 @@ jobs: - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Aggregate test reports with ciMate if: always() env: @@ -88,9 +87,6 @@ jobs: working-directory: ./examples/ run: | ./gradlew --no-daemon --scan --info check - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Aggregate test reports with ciMate if: always() env: From fd28fcf42bde161ab42a2f8157e205de5bb0446e Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 2 May 2020 12:23:44 +0100 Subject: [PATCH 0658/4969] Fix flaky JDBC tmpfs test (#2646) --- .../jdbc/DatabaseDriverTmpfsTest.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java index 07a17f68ade..6f337a586b6 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java +++ b/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -1,27 +1,19 @@ package org.testcontainers.jdbc; -import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.Container; import org.testcontainers.containers.JdbcDatabaseContainer; -import org.testcontainers.testsupport.Flaky; -import org.testcontainers.testsupport.FlakyTestJUnit4RetryRule; -import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; -import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; public class DatabaseDriverTmpfsTest { - @Rule - public FlakyTestJUnit4RetryRule retry = new FlakyTestJUnit4RetryRule(); - @Test - @Flaky(githubIssueUrl = "https://github.com/testcontainers/testcontainers-java/issues/1687", reviewDate = "2020-03-01") - public void tmpfs() throws IOException, InterruptedException, SQLException { + public void testDatabaseHasTmpFsViaConnectionString() throws Exception { final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw"; try (Connection ignored = DriverManager.getConnection(jdbcUrl)) { @@ -29,15 +21,11 @@ public void tmpfs() throws IOException, InterruptedException, SQLException { // check file doesn't exist String path = "/testtmpfs/test.file"; Container.ExecResult execResult = container.execInContainer("ls", path); - assertEquals("tmpfs inside container works fine", execResult.getStderr(), - "ls: cannot access '/testtmpfs/test.file': No such file or directory\n"); + assertNotEquals("tmpfs inside container doesn't have file that doesn't exist", 0, execResult.getExitCode()); // touch && check file does exist container.execInContainer("touch", path); execResult = container.execInContainer("ls", path); - assertEquals("tmpfs inside container works fine", execResult.getStdout(), path + "\n"); + assertEquals("tmpfs inside container has file that does exist", 0, execResult.getExitCode()); } - } - - } From 12fef372c278f6b2d07700161dec5ff92da6576d Mon Sep 17 00:00:00 2001 From: mans2singh Date: Sat, 2 May 2020 10:25:24 -0400 Subject: [PATCH 0659/4969] Doc update for elasticsearch and kafka (#2615) --- docs/modules/elasticsearch.md | 2 +- docs/modules/kafka.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index 02eeb61dfbe..c7efa872df6 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -36,7 +36,7 @@ container.stop(); ``` Note that if you are still using the [TransportClient](https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.3/transport-client.html) -(not recommended as deprecated), the default cluster name is set to `docker-cluster` so you need to change `cluster.name` setting +(not recommended as it is deprecated), the default cluster name is set to `docker-cluster` so you need to change `cluster.name` setting or set `client.transport.ignore_cluster_name` to `true`. ## Choose your Elasticsearch license diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index c0b85b67a62..a96a0a0b43a 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -42,7 +42,7 @@ new KafkaContainer().withExternalZookeeper("localhost:2181") If your test needs to run some other Docker container which needs access to the Kafka, do the following: -* Run you other container on the same network as Kafka container. E.g. as following: +* Run your other container on the same network as Kafka container, e.g.: ```java new GenericContainer("myImage").withNetwork(kafka.getNetwork()) ``` From 3e4e5f27988809a5897bc1cf0e2407002153dfec Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 2 May 2020 17:51:39 +0200 Subject: [PATCH 0660/4969] Fix a regression in OracleContainer introduced in #2473 (#2612) --- .../org/testcontainers/containers/OracleContainer.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index bad22af2511..e86768bc383 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -38,12 +38,15 @@ public OracleContainer() { public OracleContainer(String dockerImageName) { super(dockerImageName); - withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); - withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); + preconfigure(); } public OracleContainer(Future dockerImageName) { super(dockerImageName); + preconfigure(); + } + + private void preconfigure() { withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT); From 2bb9613731a0a662f63323f7bb99a399cc1e1c92 Mon Sep 17 00:00:00 2001 From: Janusz Date: Sat, 2 May 2020 17:56:10 +0200 Subject: [PATCH 0661/4969] Docker Compose: Verify that all services that have a wait condition defined also have a corresponding service instance (#2637) --- .../containers/DockerComposeContainer.java | 15 +++++ .../junit/DockerComposeWaitStrategyTest.java | 55 ++++++++++++++++--- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 61036f690cd..7bf8d3c916b 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -6,6 +6,7 @@ import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.common.util.concurrent.Uninterruptibles; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -216,6 +217,20 @@ private void createServices() { private void waitUntilServiceStarted() { listChildContainers().forEach(this::createServiceInstance); + + Set servicesToWaitFor = waitStrategyMap.keySet(); + Set instantiatedServices = serviceInstanceMap.keySet(); + Sets.SetView missingServiceInstances = + Sets.difference(servicesToWaitFor, instantiatedServices); + + if (!missingServiceInstances.isEmpty()) { + throw new IllegalStateException( + "Services named " + missingServiceInstances + " " + + "do not exist, but wait conditions have been defined " + + "for them. This might mean that you misspelled " + + "the service name when defining the wait condition."); + } + serviceInstanceMap.forEach(this::waitUntilServiceStarted); } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java index 7724b048b69..32465010700 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java @@ -1,21 +1,40 @@ package org.testcontainers.junit; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.io.File; +import java.time.Duration; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.Description; +import org.mockito.Mockito; import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.wait.strategy.Wait; - -import java.io.File; -import java.time.Duration; +import org.testcontainers.containers.wait.strategy.WaitStrategy; public class DockerComposeWaitStrategyTest { private static final int REDIS_PORT = 6379; + private DockerComposeContainer environment; + + @Before + public final void setUp() { + environment = new DockerComposeContainer<>( + new File("src/test/resources/compose-test.yml")); + } + + @After + public final void cleanUp() { + environment.stop(); + } + @Test public void testWaitOnListeningPort() { - final DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) + environment .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()); try { @@ -28,7 +47,7 @@ public void testWaitOnListeningPort() { @Test public void testWaitOnMultipleStrategiesPassing() { - final DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) + environment .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()) .withExposedService("db_1", 3306, Wait.forLogMessage(".*ready for connections.*\\s", 1)) .withTailChildContainers(true); @@ -43,7 +62,7 @@ public void testWaitOnMultipleStrategiesPassing() { @Test public void testWaitingFails() { - final DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) + environment .withExposedService("redis_1", REDIS_PORT, Wait.forHttp("/test").withStartupTimeout(Duration.ofSeconds(10))); VisibleAssertions.assertThrows("waiting on an invalid http path times out", RuntimeException.class, @@ -52,7 +71,7 @@ public void testWaitingFails() { @Test public void testWaitOnOneOfMultipleStrategiesFailing() { - final DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) + environment .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(10))) .waitingFor("db_1", Wait.forLogMessage(".*test test test.*\\s", 1).withStartupTimeout(Duration.ofSeconds(10))) .withTailChildContainers(true); @@ -62,4 +81,26 @@ public void testWaitOnOneOfMultipleStrategiesFailing() { () -> environment.starting(Description.createTestDescription(Object.class, "name"))); } + @Test + public void testWaitingForNonexistentServices() { + String existentServiceName = "db_1"; + String nonexistentServiceName1 = "some_nonexistent_service_1"; + String nonexistentServiceName2 = "some_nonexistent_service_2"; + WaitStrategy someWaitStrategy = Mockito.mock(WaitStrategy.class); + + environment + .waitingFor(existentServiceName, someWaitStrategy) + .waitingFor(nonexistentServiceName1, someWaitStrategy) + .waitingFor(nonexistentServiceName2, someWaitStrategy); + + Throwable thrownWhenRequestedToWaitForNonexistentService = + catchThrowable(environment::start); + + assertThat(thrownWhenRequestedToWaitForNonexistentService) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining( + nonexistentServiceName1, + nonexistentServiceName2) + .hasMessageNotContaining(existentServiceName); + } } From eada48eadcbc5ab1cb97d833b9de6b2350efa172 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 2 May 2020 19:50:26 +0100 Subject: [PATCH 0662/4969] Remove .envrc file --- .envrc | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .envrc diff --git a/.envrc b/.envrc deleted file mode 100644 index dad2eb2cfc6..00000000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use python 3.7.5 From a3b200b12d6f93d07c1c1864c2197b6a358dd7b1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 2 May 2020 20:05:47 +0100 Subject: [PATCH 0663/4969] Bump mysql-connector-java from 8.0.19 to 8.0.20 in /modules/mysql (#2618) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 606aeefe813..2ee2d62ce59 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly project(':r2dbc') compileOnly 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' - testCompile 'mysql:mysql-connector-java:8.0.19' + testCompile 'mysql:mysql-connector-java:8.0.20' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.34' testCompile 'commons-dbutils:commons-dbutils:1.7' From f30ac94f8aa0b67e8795845b7357ae70c33ec4a0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 2 May 2020 20:05:59 +0100 Subject: [PATCH 0664/4969] Bump s3 from 2.13.4 to 2.13.7 in /modules/localstack (#2642) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 82cf5c1f841..0f905597e26 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.773' - testCompile 'software.amazon.awssdk:s3:2.13.4' + testCompile 'software.amazon.awssdk:s3:2.13.7' } From 7c761a9e3571609ab6aacbaecdae67f79c3526b4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 2 May 2020 20:07:08 +0100 Subject: [PATCH 0665/4969] Bump guava from 28.2-jre to 29.0-jre in /core (#2643) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index bbf57a34a70..9b317074909 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ buildscript { dependencies { // https://github.com/melix/japicmp-gradle-plugin/issues/36 - classpath 'com.google.guava:guava:28.2-jre' + classpath 'com.google.guava:guava:29.0-jre' } } From 0050e70e24b1cd6540bd08eb960467aa11544398 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 3 May 2020 10:43:38 +0100 Subject: [PATCH 0666/4969] Revert "Example and docs for ability to copy to and from container for #1164" (#2651) --- .../junit/CopyFileToContainerTest.java | 30 +++---------------- docs/features/files.md | 16 ---------- 2 files changed, 4 insertions(+), 42 deletions(-) diff --git a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java index 1e230ec605b..ed6ee561505 100644 --- a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java @@ -1,54 +1,32 @@ package org.testcontainers.junit; -import com.google.common.io.Files; -import com.google.common.io.Resources; import org.junit.Test; import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.SelinuxContext; import org.testcontainers.utility.MountableFile; -import java.io.File; import java.io.IOException; import java.util.Map; -import static org.junit.Assert.assertArrayEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class CopyFileToContainerTest { - public static final String destinationOnHost = "/tmp/test-resource-in-host.txt"; - private static String directoryInContainer = "/tmp/mappable-resource/"; + private static String containerPath = "/tmp/mappable-resource/"; private static String fileName = "test-resource.txt"; @Test public void checkFileCopied() throws IOException, InterruptedException { try ( - // copyToContainer { GenericContainer container = new GenericContainer() .withCommand("sleep", "3000") - // withCopyFileToContainer ensure that a file or directory will be copied to the container - // before starting. In this case, we map a classpath directory to a directory inside the container - .withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), directoryInContainer) - // } + .withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), containerPath) ) { container.start(); - - // at this point directoryInContainer should exist, and should contain copies of file(s) - String filesList = container.execInContainer("ls", directoryInContainer).getStdout(); + String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); assertTrue("file list contains the file", filesList.contains(fileName)); - - // ... - - // copyFromContainer { - container.copyFileFromContainer(directoryInContainer + fileName, destinationOnHost); - // } } - - assertArrayEquals( - Files.toByteArray(new File(destinationOnHost)), - Resources.toByteArray(CopyFileToContainerTest.class.getResource("/mappable-resource/" + fileName)) - ); } @Test @@ -56,7 +34,7 @@ public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { try ( GenericContainer container = new GenericContainer() .withCommand("sleep", "3000") - .withClasspathResourceMapping("/mappable-resource/", directoryInContainer, BindMode.READ_ONLY) + .withClasspathResourceMapping("/mappable-resource/", containerPath, BindMode.READ_ONLY) ) { container.start(); String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); diff --git a/docs/features/files.md b/docs/features/files.md index 47240f82cd2..a74b1add134 100644 --- a/docs/features/files.md +++ b/docs/features/files.md @@ -9,19 +9,3 @@ new GenericContainer(...) "/etc/redis.conf", BindMode.READ_ONLY) ``` - -## Copying files to and from containers - -Files can be copied into the container before startup, or can be copied from the container after the container has started. - -### Copying to a container before startup - - -[Copying files to a container](../../core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java) inside_block:copyToContainer - - -### Copying a file from a running container - - -[Copying files from a container](../../core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java) inside_block:copyFromContainer - From 8fd4c2081d3975473d430b81b08fa25c30d74199 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 5 May 2020 20:58:50 +0100 Subject: [PATCH 0667/4969] Make neo4j module support Gradle caching (#2649) --- modules/neo4j/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 9361824fdd6..1f119ff83bd 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -20,6 +20,10 @@ task customNeo4jPluginJar(type: Jar) { from sourceSets.customNeo4jPlugin.output archiveName = "hello-world.jar" destinationDir = customNeo4jPluginDestinationDir + + inputs.files(sourceSets.customNeo4jPlugin.java.srcDirs) + outputs.cacheIf { true } + outputs.dir(customNeo4jPluginDestinationDir) } test.dependsOn customNeo4jPluginJar From 2ea0524494075709babd3b470cadb99bf19a0e0a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 May 2020 20:59:58 +0100 Subject: [PATCH 0668/4969] Bump jedis from 3.2.0 to 3.3.0 in /core (#2653) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9b317074909..fc4a36ea0b9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -155,7 +155,7 @@ dependencies { } testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testCompile 'redis.clients:jedis:3.2.0' + testCompile 'redis.clients:jedis:3.3.0' testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.3' From 6f4f808357d47907decfd650b211ac6cae9e182b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 May 2020 21:00:11 +0100 Subject: [PATCH 0669/4969] Bump jedis from 3.2.0 to 3.3.0 in /modules/junit-jupiter (#2652) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5046008c7fa..7acc7fcbf11 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.3' - testCompile 'redis.clients:jedis:3.2.0' + testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.11' testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') From 6b522dbc6c39d68ae1c046bbcaf2acd110a91f86 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 May 2020 21:00:27 +0100 Subject: [PATCH 0670/4969] Bump jedis from 3.2.0 to 3.3.0 in /examples (#2656) --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 1779966c692..62f7de6dcf8 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.2.0' + implementation 'redis.clients:jedis:3.3.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 9dea8531b5e..258c98fb107 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.2.0' + implementation 'redis.clients:jedis:3.3.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index b06d4e7cb30..11e6cb2a31b 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.2.0' + implementation 'redis.clients:jedis:3.3.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.30' From 71d0c0c48c445fe77450a44fa27f756f58bf36f4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 May 2020 21:01:07 +0100 Subject: [PATCH 0671/4969] Bump cucumber-junit from 5.6.0 to 5.7.0 in /examples (#2657) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 53a50c374f5..92724e358db 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' - testImplementation 'io.cucumber:cucumber-junit:5.6.0' + testImplementation 'io.cucumber:cucumber-junit:5.7.0' testImplementation 'io.cucumber:cucumber-java:5.6.0' testImplementation 'org.testcontainers:selenium' } From 7e92eea2f0650ed0ff19a702451cbf60ef27395f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 May 2020 21:14:06 +0100 Subject: [PATCH 0672/4969] Bump cucumber-java from 5.6.0 to 5.7.0 in /examples (#2658) --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 92724e358db..011b2bddecd 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' + testImplementation 'io.cucumber:cucumber-java:5.7.0' testImplementation 'io.cucumber:cucumber-junit:5.7.0' - testImplementation 'io.cucumber:cucumber-java:5.6.0' testImplementation 'org.testcontainers:selenium' } From 5cd771e6294e25fa186452fcd3f699246950b89d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 May 2020 21:15:13 +0100 Subject: [PATCH 0673/4969] Bump s3 from 2.13.7 to 2.13.9 in /modules/localstack (#2659) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 0f905597e26..98f01ea3b38 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.773' - testCompile 'software.amazon.awssdk:s3:2.13.7' + testCompile 'software.amazon.awssdk:s3:2.13.9' } From 0adeb114b957721ff457b83e3dbd26a5be0eae36 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 May 2020 21:25:05 +0100 Subject: [PATCH 0674/4969] Bump aws-java-sdk-logs from 1.11.773 to 1.11.775 in /modules/localstack (#2660) --- modules/localstack/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 98f01ea3b38..89e204515c5 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,9 +3,9 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.683' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.773' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.775' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.775' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.775' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' testCompile 'software.amazon.awssdk:s3:2.13.9' } From edde70525af03a2a8fdde95a9e5f6a3d6a27bf5f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 6 May 2020 09:01:01 +0200 Subject: [PATCH 0675/4969] Bump assertj-core from 3.15.0 to 3.16.0 in /core (#2671) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.15.0 to 3.16.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.15.0...assertj-core-3.16.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index fc4a36ea0b9..f74744255f8 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -165,12 +165,12 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.15.0' + testCompile 'org.assertj:assertj-core:3.16.0' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' - jarFileTestCompile 'org.assertj:assertj-core:3.14.0' + jarFileTestCompile 'org.assertj:assertj-core:3.16.0' jarFileTestCompile 'org.ow2.asm:asm-debug-all:5.2' } From eb58a9a023d1d52980f578af8083421216416352 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 6 May 2020 09:02:28 +0200 Subject: [PATCH 0676/4969] Bump assertj-core from 3.15.0 to 3.16.0 in /modules/vault (#2670) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.15.0 to 3.16.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.15.0...assertj-core-3.16.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index bf85047ddd7..b8681be150d 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.0' - testCompile 'org.assertj:assertj-core:3.15.0' + testCompile 'org.assertj:assertj-core:3.16.0' } From ef3ac663b4bc1f43520407aa971537506a1c5dfb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 6 May 2020 09:02:52 +0200 Subject: [PATCH 0677/4969] Bump assertj-core from 3.15.0 to 3.16.0 in /modules/junit-jupiter (#2669) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.15.0 to 3.16.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.15.0...assertj-core-3.16.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7acc7fcbf11..b80f9263e9c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.15.0' + testCompile 'org.assertj:assertj-core:3.16.0' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' testRuntime 'org.postgresql:postgresql:42.2.12' From 1f535b72bd4a2ff02f9b58d5c588acd0ff8eb395 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 6 May 2020 09:03:17 +0200 Subject: [PATCH 0678/4969] Bump assertj-core from 3.15.0 to 3.16.0 in /modules/database-commons (#2672) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.15.0 to 3.16.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.15.0...assertj-core-3.16.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index d8738a6cb69..14dffc649ac 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.15.0' + testCompile 'org.assertj:assertj-core:3.16.0' } From 5b2590c2eae76aeccd29a49c347591674cffead7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 11:49:38 +0100 Subject: [PATCH 0679/4969] Bump aws-java-sdk-sqs from 1.11.775 to 1.11.777 in /modules/localstack (#2675) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 89e204515c5..d2e3a1ff2cf 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.775' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.775' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.775' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' testCompile 'software.amazon.awssdk:s3:2.13.9' } From 76ff1118f8caf4dbd0a7c9210d44d0702ce021c0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 14:30:02 +0100 Subject: [PATCH 0680/4969] Bump assertj-core from 3.15.0 to 3.16.0 in /modules/pulsar (#2668) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 4f459d9a97e..ecfa7c5f26a 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,5 +4,5 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.1' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.15.0' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.0' } From 402823c43ce2e2aa576fef11a9803add317c54fd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 14:30:22 +0100 Subject: [PATCH 0681/4969] Bump assertj-core from 3.15.0 to 3.16.0 in /modules/neo4j (#2665) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 1f119ff83bd..77ac94a5e8d 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.15.0' + testCompile 'org.assertj:assertj-core:3.16.0' } From 81483cfc85d8b805b20ca9017394c92ab7d25fed Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 14:30:30 +0100 Subject: [PATCH 0682/4969] Bump assertj-core from 3.15.0 to 3.16.0 in /modules/kafka (#2664) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 355c44eab1a..17d6f4b652d 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.5.0' - testCompile 'org.assertj:assertj-core:3.15.0' + testCompile 'org.assertj:assertj-core:3.16.0' testCompile 'com.google.guava:guava:23.0' } From 89ef00389218a5b89682e2ed01db3cabaca85a16 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 14:31:18 +0100 Subject: [PATCH 0683/4969] Bump aws-java-sdk-logs from 1.11.775 to 1.11.777 in /modules/localstack (#2674) --- modules/localstack/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d2e3a1ff2cf..2aa9150b32b 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,6 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.775' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.775' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.777' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' testCompile 'software.amazon.awssdk:s3:2.13.9' } From bc67cb5d55fbf4595e1d9bd644280e30310a33be Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 14:31:31 +0100 Subject: [PATCH 0684/4969] Bump s3 from 2.13.9 to 2.13.11 in /modules/localstack (#2673) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 2aa9150b32b..9270eb9a3ca 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -8,5 +8,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' - testCompile 'software.amazon.awssdk:s3:2.13.9' + testCompile 'software.amazon.awssdk:s3:2.13.11' } From 342f6aef60a0421495f28ce36dd42268d5553796 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 14:31:43 +0100 Subject: [PATCH 0685/4969] Bump mongo-java-driver from 3.12.3 to 3.12.4 in /core (#2676) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index f74744255f8..e7176938b43 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -157,7 +157,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.3.0' testCompile 'com.rabbitmq:amqp-client:5.9.0' - testCompile 'org.mongodb:mongo-java-driver:3.12.3' + testCompile 'org.mongodb:mongo-java-driver:3.12.4' testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') From 886e4c3239da7b73625cd4b965a0ff5b6b74d6aa Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 15:21:58 +0100 Subject: [PATCH 0686/4969] Bump annotations from 17.0.0 to 19.0.0 in /core (#2358) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index e7176938b43..3f4faf0c709 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -116,7 +116,7 @@ dependencies { compile 'junit:junit:4.12' compile 'org.slf4j:slf4j-api:1.7.30' - compile 'org.jetbrains:annotations:17.0.0' + compile 'org.jetbrains:annotations:19.0.0' compile 'org.apache.commons:commons-compress:1.20' compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') From 83a3c941ce948b5339529dd1b2b9928bee1dee19 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 19:55:23 +0100 Subject: [PATCH 0687/4969] Bump httpclient from 4.5.11 to 4.5.12 in /modules/junit-jupiter (#2409) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index b80f9263e9c..fb5548c320d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,7 +8,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.3' testCompile 'redis.clients:jedis:3.3.0' - testCompile 'org.apache.httpcomponents:httpclient:4.5.11' + testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } From e5489d2dd4136d6bc39ed98e0a7db7c66d0cfcb2 Mon Sep 17 00:00:00 2001 From: Danny George Date: Thu, 7 May 2020 13:22:32 -0600 Subject: [PATCH 0688/4969] RabbitMQ: Support declaring an exchange within a vhost (#2362) --- .../containers/RabbitMQContainer.java | 11 +++++++++++ .../containers/RabbitMQContainerTest.java | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index ede111ed2d8..aba71e25a7e 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -345,6 +345,17 @@ public RabbitMQContainer withExchange(String name, String type) { public RabbitMQContainer withExchange(String name, String type, boolean autoDelete, boolean internal, boolean durable, Map arguments) { values.add(asList("rabbitmqadmin", "declare", "exchange", + "name=" + name, + "type=" + type, + "auto_delete=" + autoDelete, + "internal=" + internal, + "durable=" + durable, + "arguments=" + toJson(arguments))); + return self(); + } + + public RabbitMQContainer withExchange(String vhost, String name, String type, boolean autoDelete, boolean internal, boolean durable, Map arguments) { + values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "exchange", "name=" + name, "type=" + type, "auto_delete=" + autoDelete, diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index 5822e213a82..6f283c7451f 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -19,6 +19,7 @@ import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +import java.util.Collections; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; @@ -91,6 +92,20 @@ public void shouldCreateRabbitMQContainerWithExchange() throws IOException, Inte } } + @Test + public void shouldCreateRabbitMQContainerWithExchangeInVhost() throws IOException, InterruptedException + { + try (RabbitMQContainer container = new RabbitMQContainer()) { + container.withVhost("test-vhost"); + container.withExchange("test-vhost", "test-exchange", "direct", false, false, false, Collections.emptyMap()); + + container.start(); + + assertThat(container.execInContainer("rabbitmqctl", "list_exchanges", "-p", "test-vhost").getStdout()) + .containsPattern("test-exchange\\s+direct"); + } + } + @Test public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException { From c88d25705942024677533f333a84734557044088 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 7 May 2020 20:23:42 +0100 Subject: [PATCH 0689/4969] Bump okhttp from 3.14.6 to 3.14.8 in /core (#2644) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 3f4faf0c709..312298bf77d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -146,7 +146,7 @@ dependencies { shaded "org.yaml:snakeyaml:1.25" - shaded 'com.squareup.okhttp3:okhttp:3.14.6' + shaded 'com.squareup.okhttp3:okhttp:3.14.8' shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From 6263cad11a6e8e466ebf12f11173238ac2915052 Mon Sep 17 00:00:00 2001 From: streppel Date: Thu, 7 May 2020 16:32:06 -0300 Subject: [PATCH 0690/4969] Remove duplicate debug log message at container start (#2522) --- .../java/org/testcontainers/containers/GenericContainer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 211ad2f59cb..23e5f9bf173 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -307,7 +307,6 @@ protected void doStart() { Instant startedAt = Instant.now(); logger().debug("Starting container: {}", getDockerImageName()); - logger().debug("Trying to start container: {}", getDockerImageName()); AtomicInteger attempt = new AtomicInteger(0); Unreliables.retryUntilSuccess(startupAttempts, () -> { From 0df9f87b9af0ec58dbe04930416799ac58f562af Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 8 May 2020 08:41:41 +0100 Subject: [PATCH 0691/4969] Bump aws-java-sdk-s3 from 1.11.775 to 1.11.778 in /modules/localstack (#2682) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9270eb9a3ca..31ce7af53b7 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.775' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.778' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.775' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' From 05da884d1beef61fa8b743b798ea988f3cb0dc5d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 8 May 2020 08:41:51 +0100 Subject: [PATCH 0692/4969] Bump HikariCP from 3.4.3 to 3.4.4 in /modules/spock (#2678) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 7b1780391b5..8ea7a940212 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.3' + testCompile 'com.zaxxer:HikariCP:3.4.4' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testRuntime 'org.postgresql:postgresql:42.2.12' From 8f5863b4b8245af3e9dddb3d70c1ff7e1dace152 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 8 May 2020 08:41:58 +0100 Subject: [PATCH 0693/4969] Bump org.springframework.boot from 2.2.6.RELEASE to 2.2.7.RELEASE in /examples (#2683) --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index edbe7d1fb68..04888a55c65 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.6.RELEASE' + id 'org.springframework.boot' version '2.2.7.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 6cd1db0172a..c7b0c63d7ba 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.6.RELEASE' + id 'org.springframework.boot' version '2.2.7.RELEASE' } apply plugin: 'io.spring.dependency-management' From d1ae700f18cf37e9954c2b9c75e30072b55ce2d5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 8 May 2020 08:42:05 +0100 Subject: [PATCH 0694/4969] Bump s3 from 2.13.11 to 2.13.12 in /modules/localstack (#2681) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 31ce7af53b7..25365a3f8a3 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -8,5 +8,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' - testCompile 'software.amazon.awssdk:s3:2.13.11' + testCompile 'software.amazon.awssdk:s3:2.13.12' } From d3d168a3885947f58c13d6e0f9a4cf5500b96794 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 8 May 2020 08:42:12 +0100 Subject: [PATCH 0695/4969] Bump aws-java-sdk-sqs from 1.11.777 to 1.11.778 in /modules/localstack (#2680) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 25365a3f8a3..874e5fe54df 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.778' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.775' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.777' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.778' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' testCompile 'software.amazon.awssdk:s3:2.13.12' From 69b3bc2359dd01e025ec618a4e4ba1ec5b8fb1c2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 8 May 2020 08:42:19 +0100 Subject: [PATCH 0696/4969] Bump HikariCP from 3.4.3 to 3.4.4 in /modules/junit-jupiter (#2679) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index fb5548c320d..93b9b1dc23e 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.3' + testCompile 'com.zaxxer:HikariCP:3.4.4' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testCompile ('org.mockito:mockito-core:3.3.3') { From a2cfd4502d272d1116d42e5c7339a5320a401a43 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 8 May 2020 12:51:53 +0100 Subject: [PATCH 0697/4969] Revert "Bump HikariCP from 3.4.3 to 3.4.4 in /modules/spock" (#2686) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 8ea7a940212..7b1780391b5 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.4' + testCompile 'com.zaxxer:HikariCP:3.4.3' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testRuntime 'org.postgresql:postgresql:42.2.12' From 9b12c6403eecf6ebeaa412d85c8a8aaa7ad7de49 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 8 May 2020 12:52:05 +0100 Subject: [PATCH 0698/4969] Revert "Bump HikariCP from 3.4.3 to 3.4.4 in /modules/junit-jupiter" (#2685) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 93b9b1dc23e..fb5548c320d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.4' + testCompile 'com.zaxxer:HikariCP:3.4.3' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testCompile ('org.mockito:mockito-core:3.3.3') { From 8377288a10a892d8ed830b59b860eb3e40a72491 Mon Sep 17 00:00:00 2001 From: silaev Date: Fri, 8 May 2020 17:02:29 +0500 Subject: [PATCH 0699/4969] Add MongoDB module (#1961) --- docs/modules/databases/mongodb.md | 60 +++++++++ mkdocs.yml | 1 + modules/mongodb/build.gradle | 7 + .../containers/MongoDBContainer.java | 120 ++++++++++++++++++ .../containers/MongoDBContainerTest.java | 74 +++++++++++ .../src/test/resources/logback-test.xml | 16 +++ 6 files changed, 278 insertions(+) create mode 100644 docs/modules/databases/mongodb.md create mode 100644 modules/mongodb/build.gradle create mode 100644 modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java create mode 100644 modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java create mode 100644 modules/mongodb/src/test/resources/logback-test.xml diff --git a/docs/modules/databases/mongodb.md b/docs/modules/databases/mongodb.md new file mode 100644 index 00000000000..fc2cb873f59 --- /dev/null +++ b/docs/modules/databases/mongodb.md @@ -0,0 +1,60 @@ +# MongoDB Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +## Usage example + +The following example shows how to create a MongoDBContainer: + + +[Creating a MongoDB container](../../../modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java) inside_block:creatingMongoDBContainer + + +And how to start it: + + +[Starting a MongoDB container](../../../modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java) inside_block:startingMongoDBContainer + + +!!! note + To construct a multi-node MongoDB cluster, consider the [mongodb-replica-set project](https://github.com/silaev/mongodb-replica-set/) + +#### Motivation +Implement a reusable, cross-platform, simple to install solution that doesn't depend on +fixed ports to test MongoDB transactions. + +#### General info +MongoDB starting from version 4 supports multi-document transactions only for a replica set. +For instance, to initialize a single node replica set on fixed ports via Docker, one has to do the following: + +* Run a MongoDB container of version 4 and up specifying --replSet command +* Initialize a single replica set via executing a proper command +* Wait for the initialization to complete +* Provide a special url for a user to employ with a MongoDB driver without specifying replicaSet + +As we can see, there is a lot of operations to execute and we even haven't touched a non-fixed port approach. +That's where the MongoDBContainer might come in handy. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:mongodb:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + mongodb + {{latest_version}} + test + +``` + +!!! hint +Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency + +#### Copyright +Copyright (c) 2019 Konstantin Silaev diff --git a/mkdocs.yml b/mkdocs.yml index 708fbe06883..e1b21d80811 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -50,6 +50,7 @@ nav: - modules/databases/dynalite.md - modules/databases/influxdb.md - modules/databases/mariadb.md + - modules/databases/mongodb.md - modules/databases/mssqlserver.md - modules/databases/mysql.md - modules/databases/neo4j.md diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle new file mode 100644 index 00000000000..57db1be21de --- /dev/null +++ b/modules/mongodb/build.gradle @@ -0,0 +1,7 @@ +description = "Testcontainers :: MongoDB" + +dependencies { + compile project(':testcontainers') + + testCompile("org.mongodb:mongodb-driver-sync:4.0.2") +} diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java new file mode 100644 index 00000000000..a7f57d310f2 --- /dev/null +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -0,0 +1,120 @@ +package org.testcontainers.containers; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import lombok.NonNull; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.containers.wait.strategy.Wait; + +import java.io.IOException; + +/** + * Constructs a single node MongoDB replica set for testing transactions. + *

To construct a multi-node MongoDB cluster, consider the mongodb-replica-set project on GitHub + *

Tested on a MongoDB version 4.0.10+ (that is the default version if not specified). + */ +@Slf4j +public class MongoDBContainer extends GenericContainer { + private static final int CONTAINER_EXIT_CODE_OK = 0; + private static final int MONGODB_INTERNAL_PORT = 27017; + private static final int AWAIT_INIT_REPLICA_SET_ATTEMPTS = 60; + private static final String MONGODB_VERSION_DEFAULT = "4.0.10"; + private static final String MONGODB_DATABASE_NAME_DEFAULT = "test"; + + public MongoDBContainer() { + this("mongo:" + MONGODB_VERSION_DEFAULT); + } + + public MongoDBContainer(@NonNull final String dockerImageName) { + super(dockerImageName); + withExposedPorts(MONGODB_INTERNAL_PORT); + withCommand("--replSet", "docker-rs"); + waitingFor( + Wait.forLogMessage(".*waiting for connections on port.*", 1) + ); + } + + public String getReplicaSetUrl() { + if (!isRunning()) { + throw new IllegalStateException("MongoDBContainer should be started first"); + } + return String.format( + "mongodb://%s:%d/%s", + getContainerIpAddress(), + getMappedPort(MONGODB_INTERNAL_PORT), + MONGODB_DATABASE_NAME_DEFAULT + ); + } + + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + initReplicaSet(); + } + + private String[] buildMongoEvalCommand(final String command) { + return new String[]{"mongo", "--eval", command}; + } + + private void checkMongoNodeExitCode(final Container.ExecResult execResult) { + if (execResult.getExitCode() != CONTAINER_EXIT_CODE_OK) { + final String errorMessage = String.format("An error occurred: %s", execResult.getStdout()); + log.error(errorMessage); + throw new ReplicaSetInitializationException(errorMessage); + } + } + + private String buildMongoWaitCommand() { + return String.format( + "var attempt = 0; " + + "while" + + "(%s) " + + "{ " + + "if (attempt > %d) {quit(1);} " + + "print('%s ' + attempt); sleep(100); attempt++; " + + " }", + "db.runCommand( { isMaster: 1 } ).ismaster==false", + AWAIT_INIT_REPLICA_SET_ATTEMPTS, + "An attempt to await for a single node replica set initialization:" + ); + } + + private void checkMongoNodeExitCodeAfterWaiting( + final Container.ExecResult execResultWaitForMaster + ) { + if (execResultWaitForMaster.getExitCode() != CONTAINER_EXIT_CODE_OK) { + final String errorMessage = String.format( + "A single node replica set was not initialized in a set timeout: %d attempts", + AWAIT_INIT_REPLICA_SET_ATTEMPTS + ); + log.error(errorMessage); + throw new ReplicaSetInitializationException(errorMessage); + } + } + + @SneakyThrows(value = {IOException.class, InterruptedException.class}) + private void initReplicaSet() { + log.debug("Initializing a single node node replica set..."); + final ExecResult execResultInitRs = execInContainer( + buildMongoEvalCommand("rs.initiate();") + ); + log.debug(execResultInitRs.getStdout()); + checkMongoNodeExitCode(execResultInitRs); + + log.debug( + "Awaiting for a single node replica set initialization up to {} attempts", + AWAIT_INIT_REPLICA_SET_ATTEMPTS + ); + final ExecResult execResultWaitForMaster = execInContainer( + buildMongoEvalCommand(buildMongoWaitCommand()) + ); + log.debug(execResultWaitForMaster.getStdout()); + + checkMongoNodeExitCodeAfterWaiting(execResultWaitForMaster); + } + + public static class ReplicaSetInitializationException extends RuntimeException { + ReplicaSetInitializationException(final String errorMessage) { + super(errorMessage); + } + } +} diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java new file mode 100644 index 00000000000..7c4f4c12408 --- /dev/null +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -0,0 +1,74 @@ +package org.testcontainers.containers; + +import com.mongodb.ReadConcern; +import com.mongodb.ReadPreference; +import com.mongodb.TransactionOptions; +import com.mongodb.WriteConcern; +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.TransactionBody; +import org.bson.Document; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + + +public class MongoDBContainerTest { + /** + * Taken from https://docs.mongodb.com + */ + @Test + public void shouldExecuteTransactions() { + try ( + // creatingMongoDBContainer { + final MongoDBContainer mongoDBContainer = new MongoDBContainer() + // } + ) { + + // startingMongoDBContainer { + mongoDBContainer.start(); + // } + + final String mongoRsUrl = mongoDBContainer.getReplicaSetUrl(); + assertNotNull(mongoRsUrl); + final MongoClient mongoSyncClient = MongoClients.create(mongoRsUrl); + mongoSyncClient.getDatabase("mydb1").getCollection("foo") + .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0)); + mongoSyncClient.getDatabase("mydb2").getCollection("bar") + .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0)); + + final ClientSession clientSession = mongoSyncClient.startSession(); + final TransactionOptions txnOptions = TransactionOptions.builder() + .readPreference(ReadPreference.primary()) + .readConcern(ReadConcern.LOCAL) + .writeConcern(WriteConcern.MAJORITY) + .build(); + + final String trxResult = "Inserted into collections in different databases"; + + TransactionBody txnBody = () -> { + final MongoCollection coll1 = + mongoSyncClient.getDatabase("mydb1").getCollection("foo"); + final MongoCollection coll2 = + mongoSyncClient.getDatabase("mydb2").getCollection("bar"); + + coll1.insertOne(clientSession, new Document("abc", 1)); + coll2.insertOne(clientSession, new Document("xyz", 999)); + return trxResult; + }; + + try { + final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions); + assertEquals(trxResult, trxResultActual); + } catch (RuntimeException re) { + throw new IllegalStateException(re.getMessage(), re); + } finally { + clientSession.close(); + mongoSyncClient.close(); + } + } + } +} diff --git a/modules/mongodb/src/test/resources/logback-test.xml b/modules/mongodb/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/mongodb/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From e6930d6ac986db1373e29b61263f61aecbfc5155 Mon Sep 17 00:00:00 2001 From: Vivek Jaiswal Date: Wed, 13 May 2020 22:50:49 +0530 Subject: [PATCH 0700/4969] Fix typo in DinD docs (#2725) --- .../continuous_integration/dind_patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/continuous_integration/dind_patterns.md b/docs/supported_docker_environment/continuous_integration/dind_patterns.md index 1534949e1bd..e742c047afa 100644 --- a/docs/supported_docker_environment/continuous_integration/dind_patterns.md +++ b/docs/supported_docker_environment/continuous_integration/dind_patterns.md @@ -32,7 +32,7 @@ Where: * `-v /var/run/docker.sock:/var/run/docker.sock` will map the Docker socket ### Docker Compose example -The same can be achived with Docker Compose: +The same can be achieved with Docker Compose: ```yaml tests: image: maven:3 From 123f13aeec72b9c7998b8b5fa32aa1de57c3b31e Mon Sep 17 00:00:00 2001 From: Perennes Date: Wed, 13 May 2020 21:34:26 +0200 Subject: [PATCH 0701/4969] Do not fail on duplicated local image tags. Fixes #2431 (#2692) * #2431 Correction for an edge case in local image repos (duplicates repo tags) crashing the image pulling * Indentation correction * Indentation correction --- .../org/testcontainers/images/LocalImagesCache.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java index 29bc8ef1408..e6b330d4c90 100644 --- a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java +++ b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java @@ -79,10 +79,14 @@ private void populateFromList(List images) { } cache.putAll( - Stream.of(repoTags).collect(Collectors.toMap( - DockerImageName::new, - it -> ImageData.from(image) - )) + Stream.of(repoTags) + // Protection against some edge case where local image repository tags end up with duplicates + // making toMap crash at merge time. + .distinct() + .collect(Collectors.toMap( + DockerImageName::new, + it -> ImageData.from(image) + )) ); } } From 284c272cbf5095fd586ffebfd7d7ec6e7f634f84 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:25:00 +0100 Subject: [PATCH 0702/4969] Bump HikariCP from 3.4.3 to 3.4.5 in /modules/junit-jupiter (#2697) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index fb5548c320d..5e143b3b706 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.3' + testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testCompile ('org.mockito:mockito-core:3.3.3') { From d2b677856aa41940a106f2a9da9c15370cfb8077 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:25:19 +0100 Subject: [PATCH 0703/4969] Bump tomcat-jdbc from 9.0.34 to 9.0.35 in /modules/mariadb (#2712) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 730dae7c794..226e34aae90 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.34' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.35' testCompile 'org.vibur:vibur-dbcp:25.0' testCompile testFixtures(project(':r2dbc')) From df6816940a2970a0577933e6b9bd88719984ea30 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:25:36 +0100 Subject: [PATCH 0704/4969] Bump assertj-core from 3.16.0 to 3.16.1 in /modules/neo4j (#2698) --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 77ac94a5e8d..4bc92e49cda 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.16.0' + testCompile 'org.assertj:assertj-core:3.16.1' } From 1a754757ebc0d580e04a2ffdc504ed53a2a1e953 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:25:41 +0100 Subject: [PATCH 0705/4969] Bump assertj-core from 3.16.0 to 3.16.1 in /modules/junit-jupiter (#2700) --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5e143b3b706..485e02f6089 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.16.0' + testCompile 'org.assertj:assertj-core:3.16.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' testRuntime 'org.postgresql:postgresql:42.2.12' From f60160993117e83eae612d3614a4bdb7fc5fda37 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:25:56 +0100 Subject: [PATCH 0706/4969] Bump assertj-core from 3.16.0 to 3.16.1 in /modules/kafka (#2709) --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 17d6f4b652d..06090c5b35e 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.5.0' - testCompile 'org.assertj:assertj-core:3.16.0' + testCompile 'org.assertj:assertj-core:3.16.1' testCompile 'com.google.guava:guava:23.0' } From 948e58dca8ab80e60251f2e7065fc2e3d05a4513 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:26:11 +0100 Subject: [PATCH 0707/4969] Bump HikariCP from 3.4.3 to 3.4.5 in /modules/spock (#2699) --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 7b1780391b5..fea1c8baa2d 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.3' + testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testRuntime 'org.postgresql:postgresql:42.2.12' From 7b3a45d1b2f607ba921f3523a9a0e1745768509d Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 14 May 2020 10:24:13 +0100 Subject: [PATCH 0708/4969] Reduce dependabot bump frequency --- .dependabot/config.yml | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.dependabot/config.yml b/.dependabot/config.yml index 7fe8921a36b..bf80d72ab92 100644 --- a/.dependabot/config.yml +++ b/.dependabot/config.yml @@ -3,150 +3,150 @@ version: 1 update_configs: - package_manager: "java:gradle" directory: "/core" - update_schedule: "daily" + update_schedule: "weekly" # Explicit entry for each module - package_manager: "java:gradle" directory: "/modules/cassandra" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/clickhouse" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/couchbase" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/database-commons" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/dynalite" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/elasticsearch" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/influxdb" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/jdbc" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/jdbc-test" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/junit-jupiter" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/kafka" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/localstack" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/mariadb" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/mockserver" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/mssqlserver" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/mysql" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/neo4j" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/nginx" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/oracle-xe" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/postgresql" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/pulsar" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/selenium" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/spock" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } - package_manager: "java:gradle" directory: "/modules/vault" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } @@ -154,7 +154,7 @@ update_configs: # Examples - package_manager: "java:gradle" directory: "/examples" - update_schedule: "daily" + update_schedule: "weekly" automerged_updates: - match: { dependency_type: "development", update_type: "semver:minor" } - match: { dependency_type: "production", update_type: "semver:minor" } From 64fc34a10e0bab2b1675b3878e52be72d6c65451 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:26:39 +0100 Subject: [PATCH 0709/4969] Bump assertj-core from 3.16.0 to 3.16.1 in /modules/pulsar (#2696) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index ecfa7c5f26a..74626006ba0 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,5 +4,5 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.1' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.0' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.1' } From 279b5b25438e07856d437d4650cc0ec37b8b72de Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:26:45 +0100 Subject: [PATCH 0710/4969] Bump assertj-core from 3.16.0 to 3.16.1 in /modules/vault (#2695) --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index b8681be150d..2b9f702f9d9 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.0' - testCompile 'org.assertj:assertj-core:3.16.0' + testCompile 'org.assertj:assertj-core:3.16.1' } From 82be21d7272f4e25adbd14db281f5a63e5c35489 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:27:12 +0100 Subject: [PATCH 0711/4969] Bump assertj-core from 3.16.0 to 3.16.1 in /modules/database-commons (#2703) --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 14dffc649ac..82e318e5017 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.16.0' + testCompile 'org.assertj:assertj-core:3.16.1' } From 024d33261ed4c4337b4b6319a991d59e2401140f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:27:25 +0100 Subject: [PATCH 0712/4969] Bump s3 from 2.13.12 to 2.13.16 in /modules/localstack (#2729) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 874e5fe54df..566eb403468 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -8,5 +8,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.778' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' - testCompile 'software.amazon.awssdk:s3:2.13.12' + testCompile 'software.amazon.awssdk:s3:2.13.16' } From 1cefa4b9255d13a0ef20c1cec96d127e3b8d7dcd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:27:37 +0100 Subject: [PATCH 0713/4969] Bump aws-java-sdk-sqs from 1.11.778 to 1.11.782 in /modules/localstack (#2732) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 566eb403468..44b732d4c60 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.778' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.775' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.778' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' testCompile 'software.amazon.awssdk:s3:2.13.16' From 1a9e55457ab0f9b8ec5b5b3f8b27428d307118ac Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:29:43 +0100 Subject: [PATCH 0714/4969] Bump auto-service from 1.0-rc6 to 1.0-rc7 in /modules/mssqlserver (#2734) --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 4a496e9eb35..055548d4182 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: MS SQL Server" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' compileOnly 'com.google.auto.service:auto-service:1.0-rc6' compile project(':jdbc') From 4ef332644a08ee57b3e01c57d275da3a33cec31b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:30:07 +0100 Subject: [PATCH 0715/4969] Bump auto-service from 1.0-rc6 to 1.0-rc7 in /modules/postgresql (#2735) --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 9893ec28bd1..8c07465d424 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' compileOnly 'com.google.auto.service:auto-service:1.0-rc6' compile project(':jdbc') From c40d56e4d44cfe4f5d0e0487a2f4b4627d9f6454 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:30:16 +0100 Subject: [PATCH 0716/4969] Bump auto-service from 1.0-rc6 to 1.0-rc7 in /modules/mysql (#2736) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 2ee2d62ce59..d41609ac6aa 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' compileOnly 'com.google.auto.service:auto-service:1.0-rc6' compile project(':jdbc') From 44ab8134b286febe8a40f979372b550fd40dd9d1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:30:31 +0100 Subject: [PATCH 0717/4969] Bump auto-service from 1.0-rc6 to 1.0-rc7 in /modules/mariadb (#2739) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 226e34aae90..fe8788cb06b 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' compileOnly 'com.google.auto.service:auto-service:1.0-rc6' compile project(':jdbc') From 3f7c0ed2916cc103051fdcb713d1dabf96da3a16 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:32:40 +0100 Subject: [PATCH 0718/4969] Bump java-client from 2.7.14 to 2.7.15 in /modules/couchbase (#2701) --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 9dd0856fd51..9cb778fd479 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Couchbase" dependencies { compile project(':testcontainers') - testCompile 'com.couchbase.client:java-client:2.7.14' + testCompile 'com.couchbase.client:java-client:2.7.15' } From c4e2e3184afdef0b265e16498b83c520a1cfb31a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:33:06 +0100 Subject: [PATCH 0719/4969] Bump tomcat-jdbc from 9.0.34 to 9.0.35 in /modules/mysql (#2713) --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index d41609ac6aa..04648e35f94 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.20' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.34' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.35' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' From e508b542f6d54adad17bf104ac0e34afd8ccc7f3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 10:33:40 +0100 Subject: [PATCH 0720/4969] Bump transport from 6.7.1 to 7.7.0 in /modules/elasticsearch (#2737) --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 6deaf802112..959d17e3d02 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.2" - testCompile "org.elasticsearch.client:transport:6.7.1" + testCompile "org.elasticsearch.client:transport:7.7.0" } From 79d89ce75c300d26904a75f84430a118ab36d69b Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 14 May 2020 10:42:33 +0100 Subject: [PATCH 0721/4969] Revert "Bump transport from 6.7.1 to 7.7.0 in /modules/elasticsearch" (#2740) --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 959d17e3d02..6deaf802112 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.2" - testCompile "org.elasticsearch.client:transport:7.7.0" + testCompile "org.elasticsearch.client:transport:6.7.1" } From 2f8bbdd57287bcf0409b02cf85f0343a05f52e68 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 11:05:41 +0100 Subject: [PATCH 0722/4969] Bump assertj-core from 3.16.0 to 3.16.1 in /core (#2706) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 312298bf77d..4c62a2416ef 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -165,7 +165,7 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.16.0' + testCompile 'org.assertj:assertj-core:3.16.1' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" From c18a203e3bf06872c0f73a2743bb2c4da0a72023 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 14 May 2020 11:37:08 +0100 Subject: [PATCH 0723/4969] Split JDBC tests (#2556) --- modules/clickhouse/build.gradle | 3 + .../clickhouse/ClickhouseJDBCDriverTest.java | 21 ++++ .../clickhouse/SimpleClickhouseTest.java | 25 +++++ modules/cockroachdb/build.gradle | 3 + .../CockroachDBJDBCDriverTest.java | 21 ++++ .../cockroachdb}/SimpleCockroachDBTest.java | 3 +- .../resources/somepath/init_postgresql.sql | 0 modules/db2/build.gradle | 3 + .../jdbc/db2/DB2JDBCDriverTest.java | 21 ++++ .../junit/db2/SimpleDb2Test.java | 27 ++++++ .../container-license-acceptance.txt | 1 + modules/jdbc-test/build.gradle | 46 ++++----- .../db}/AbstractContainerDatabaseTest.java | 23 +---- .../jdbc/AbstractJDBCDriverTest.java} | 42 +------- .../{test => main}/resources/logback-test.xml | 0 .../junit/CustomizableMSSQLServerTest.java | 44 --------- .../junit/CustomizableMysqlTest.java | 47 --------- .../junit/CustomizablePostgreSQLTest.java | 48 ---------- .../junit/EmptyPasswordMysqlTest.java | 46 --------- .../junit/SimpleClickhouseTest.java | 25 ----- .../testcontainers/junit/SimpleDb2Test.java | 41 -------- .../junit/SimpleMSSQLServerTest.java | 47 --------- .../container-license-acceptance.txt | 2 - modules/jdbc/build.gradle | 7 ++ .../jupiter/inheritance/InheritedTests.java | 1 - modules/mariadb/build.gradle | 5 +- .../jdbc/mariadb/MariaDBJDBCDriverTest.java | 29 ++++++ .../junit/mariadb}/SimpleMariaDBTest.java | 42 +++----- .../test/resources/somepath/init_mariadb.sql | 0 .../somepath/init_unicode_mariadb.sql} | 0 .../somepath/mariadb_conf_override/my.cnf | 0 modules/mssqlserver/build.gradle | 3 + .../MSSQLServerJDBCDriverTest.java | 21 ++++ .../CustomPasswordMSSQLServerTest.java | 4 +- .../CustomizableMSSQLServerTest.java | 28 ++++++ .../mssqlserver/SimpleMSSQLServerTest.java | 47 +++++++++ modules/mysql/build.gradle | 5 +- modules/mysql/sql/init_mysql.sql | 5 + .../jdbc/mysql}/JDBCDriverWithPoolTest.java | 36 ++++--- .../jdbc/mysql/MySQLJDBCDriverTest.java | 30 ++++++ .../junit/mysql/CustomizableMysqlTest.java | 34 +++++++ .../junit/mysql}/MultiVersionMySQLTest.java | 9 +- .../junit/mysql}/SimpleMySQLTest.java | 96 ++++++++++--------- .../test/resources/somepath/init_mysql.sql | 0 .../resources/somepath/init_unicode_mysql.sql | 5 + .../somepath/mysql_conf_override/my.cnf | 0 modules/oracle-xe/build.gradle | 3 +- .../{ => jdbc}/OracleJDBCDriverTest.java | 2 +- .../junit/oracle}/SimpleOracleTest.java | 19 ++-- modules/postgresql/build.gradle | 5 +- .../PostgreSQLConnectionURLTest.java | 10 +- .../jdbc/DatabaseDriverShutdownTest.java | 5 +- .../jdbc/DatabaseDriverTmpfsTest.java | 6 ++ .../jdbc/postgis/PostgisJDBCDriverTest.java | 22 +++++ .../postgresql/PostgreSQLJDBCDriverTest.java | 21 ++++ .../CustomizablePostgreSQLTest.java | 35 +++++++ .../postgresql}/SimplePostgreSQLTest.java | 11 ++- .../resources/somepath/init_postgresql.sql | 5 + modules/presto/build.gradle | 4 +- .../jdbc/presto/PrestoJDBCDriverTest.java | 21 ++++ test-support/build.gradle | 2 +- 61 files changed, 596 insertions(+), 521 deletions(-) create mode 100644 modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java create mode 100644 modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java create mode 100644 modules/cockroachdb/src/test/java/org/testcontainers/jdbc/cockroachdb/CockroachDBJDBCDriverTest.java rename modules/{jdbc-test/src/test/java/org/testcontainers/junit => cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb}/SimpleCockroachDBTest.java (93%) rename modules/{jdbc-test => cockroachdb}/src/test/resources/somepath/init_postgresql.sql (100%) create mode 100644 modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java create mode 100644 modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java create mode 100644 modules/db2/src/test/resources/container-license-acceptance.txt rename modules/jdbc-test/src/{test/java/org/testcontainers/junit => main/java/org/testcontainers/db}/AbstractContainerDatabaseTest.java (55%) rename modules/jdbc-test/src/{test/java/org/testcontainers/jdbc/JDBCDriverTest.java => main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java} (63%) rename modules/jdbc-test/src/{test => main}/resources/logback-test.xml (100%) delete mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMSSQLServerTest.java delete mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMysqlTest.java delete mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizablePostgreSQLTest.java delete mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/EmptyPasswordMysqlTest.java delete mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java delete mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java delete mode 100644 modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java delete mode 100644 modules/jdbc-test/src/test/resources/container-license-acceptance.txt create mode 100644 modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java rename modules/{jdbc-test/src/test/java/org/testcontainers/junit => mariadb/src/test/java/org/testcontainers/junit/mariadb}/SimpleMariaDBTest.java (70%) rename modules/{jdbc-test => mariadb}/src/test/resources/somepath/init_mariadb.sql (100%) rename modules/{jdbc-test/src/test/resources/somepath/init_unicode_mysql.sql => mariadb/src/test/resources/somepath/init_unicode_mariadb.sql} (100%) rename modules/{jdbc-test => mariadb}/src/test/resources/somepath/mariadb_conf_override/my.cnf (100%) create mode 100644 modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java rename modules/{jdbc-test/src/test/java/org/testcontainers/junit => mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver}/CustomPasswordMSSQLServerTest.java (95%) create mode 100644 modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java create mode 100644 modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java create mode 100644 modules/mysql/sql/init_mysql.sql rename modules/{jdbc-test/src/test/java/org/testcontainers/jdbc => mysql/src/test/java/org/testcontainers/jdbc/mysql}/JDBCDriverWithPoolTest.java (78%) create mode 100644 modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java create mode 100644 modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java rename modules/{jdbc-test/src/test/java/org/testcontainers/junit => mysql/src/test/java/org/testcontainers/junit/mysql}/MultiVersionMySQLTest.java (76%) rename modules/{jdbc-test/src/test/java/org/testcontainers/junit => mysql/src/test/java/org/testcontainers/junit/mysql}/SimpleMySQLTest.java (58%) rename modules/{jdbc-test => mysql}/src/test/resources/somepath/init_mysql.sql (100%) create mode 100644 modules/mysql/src/test/resources/somepath/init_unicode_mysql.sql rename modules/{jdbc-test => mysql}/src/test/resources/somepath/mysql_conf_override/my.cnf (100%) rename modules/oracle-xe/src/test/java/org/testcontainers/containers/{ => jdbc}/OracleJDBCDriverTest.java (97%) rename modules/{jdbc-test/src/test/java/org/testcontainers/junit => oracle-xe/src/test/java/org/testcontainers/junit/oracle}/SimpleOracleTest.java (50%) rename modules/{jdbc-test => postgresql}/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java (76%) rename modules/{jdbc-test => postgresql}/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java (71%) create mode 100644 modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java create mode 100644 modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java create mode 100644 modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java rename modules/{jdbc-test/src/test/java/org/testcontainers/junit => postgresql/src/test/java/org/testcontainers/junit/postgresql}/SimplePostgreSQLTest.java (78%) create mode 100644 modules/postgresql/src/test/resources/somepath/init_postgresql.sql create mode 100644 modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java diff --git a/modules/clickhouse/build.gradle b/modules/clickhouse/build.gradle index 4f0e1a1fd90..323475b1d1c 100644 --- a/modules/clickhouse/build.gradle +++ b/modules/clickhouse/build.gradle @@ -3,4 +3,7 @@ description = "Testcontainers :: JDBC :: ClickHouse" dependencies { compile project(':testcontainers') compile project(':jdbc') + + testCompile project(':jdbc-test') + testCompile 'ru.yandex.clickhouse:clickhouse-jdbc:0.2.4' } diff --git a/modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java b/modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java new file mode 100644 index 00000000000..f3946c8a317 --- /dev/null +++ b/modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.jdbc.clickhouse; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class ClickhouseJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken)}, + }); + } +} diff --git a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java new file mode 100644 index 00000000000..2dbce0b3593 --- /dev/null +++ b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java @@ -0,0 +1,25 @@ +package org.testcontainers.junit.clickhouse; + +import org.junit.Test; +import org.testcontainers.containers.ClickHouseContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class SimpleClickhouseTest extends AbstractContainerDatabaseTest { + + @Test + public void testSimple() throws SQLException { + try (ClickHouseContainer clickhouse = new ClickHouseContainer()) { + clickhouse.start(); + + ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); + + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } +} diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index e52f9f3729c..a3927258679 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -2,4 +2,7 @@ description = "Testcontainers :: JDBC :: CockroachDB" dependencies { compile project(':jdbc') + + testCompile project(':jdbc-test') + testCompile 'org.postgresql:postgresql:42.2.12' } diff --git a/modules/cockroachdb/src/test/java/org/testcontainers/jdbc/cockroachdb/CockroachDBJDBCDriverTest.java b/modules/cockroachdb/src/test/java/org/testcontainers/jdbc/cockroachdb/CockroachDBJDBCDriverTest.java new file mode 100644 index 00000000000..75b1fadb47e --- /dev/null +++ b/modules/cockroachdb/src/test/java/org/testcontainers/jdbc/cockroachdb/CockroachDBJDBCDriverTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.jdbc.cockroachdb; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class CockroachDBJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:cockroach://hostname/databasename", EnumSet.noneOf(Options.class)}, + }); + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleCockroachDBTest.java b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java similarity index 93% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleCockroachDBTest.java rename to modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java index c21a5ddfaf1..7c62b2f6bcf 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleCockroachDBTest.java +++ b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java @@ -1,7 +1,8 @@ -package org.testcontainers.junit; +package org.testcontainers.junit.cockroachdb; import org.junit.Test; import org.testcontainers.containers.CockroachContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/modules/jdbc-test/src/test/resources/somepath/init_postgresql.sql b/modules/cockroachdb/src/test/resources/somepath/init_postgresql.sql similarity index 100% rename from modules/jdbc-test/src/test/resources/somepath/init_postgresql.sql rename to modules/cockroachdb/src/test/resources/somepath/init_postgresql.sql diff --git a/modules/db2/build.gradle b/modules/db2/build.gradle index a92631df264..feaf5f790c5 100644 --- a/modules/db2/build.gradle +++ b/modules/db2/build.gradle @@ -2,4 +2,7 @@ description = "Testcontainers :: JDBC :: DB2" dependencies { compile project(':jdbc') + + testCompile project(':jdbc-test') + testCompile 'com.ibm.db2:jcc:11.5.0.0' } diff --git a/modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java b/modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java new file mode 100644 index 00000000000..2c87a4a1a65 --- /dev/null +++ b/modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.jdbc.db2; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class DB2JDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)} + }); + } +} diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java new file mode 100644 index 00000000000..08f427cf12b --- /dev/null +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -0,0 +1,27 @@ +package org.testcontainers.junit.db2; + +import org.junit.Test; +import org.testcontainers.containers.Db2Container; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class SimpleDb2Test extends AbstractContainerDatabaseTest { + + @Test + public void testSimple() throws SQLException { + try (Db2Container db2 = new Db2Container() + .acceptLicense()) { + + db2.start(); + + ResultSet resultSet = performQuery(db2, "SELECT 1 FROM SYSIBM.SYSDUMMY1"); + + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } +} diff --git a/modules/db2/src/test/resources/container-license-acceptance.txt b/modules/db2/src/test/resources/container-license-acceptance.txt new file mode 100644 index 00000000000..c4ad0a38410 --- /dev/null +++ b/modules/db2/src/test/resources/container-license-acceptance.txt @@ -0,0 +1 @@ +ibmcom/db2:11.5.0.0a diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index c7c909782bb..8b36f126b86 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -1,35 +1,21 @@ -repositories { - maven { - url "https://maven.atlassian.com/3rdparty/" - } -} - dependencies { - compile project(':mysql') - compile project(':postgresql') - compile project(':presto') - compile project(':cockroachdb') - compile project(':mariadb') - compile project(':oracle-xe') - compile project(':mssqlserver') - compile project(':clickhouse') - compile project(':db2') + compile project(':jdbc') + compile project(':test-support') - testCompile 'com.google.guava:guava:18.0' - testCompile 'org.postgresql:postgresql:42.0.0' - testCompile 'io.prestosql:presto-jdbc:329' - testCompile 'mysql:mysql-connector-java:8.0.14' - testCompile 'org.mariadb.jdbc:mariadb-java-client:1.4.6' - testCompile 'com.oracle:ojdbc6:12.1.0.1-atlassian-hosted' - testCompile 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8' - testCompile 'ru.yandex.clickhouse:clickhouse-jdbc:0.1.41' - testCompile 'com.ibm.db2:jcc:11.1.4.4' + compile 'com.google.guava:guava:28.2-jre' + compile 'org.apache.commons:commons-lang3:3.10' + compile 'com.zaxxer:HikariCP-java6:2.3.13' + compile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'com.zaxxer:HikariCP-java6:2.3.8' - testCompile 'org.apache.tomcat:tomcat-jdbc:8.5.4' - testCompile 'org.vibur:vibur-dbcp:9.0' - testCompile 'commons-dbutils:commons-dbutils:1.6' + compile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' + + compile('org.rnorth.visible-assertions:visible-assertions:2.1.2') { + // Excluded in favor of jna-platform + exclude(group: "net.java.dev.jna", module: "jna") + } - testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' - testCompile project(':test-support') + compile 'commons-dbutils:commons-dbutils:1.7' + compile 'org.apache.tomcat:tomcat-jdbc:9.0.33' + compile 'org.vibur:vibur-dbcp:25.0' + compile 'mysql:mysql-connector-java:8.0.19' } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java similarity index 55% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java rename to modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java index 7230759382d..8881ed963d8 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java @@ -1,22 +1,17 @@ -package org.testcontainers.junit; +package org.testcontainers.db; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import org.junit.After; import org.testcontainers.containers.JdbcDatabaseContainer; import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.HashSet; -import java.util.Set; -abstract class AbstractContainerDatabaseTest { +public abstract class AbstractContainerDatabaseTest { - private final Set datasourcesForCleanup = new HashSet<>(); - - ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLException { + protected ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLException { DataSource ds = getDataSource(container); Statement statement = ds.getConnection().createStatement(); statement.execute(sql); @@ -26,21 +21,13 @@ ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLEx return resultSet; } - DataSource getDataSource(JdbcDatabaseContainer container) { + protected DataSource getDataSource(JdbcDatabaseContainer container) { HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(container.getJdbcUrl()); hikariConfig.setUsername(container.getUsername()); hikariConfig.setPassword(container.getPassword()); hikariConfig.setDriverClassName(container.getDriverClassName()); - final HikariDataSource dataSource = new HikariDataSource(hikariConfig); - datasourcesForCleanup.add(dataSource); - - return dataSource; - } - - @After - public void teardown() { - datasourcesForCleanup.forEach(HikariDataSource::close); + return new HikariDataSource(hikariConfig); } } diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java similarity index 63% rename from modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java rename to modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java index c96ce251a63..38ca2237567 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java @@ -6,8 +6,6 @@ import org.apache.commons.lang.SystemUtils; import org.junit.AfterClass; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import java.sql.Connection; @@ -16,15 +14,13 @@ import java.sql.Statement; import java.util.EnumSet; -import static java.util.Arrays.asList; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -@RunWith(Parameterized.class) -public class JDBCDriverTest { +public class AbstractJDBCDriverTest { - private enum Options { + protected enum Options { ScriptedSchema, CharacterSet, CustomIniFile, @@ -37,40 +33,6 @@ private enum Options { @Parameter(1) public EnumSet options; - @Parameterized.Parameters(name = "{index} - {0}") - public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:mysql://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - {"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - {"jdbc:tc:postgis:9.6://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - {"jdbc:tc:presto:329://hostname/", EnumSet.of(Options.PmdKnownBroken)}, - {"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)}, - {"jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", EnumSet.of(Options.CustomIniFile)}, - {"jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken)}, - {"jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:cockroach://hostname/databasename", EnumSet.noneOf(Options.class)}, -// {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)} - }); - } - public static void sampleInitFunction(Connection connection) throws SQLException { connection.createStatement().execute("CREATE TABLE bar (\n" + " foo VARCHAR(255)\n" + diff --git a/modules/jdbc-test/src/test/resources/logback-test.xml b/modules/jdbc-test/src/main/resources/logback-test.xml similarity index 100% rename from modules/jdbc-test/src/test/resources/logback-test.xml rename to modules/jdbc-test/src/main/resources/logback-test.xml diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMSSQLServerTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMSSQLServerTest.java deleted file mode 100644 index 2f6e43a771f..00000000000 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMSSQLServerTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.testcontainers.junit; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.MSSQLServerContainer; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.fail; - -public class CustomizableMSSQLServerTest { - - private static final String STRONG_PASSWORD = "myStrong(!)Password"; - - @Rule - public MSSQLServerContainer mssqlServerContainer = new MSSQLServerContainer() - .withPassword(STRONG_PASSWORD); - - @Test - public void testSqlServerConnection() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl("jdbc:sqlserver://localhost:" + - mssqlServerContainer.getMappedPort(MSSQLServerContainer.MS_SQL_SERVER_PORT)); - hikariConfig.setUsername("SA"); - hikariConfig.setPassword(STRONG_PASSWORD); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute(mssqlServerContainer.getTestQueryString()); - ResultSet resultSet = statement.getResultSet(); - if (resultSet.next()) { - int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } else { - fail("No results returned from query"); - } - - } -} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMysqlTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMysqlTest.java deleted file mode 100644 index 11ad8f111ee..00000000000 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizableMysqlTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.testcontainers.junit; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.MySQLContainer; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - -public class CustomizableMysqlTest { - private static final String DB_NAME = "foo"; - private static final String USER = "bar"; - private static final String PWD = "baz"; - - // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - @Rule - public MySQLContainer mysql = (MySQLContainer) new MySQLContainer("mysql:5.5") - .withDatabaseName(DB_NAME) - .withUsername(USER) - .withPassword(PWD) - .withEnv("MYSQL_ROOT_HOST", "%"); - - @Test - public void testSimple() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl("jdbc:mysql://" - + mysql.getContainerIpAddress() - + ":" + mysql.getMappedPort(MySQLContainer.MYSQL_PORT) - + "/" + DB_NAME); - hikariConfig.setUsername(USER); - hikariConfig.setPassword(PWD); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT 1"); - ResultSet resultSet = statement.getResultSet(); - - assertEquals("There is a result", resultSet.next(), true); - int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } -} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizablePostgreSQLTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizablePostgreSQLTest.java deleted file mode 100644 index ef1c7b212db..00000000000 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomizablePostgreSQLTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.testcontainers.junit; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.PostgreSQLContainer; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - -/** - * @author richardnorth - */ -public class CustomizablePostgreSQLTest { - private static final String DB_NAME = "foo"; - private static final String USER = "bar"; - private static final String PWD = "baz"; - - @Rule - public PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:9.6.8") - .withDatabaseName(DB_NAME) - .withUsername(USER) - .withPassword(PWD); - - @Test - public void testSimple() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl("jdbc:postgresql://" - + postgres.getContainerIpAddress() - + ":" + postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT) - + "/" + DB_NAME); - hikariConfig.setUsername(USER); - hikariConfig.setPassword(PWD); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT 1"); - ResultSet resultSet = statement.getResultSet(); - - resultSet.next(); - int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } -} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/EmptyPasswordMysqlTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/EmptyPasswordMysqlTest.java deleted file mode 100644 index 0dfc3149ef5..00000000000 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/EmptyPasswordMysqlTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.testcontainers.junit; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.MySQLContainer; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - -public class EmptyPasswordMysqlTest { - private static final String DB_NAME = "foo"; - private static final String USER = "root"; // MySQL allows empty password with root only - - // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - @Rule - public MySQLContainer mysql = (MySQLContainer) new MySQLContainer("mysql:5.5") - .withDatabaseName(DB_NAME) - .withUsername(USER) - .withPassword("") - .withEnv("MYSQL_ROOT_HOST", "%"); - - @Test - public void testSimple() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl("jdbc:mysql://" - + mysql.getContainerIpAddress() - + ":" + mysql.getMappedPort(MySQLContainer.MYSQL_PORT) - + "/" + DB_NAME); - hikariConfig.setUsername(USER); - hikariConfig.setPassword(""); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT 1"); - ResultSet resultSet = statement.getResultSet(); - - assertEquals("There is a result", resultSet.next(), true); - int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } -} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java deleted file mode 100644 index b765208e212..00000000000 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleClickhouseTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.testcontainers.junit; - -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.ClickHouseContainer; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - -public class SimpleClickhouseTest extends AbstractContainerDatabaseTest { - - @Rule - public ClickHouseContainer clickhouse = new ClickHouseContainer(); - - @Test - public void testSimple() throws SQLException { - ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); - - resultSet.next(); - int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } -} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java deleted file mode 100644 index 60ad9a23a27..00000000000 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleDb2Test.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.testcontainers.junit; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.Db2Container; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - - -@Ignore("Disabled since we had problems with CI disk space filling up from images in jdbc-test module") -public class SimpleDb2Test { - - @Rule - public Db2Container db2 = new Db2Container() - .acceptLicense(); - - @Test - public void testSimple() throws SQLException { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(db2.getJdbcUrl()); - hikariConfig.setUsername(db2.getUsername()); - hikariConfig.setPassword(db2.getPassword()); - - HikariDataSource ds = new HikariDataSource(hikariConfig); - Statement statement = ds.getConnection().createStatement(); - statement.execute("SELECT 1 FROM SYSIBM.SYSDUMMY1"); - ResultSet resultSet = statement.getResultSet(); - - resultSet.next(); - int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } - -} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java deleted file mode 100644 index 2791efa0780..00000000000 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMSSQLServerTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.testcontainers.junit; - -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.MSSQLServerContainer; - -import javax.sql.DataSource; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - -/** - * @author Stefan Hufschmidt - */ -public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { - - @Rule - public MSSQLServerContainer mssqlServer = new MSSQLServerContainer(); - - @Test - public void testSimple() throws SQLException { - ResultSet resultSet = performQuery(mssqlServer, "SELECT 1"); - - int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } - - @Test - public void testSetupDatabase() throws SQLException { - DataSource ds = getDataSource(mssqlServer); - Statement statement = ds.getConnection().createStatement(); - statement.executeUpdate("CREATE DATABASE [test];"); - statement = ds.getConnection().createStatement(); - statement.executeUpdate("CREATE TABLE [test].[dbo].[Foo](ID INT PRIMARY KEY);"); - statement = ds.getConnection().createStatement(); - statement.executeUpdate("INSERT INTO [test].[dbo].[Foo] (ID) VALUES (3);"); - statement = ds.getConnection().createStatement(); - statement.execute("SELECT * FROM [test].[dbo].[Foo];"); - ResultSet resultSet = statement.getResultSet(); - - resultSet.next(); - int resultSetInt = resultSet.getInt("ID"); - assertEquals("A basic SELECT query succeeds", 3, resultSetInt); - } -} diff --git a/modules/jdbc-test/src/test/resources/container-license-acceptance.txt b/modules/jdbc-test/src/test/resources/container-license-acceptance.txt deleted file mode 100644 index 4af979f0f18..00000000000 --- a/modules/jdbc-test/src/test/resources/container-license-acceptance.txt +++ /dev/null @@ -1,2 +0,0 @@ -mcr.microsoft.com/mssql/server:2017-CU12 -ibmcom/db2:11.5.0.0a diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 2278b14006d..aa21939c769 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -2,4 +2,11 @@ description = "Testcontainers :: JDBC" dependencies { compile project(':database-commons') + testCompile project(':test-support') + + testCompile 'commons-dbutils:commons-dbutils:1.7' + testCompile 'org.vibur:vibur-dbcp:25.0' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' + testCompile 'com.zaxxer:HikariCP-java6:2.3.13' + testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java index f050e428692..720c31cf794 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.Test; import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index fe8788cb06b..71f2417f2ad 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -9,11 +9,8 @@ dependencies { compileOnly project(':r2dbc') compileOnly 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' + testCompile project(':jdbc-test') testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' - testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.35' - testCompile 'org.vibur:vibur-dbcp:25.0' testCompile testFixtures(project(':r2dbc')) testCompile 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' diff --git a/modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java b/modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java new file mode 100644 index 00000000000..ef1dfef2703 --- /dev/null +++ b/modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java @@ -0,0 +1,29 @@ +package org.testcontainers.jdbc.mariadb; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class MariaDBJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mariadb:10.2.14://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mariadb.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, + {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", EnumSet.of(Options.CustomIniFile)}, + }); + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java similarity index 70% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMariaDBTest.java rename to modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index 21badefb9fb..646fbb40947 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -1,8 +1,9 @@ -package org.testcontainers.junit; +package org.testcontainers.junit.mariadb; import org.apache.commons.lang.SystemUtils; import org.junit.Test; import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; @@ -12,72 +13,59 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -/** - * @author Miguel Gonzalez Sanchez - */ public class SimpleMariaDBTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - MariaDBContainer mariadb = new MariaDBContainer(); - mariadb.start(); + try (MariaDBContainer mariadb = new MariaDBContainer<>()) { + + mariadb.start(); - try { ResultSet resultSet = performQuery(mariadb, "SELECT 1"); int resultSetInt = resultSet.getInt(1); assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } finally { - mariadb.stop(); } } @Test public void testSpecificVersion() throws SQLException { - MariaDBContainer mariadbOldVersion = new MariaDBContainer("mariadb:5.5.51"); - mariadbOldVersion.start(); + try (MariaDBContainer mariadbOldVersion = new MariaDBContainer<>("mariadb:5.5.51")) { + + mariadbOldVersion.start(); - try { ResultSet resultSet = performQuery(mariadbOldVersion, "SELECT VERSION()"); String resultSetString = resultSet.getString(1); assertTrue("The database version can be set using a container rule parameter", resultSetString.startsWith("5.5.51")); - } finally { - mariadbOldVersion.stop(); } } @Test public void testMariaDBWithCustomIniFile() throws SQLException { assumeFalse(SystemUtils.IS_OS_WINDOWS); - MariaDBContainer mariadbCustomConfig = new MariaDBContainer("mariadb:10.1.16") - .withConfigurationOverride("somepath/mariadb_conf_override"); - mariadbCustomConfig.start(); - try { + try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>("mariadb:10.1.16") + .withConfigurationOverride("somepath/mariadb_conf_override")) { + mariadbCustomConfig.start(); + ResultSet resultSet = performQuery(mariadbCustomConfig, "SELECT @@GLOBAL.innodb_file_format"); String result = resultSet.getString(1); assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result); - } finally { - mariadbCustomConfig.stop(); } } @Test public void testMariaDBWithCommandOverride() throws SQLException { - MariaDBContainer mariadbCustomConfig = (MariaDBContainer) new MariaDBContainer("mariadb:10.1.16") - .withCommand("mysqld --auto_increment_increment=10"); - mariadbCustomConfig.start(); - - try { + try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>("mariadb:10.1.16") + .withCommand("mysqld --auto_increment_increment=10")) { + mariadbCustomConfig.start(); ResultSet resultSet = performQuery(mariadbCustomConfig, "show variables like 'auto_increment_increment'"); String result = resultSet.getString("Value"); assertEquals("Auto increment increment should be overriden by command line", "10", result); - } finally { - mariadbCustomConfig.stop(); } } } diff --git a/modules/jdbc-test/src/test/resources/somepath/init_mariadb.sql b/modules/mariadb/src/test/resources/somepath/init_mariadb.sql similarity index 100% rename from modules/jdbc-test/src/test/resources/somepath/init_mariadb.sql rename to modules/mariadb/src/test/resources/somepath/init_mariadb.sql diff --git a/modules/jdbc-test/src/test/resources/somepath/init_unicode_mysql.sql b/modules/mariadb/src/test/resources/somepath/init_unicode_mariadb.sql similarity index 100% rename from modules/jdbc-test/src/test/resources/somepath/init_unicode_mysql.sql rename to modules/mariadb/src/test/resources/somepath/init_unicode_mariadb.sql diff --git a/modules/jdbc-test/src/test/resources/somepath/mariadb_conf_override/my.cnf b/modules/mariadb/src/test/resources/somepath/mariadb_conf_override/my.cnf similarity index 100% rename from modules/jdbc-test/src/test/resources/somepath/mariadb_conf_override/my.cnf rename to modules/mariadb/src/test/resources/somepath/mariadb_conf_override/my.cnf diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 055548d4182..c21bc43c869 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -9,6 +9,9 @@ dependencies { compileOnly project(':r2dbc') compileOnly 'io.r2dbc:r2dbc-mssql:0.8.2.RELEASE' + testCompile project(':jdbc-test') + testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.2.2.jre8' + testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java new file mode 100644 index 00000000000..00e22199b46 --- /dev/null +++ b/modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.jdbc.mssqlserver; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class MSSQLServerJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", EnumSet.noneOf(Options.class)}, + }); + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomPasswordMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java similarity index 95% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomPasswordMSSQLServerTest.java rename to modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java index 2f77dad44fc..0e1ea05b31d 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/CustomPasswordMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java @@ -1,4 +1,4 @@ -package org.testcontainers.junit; +package org.testcontainers.junit.mssqlserver; import org.apache.commons.lang.RandomStringUtils; import org.junit.Test; @@ -66,7 +66,7 @@ public static Collection data() { @Test public void runPasswordTests() { try { - new MSSQLServerContainer().withPassword(this.password); + new MSSQLServerContainer<>().withPassword(this.password); if (!valid) fail("Password " + this.password + " is not valid. Expected exception"); } catch (IllegalArgumentException e) { diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java new file mode 100644 index 00000000000..ecbc4e31714 --- /dev/null +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java @@ -0,0 +1,28 @@ +package org.testcontainers.junit.mssqlserver; + +import org.junit.Test; +import org.testcontainers.containers.MSSQLServerContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class CustomizableMSSQLServerTest extends AbstractContainerDatabaseTest { + + private static final String STRONG_PASSWORD = "myStrong(!)Password"; + + @Test + public void testSqlServerConnection() throws SQLException { + try (MSSQLServerContainer mssqlServerContainer = new MSSQLServerContainer<>() + .withPassword(STRONG_PASSWORD)) { + + mssqlServerContainer.start(); + + ResultSet resultSet = performQuery(mssqlServerContainer, mssqlServerContainer.getTestQueryString()); + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } +} diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java new file mode 100644 index 00000000000..c1699d2473a --- /dev/null +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -0,0 +1,47 @@ +package org.testcontainers.junit.mssqlserver; + +import org.junit.Test; +import org.testcontainers.containers.MSSQLServerContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { + + @Test + public void testSimple() throws SQLException { + try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>()) { + mssqlServer.start(); + ResultSet resultSet = performQuery(mssqlServer, "SELECT 1"); + + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } + + @Test + public void testSetupDatabase() throws SQLException { + try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>()) { + mssqlServer.start(); + DataSource ds = getDataSource(mssqlServer); + Statement statement = ds.getConnection().createStatement(); + statement.executeUpdate("CREATE DATABASE [test];"); + statement = ds.getConnection().createStatement(); + statement.executeUpdate("CREATE TABLE [test].[dbo].[Foo](ID INT PRIMARY KEY);"); + statement = ds.getConnection().createStatement(); + statement.executeUpdate("INSERT INTO [test].[dbo].[Foo] (ID) VALUES (3);"); + statement = ds.getConnection().createStatement(); + statement.execute("SELECT * FROM [test].[dbo].[Foo];"); + ResultSet resultSet = statement.getResultSet(); + + resultSet.next(); + int resultSetInt = resultSet.getInt("ID"); + assertEquals("A basic SELECT query succeeds", 3, resultSetInt); + } + } +} diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 04648e35f94..c9c165cc874 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -9,11 +9,8 @@ dependencies { compileOnly project(':r2dbc') compileOnly 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' + testCompile project(':jdbc-test') testCompile 'mysql:mysql-connector-java:8.0.20' - testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.35' - testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.vibur:vibur-dbcp:25.0' testCompile testFixtures(project(':r2dbc')) testCompile 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' diff --git a/modules/mysql/sql/init_mysql.sql b/modules/mysql/sql/init_mysql.sql new file mode 100644 index 00000000000..2b00ee968b0 --- /dev/null +++ b/modules/mysql/sql/init_mysql.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + foo VARCHAR(255) +); + +INSERT INTO bar (foo) VALUES ('hello world'); \ No newline at end of file diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverWithPoolTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java similarity index 78% rename from modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverWithPoolTest.java rename to modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java index 53daa1316f5..1ad77264c62 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverWithPoolTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java @@ -1,4 +1,4 @@ -package org.testcontainers.jdbc; +package org.testcontainers.jdbc.mysql; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; @@ -8,6 +8,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.ContainerDatabaseDriver; import org.vibur.dbcp.ViburDBCPDataSource; import javax.sql.DataSource; @@ -22,23 +23,26 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; /** - * + * This test belongs in the jdbc module, as it is focused on testing the behaviour of {@link org.testcontainers.containers.JdbcDatabaseContainer}. + * However, the need to use the {@link org.testcontainers.containers.MySQLContainerProvider} (due to the jdbc:tc:mysql) URL forces it to live here in + * the mysql module, to avoid circular dependencies. + * TODO: Move to the jdbc module and either (a) implement a barebones {@link org.testcontainers.containers.JdbcDatabaseContainerProvider} for testing, or (b) refactor into a unit test. */ @RunWith(Parameterized.class) public class JDBCDriverWithPoolTest { - public static final String URL = "jdbc:tc:mysql:5://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverWithPoolTest::sampleInitFunction"; + public static final String URL = "jdbc:tc:mysql:5://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.mysql.JDBCDriverWithPoolTest::sampleInitFunction"; private final DataSource dataSource; @Parameterized.Parameters public static Iterable> dataSourceSuppliers() { return asList( - JDBCDriverWithPoolTest::getTomcatDataSourceWithDriverClassName, - JDBCDriverWithPoolTest::getTomcatDataSource, - JDBCDriverWithPoolTest::getHikariDataSourceWithDriverClassName, - JDBCDriverWithPoolTest::getHikariDataSource, - JDBCDriverWithPoolTest::getViburDataSourceWithDriverClassName, - JDBCDriverWithPoolTest::getViburDataSource + JDBCDriverWithPoolTest::getTomcatDataSourceWithDriverClassName, + JDBCDriverWithPoolTest::getTomcatDataSource, + JDBCDriverWithPoolTest::getHikariDataSourceWithDriverClassName, + JDBCDriverWithPoolTest::getHikariDataSource, + JDBCDriverWithPoolTest::getViburDataSourceWithDriverClassName, + JDBCDriverWithPoolTest::getViburDataSource ); } @@ -56,7 +60,7 @@ public void testMySQLWithConnectionPoolUsingSameContainer() throws SQLException, executorService.submit(() -> { try { new QueryRunner(dataSource).insert("INSERT INTO my_counter (n) VALUES (5)", - (ResultSetHandler) rs -> true); + (ResultSetHandler) rs -> true); } catch (SQLException e) { e.printStackTrace(); } @@ -130,6 +134,8 @@ private static DataSource getViburDataSourceWithDriverClassName() { ViburDBCPDataSource ds = new ViburDBCPDataSource(); ds.setJdbcUrl(URL + ";TEST=VIBUR_WITH_CLASSNAME"); + ds.setUsername("any"); // Recent versions of Vibur require a username, even though it will not be used + ds.setPassword(""); ds.setPoolInitialSize(3); ds.setPoolMaxSize(10); ds.setTestConnectionQuery("SELECT 1"); @@ -143,6 +149,8 @@ private static DataSource getViburDataSourceWithDriverClassName() { private static DataSource getViburDataSource() { ViburDBCPDataSource ds = new ViburDBCPDataSource(); ds.setJdbcUrl(URL + ";TEST=VIBUR"); + ds.setUsername("any"); // Recent versions of Vibur require a username, even though it will not be used + ds.setPassword(""); ds.setPoolInitialSize(3); ds.setPoolMaxSize(10); ds.setTestConnectionQuery("SELECT 1"); @@ -155,11 +163,11 @@ private static DataSource getViburDataSource() { @SuppressWarnings("SqlNoDataSourceInspection") public static void sampleInitFunction(Connection connection) throws SQLException { connection.createStatement().execute("CREATE TABLE bar (\n" + - " foo VARCHAR(255)\n" + - ");"); + " foo VARCHAR(255)\n" + + ");"); connection.createStatement().execute("INSERT INTO bar (foo) VALUES ('hello world');"); connection.createStatement().execute("CREATE TABLE my_counter (\n" + - " n INT\n" + - ");"); + " n INT\n" + + ");"); } } diff --git a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java new file mode 100644 index 00000000000..d4b37b291d5 --- /dev/null +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java @@ -0,0 +1,30 @@ +package org.testcontainers.jdbc.mysql; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class MySQLJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:mysql://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)}, + }); + } +} diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java new file mode 100644 index 00000000000..590d288e3fe --- /dev/null +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java @@ -0,0 +1,34 @@ +package org.testcontainers.junit.mysql; + +import org.junit.Test; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class CustomizableMysqlTest extends AbstractContainerDatabaseTest { + private static final String DB_NAME = "foo"; + private static final String USER = "bar"; + private static final String PWD = "baz"; + + @Test + public void testSimple() throws SQLException { + // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes + try (MySQLContainer mysql = new MySQLContainer<>("mysql:5.5") + .withDatabaseName(DB_NAME) + .withUsername(USER) + .withPassword(PWD) + .withEnv("MYSQL_ROOT_HOST", "%")) { + + mysql.start(); + + ResultSet resultSet = performQuery(mysql, "SELECT 1"); + + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/MultiVersionMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java similarity index 76% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/MultiVersionMySQLTest.java rename to modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java index b685d6dad80..3c0c86ffafa 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/MultiVersionMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java @@ -1,9 +1,10 @@ -package org.testcontainers.junit; +package org.testcontainers.junit.mysql; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; @@ -26,9 +27,9 @@ public MultiVersionMySQLTest(String version) { @Test public void versionCheckTest() throws SQLException { - try (final MySQLContainer container = new MySQLContainer<>("mysql:" + version)) { - container.start(); - final ResultSet resultSet = performQuery(container, "SELECT VERSION()"); + try (MySQLContainer mysql = new MySQLContainer<>("mysql:" + version)) { + mysql.start(); + final ResultSet resultSet = performQuery(mysql, "SELECT VERSION()"); final String resultSetString = resultSet.getString(1); assertEquals("The database version can be set using a container rule parameter", version, resultSetString); diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java similarity index 58% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java rename to modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index 9570659c4dc..ee6c3ab6993 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -1,4 +1,4 @@ -package org.testcontainers.junit; +package org.testcontainers.junit.mysql; import org.apache.commons.lang.SystemUtils; import org.junit.Test; @@ -7,6 +7,7 @@ import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; @@ -17,9 +18,6 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -/** - * @author richardnorth - */ public class SimpleMySQLTest extends AbstractContainerDatabaseTest { private static final Logger logger = LoggerFactory.getLogger(SimpleMySQLTest.class); @@ -31,86 +29,79 @@ public class SimpleMySQLTest extends AbstractContainerDatabaseTest { */ /* @ClassRule - public static MySQLContainer mysql = new MySQLContainer(); + public static MySQLContainer mysql = new MySQLContainer<>(); @ClassRule - public static MySQLContainer mysqlOldVersion = new MySQLContainer("mysql:5.5"); + public static MySQLContainer mysqlOldVersion = new MySQLContainer<>("mysql:5.5"); @ClassRule - public static MySQLContainer mysqlCustomConfig = new MySQLContainer("mysql:5.6") + public static MySQLContainer mysqlCustomConfig = new MySQLContainer<>("mysql:5.6") .withConfigurationOverride("somepath/mysql_conf_override"); */ @Test public void testSimple() throws SQLException { - MySQLContainer mysql = (MySQLContainer) new MySQLContainer() - .withConfigurationOverride("somepath/mysql_conf_override") - .withLogConsumer(new Slf4jLogConsumer(logger)); - mysql.start(); + try (MySQLContainer mysql = new MySQLContainer<>() + .withConfigurationOverride("somepath/mysql_conf_override") + .withLogConsumer(new Slf4jLogConsumer(logger))) { + + mysql.start(); - try { ResultSet resultSet = performQuery(mysql, "SELECT 1"); int resultSetInt = resultSet.getInt(1); assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - } finally { - mysql.stop(); } } @Test public void testSpecificVersion() throws SQLException { - MySQLContainer mysqlOldVersion = (MySQLContainer) new MySQLContainer("mysql:5.5") - .withConfigurationOverride("somepath/mysql_conf_override") - .withLogConsumer(new Slf4jLogConsumer(logger)); - mysqlOldVersion.start(); + try (MySQLContainer mysqlOldVersion = new MySQLContainer<>("mysql:5.5") + .withConfigurationOverride("somepath/mysql_conf_override") + .withLogConsumer(new Slf4jLogConsumer(logger))) { + + mysqlOldVersion.start(); - try { ResultSet resultSet = performQuery(mysqlOldVersion, "SELECT VERSION()"); String resultSetString = resultSet.getString(1); assertTrue("The database version can be set using a container rule parameter", resultSetString.startsWith("5.5")); - } finally { - mysqlOldVersion.stop(); } } @Test public void testMySQLWithCustomIniFile() throws SQLException { - assumeFalse(SystemUtils.IS_OS_WINDOWS); - MySQLContainer mysqlCustomConfig = new MySQLContainer("mysql:5.6") - .withConfigurationOverride("somepath/mysql_conf_override"); - mysqlCustomConfig.start(); + assumeFalse(SystemUtils.IS_OS_WINDOWS); + + try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>("mysql:5.6") + .withConfigurationOverride("somepath/mysql_conf_override")) { + + mysqlCustomConfig.start(); - try { ResultSet resultSet = performQuery(mysqlCustomConfig, "SELECT @@GLOBAL.innodb_file_format"); String result = resultSet.getString(1); assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result); - } finally { - mysqlCustomConfig.stop(); } } @Test public void testCommandOverride() throws SQLException { - MySQLContainer mysqlCustomConfig = (MySQLContainer) new MySQLContainer().withCommand("mysqld --auto_increment_increment=42"); - mysqlCustomConfig.start(); + try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>() + .withCommand("mysqld --auto_increment_increment=42")) { + + mysqlCustomConfig.start(); - try { ResultSet resultSet = performQuery(mysqlCustomConfig, "show variables like 'auto_increment_increment'"); String result = resultSet.getString("Value"); assertEquals("Auto increment increment should be overriden by command line", "42", result); - } finally { - mysqlCustomConfig.stop(); } - } @Test public void testExplicitInitScript() throws SQLException { - try (MySQLContainer container = (MySQLContainer) new MySQLContainer() + try (MySQLContainer container = new MySQLContainer<>() .withInitScript("somepath/init_mysql.sql") .withLogConsumer(new Slf4jLogConsumer(logger))) { container.start(); @@ -120,20 +111,35 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } - } + } - @Test + @Test(expected = ContainerLaunchException.class) public void testEmptyPasswordWithNonRootUser() { - - MySQLContainer container = (MySQLContainer) new MySQLContainer("mysql:5.5").withDatabaseName("TEST") - .withUsername("test").withPassword("").withEnv("MYSQL_ROOT_HOST", "%"); - - try { + try (MySQLContainer container = new MySQLContainer<>("mysql:5.5") + .withDatabaseName("TEST") + .withUsername("test") + .withPassword("") + .withEnv("MYSQL_ROOT_HOST", "%")){ container.start(); fail("ContainerLaunchException expected to be thrown"); - } catch (ContainerLaunchException e) { - } finally { - container.stop(); + } + } + + @Test + public void testEmptyPasswordWithRootUser() throws SQLException { + // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes + try (MySQLContainer mysql = new MySQLContainer<>("mysql:5.5") + .withDatabaseName("foo") + .withUsername("root") + .withPassword("") + .withEnv("MYSQL_ROOT_HOST", "%")) { + + mysql.start(); + + ResultSet resultSet = performQuery(mysql, "SELECT 1"); + int resultSetInt = resultSet.getInt(1); + + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } } diff --git a/modules/jdbc-test/src/test/resources/somepath/init_mysql.sql b/modules/mysql/src/test/resources/somepath/init_mysql.sql similarity index 100% rename from modules/jdbc-test/src/test/resources/somepath/init_mysql.sql rename to modules/mysql/src/test/resources/somepath/init_mysql.sql diff --git a/modules/mysql/src/test/resources/somepath/init_unicode_mysql.sql b/modules/mysql/src/test/resources/somepath/init_unicode_mysql.sql new file mode 100644 index 00000000000..f88969b0f30 --- /dev/null +++ b/modules/mysql/src/test/resources/somepath/init_unicode_mysql.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + foo varchar(255) character set utf8 +); + +INSERT INTO bar (foo) VALUES ('привет мир'); diff --git a/modules/jdbc-test/src/test/resources/somepath/mysql_conf_override/my.cnf b/modules/mysql/src/test/resources/somepath/mysql_conf_override/my.cnf similarity index 100% rename from modules/jdbc-test/src/test/resources/somepath/mysql_conf_override/my.cnf rename to modules/mysql/src/test/resources/somepath/mysql_conf_override/my.cnf diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index 1ab61e997af..026521e9a0c 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -3,7 +3,6 @@ description = "Testcontainers :: JDBC :: Oracle XE" dependencies { compile project(':jdbc') + testCompile project(':jdbc-test') testCompile 'com.oracle.ojdbc:ojdbc8:19.3.0.0' - testCompile 'com.zaxxer:HikariCP-java6:2.3.8' - testCompile 'commons-dbutils:commons-dbutils:1.7' } diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/containers/OracleJDBCDriverTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java similarity index 97% rename from modules/oracle-xe/src/test/java/org/testcontainers/containers/OracleJDBCDriverTest.java rename to modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java index fcc09ab69a4..fbe5ce95a05 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/containers/OracleJDBCDriverTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java @@ -1,4 +1,4 @@ -package org.testcontainers.containers; +package org.testcontainers.containers.jdbc; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleOracleTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java similarity index 50% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleOracleTest.java rename to modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java index 0855fd4860e..2415fed11f4 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleOracleTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java @@ -1,31 +1,26 @@ -package org.testcontainers.junit; +package org.testcontainers.junit.oracle; import org.junit.Ignore; -import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.OracleContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -/** - * @author gusohal - */ @Ignore public class SimpleOracleTest extends AbstractContainerDatabaseTest { - @Rule - public OracleContainer oracle = new OracleContainer(); - @Test public void testSimple() throws SQLException { - ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual"); + try (OracleContainer oracle = new OracleContainer()) { + ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual"); - resultSet.next(); - int resultSetInt = resultSet.getInt(1); + int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } } } diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 8c07465d424..380a3f86a80 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -5,12 +5,13 @@ dependencies { compileOnly 'com.google.auto.service:auto-service:1.0-rc6' compile project(':jdbc') + compileOnly project(':r2dbc') compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.2.RELEASE' + testCompile project(':jdbc-test') + testCompile project(':test-support') testCompile 'org.postgresql:postgresql:42.2.12' - testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index ec6a8756cab..3b887cedbec 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -11,7 +11,7 @@ public class PostgreSQLConnectionURLTest { @Test public void shouldCorrectlyAppendQueryString() { - PostgreSQLContainer postgres = new FixedJdbcUrlPostgreSQLContainer(); + PostgreSQLContainer postgres = new FixedJdbcUrlPostgreSQLContainer(); String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); @@ -22,7 +22,7 @@ public void shouldCorrectlyAppendQueryString() { @Test public void shouldCorrectlyAppendQueryStringWhenNoBaseParams() { - PostgreSQLContainer postgres = new NoParamsUrlPostgreSQLContainer(); + PostgreSQLContainer postgres = new NoParamsUrlPostgreSQLContainer(); String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); @@ -33,7 +33,7 @@ public void shouldCorrectlyAppendQueryStringWhenNoBaseParams() { @Test public void shouldReturnOriginalURLWhenEmptyQueryString() { - PostgreSQLContainer postgres = new FixedJdbcUrlPostgreSQLContainer(); + PostgreSQLContainer postgres = new FixedJdbcUrlPostgreSQLContainer(); String connectionUrl = postgres.constructUrlForConnection(""); assertTrue("Query String remains unchanged", postgres.getJdbcUrl().equals(connectionUrl)); @@ -45,7 +45,7 @@ public void shouldRejectInvalidQueryString() { () -> new NoParamsUrlPostgreSQLContainer().constructUrlForConnection("stringtype=unspecified")); } - static class FixedJdbcUrlPostgreSQLContainer extends PostgreSQLContainer { + static class FixedJdbcUrlPostgreSQLContainer extends PostgreSQLContainer { @Override public String getContainerIpAddress() { @@ -58,7 +58,7 @@ public Integer getMappedPort(int originalPort) { } } - static class NoParamsUrlPostgreSQLContainer extends PostgreSQLContainer { + static class NoParamsUrlPostgreSQLContainer extends PostgreSQLContainer { @Override public String getJdbcUrl() { diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java similarity index 76% rename from modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java rename to modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java index 855658ada56..9e3e0b03413 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java @@ -13,7 +13,10 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** - * Created by inikolaev on 08/06/2017. + * This test belongs in the jdbc module, as it is focused on testing the behaviour of {@link org.testcontainers.containers.JdbcDatabaseContainer}. + * However, the need to use the {@link org.testcontainers.containers.PostgreSQLContainerProvider} (due to the jdbc:tc:postgresql) URL forces it to live here in + * the mysql module, to avoid circular dependencies. + * TODO: Move to the jdbc module and either (a) implement a barebones {@link org.testcontainers.containers.JdbcDatabaseContainerProvider} for testing, or (b) refactor into a unit test. */ public class DatabaseDriverShutdownTest { @AfterClass diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java similarity index 71% rename from modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java rename to modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java index 6f337a586b6..a2b1fd5da8b 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -10,6 +10,12 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; +/** + * This test belongs in the jdbc module, as it is focused on testing the behaviour of {@link org.testcontainers.containers.JdbcDatabaseContainer}. + * However, the need to use the {@link org.testcontainers.containers.PostgreSQLContainerProvider} (due to the jdbc:tc:postgresql) URL forces it to live here in + * the mysql module, to avoid circular dependencies. + * TODO: Move to the jdbc module and either (a) implement a barebones {@link org.testcontainers.containers.JdbcDatabaseContainerProvider} for testing, or (b) refactor into a unit test. + */ public class DatabaseDriverTmpfsTest { @Test diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java new file mode 100644 index 00000000000..551ba86e185 --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java @@ -0,0 +1,22 @@ +package org.testcontainers.jdbc.postgis; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class PostgisJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + {"jdbc:tc:postgis:9.6://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + }); + } +} diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java new file mode 100644 index 00000000000..c63eb9ffb9d --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.jdbc.postgresql; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class PostgreSQLJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + }); + } +} diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java new file mode 100644 index 00000000000..8446440059e --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java @@ -0,0 +1,35 @@ +package org.testcontainers.junit.postgresql; + +import org.junit.Test; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +/** + * @author richardnorth + */ +public class CustomizablePostgreSQLTest extends AbstractContainerDatabaseTest { + private static final String DB_NAME = "foo"; + private static final String USER = "bar"; + private static final String PWD = "baz"; + + @Test + public void testSimple() throws SQLException { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:9.6.8") + .withDatabaseName(DB_NAME) + .withUsername(USER) + .withPassword(PWD)) { + + postgres.start(); + + ResultSet resultSet = performQuery(postgres, "SELECT 1"); + + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } +} diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java similarity index 78% rename from modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java rename to modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 7189e05fb16..9c97f51e64e 100644 --- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -1,7 +1,8 @@ -package org.testcontainers.junit; +package org.testcontainers.junit.postgresql; import org.junit.Test; import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; @@ -20,7 +21,7 @@ public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>()) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>()) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT 1"); @@ -31,7 +32,7 @@ public void testSimple() throws SQLException { @Test public void testCommandOverride() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42")) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42")) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); @@ -42,7 +43,7 @@ public void testCommandOverride() throws SQLException { @Test public void testUnsetCommand() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42").withCommand()) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42").withCommand()) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); @@ -53,7 +54,7 @@ public void testUnsetCommand() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withInitScript("somepath/init_postgresql.sql")) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withInitScript("somepath/init_postgresql.sql")) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); diff --git a/modules/postgresql/src/test/resources/somepath/init_postgresql.sql b/modules/postgresql/src/test/resources/somepath/init_postgresql.sql new file mode 100644 index 00000000000..2b00ee968b0 --- /dev/null +++ b/modules/postgresql/src/test/resources/somepath/init_postgresql.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + foo VARCHAR(255) +); + +INSERT INTO bar (foo) VALUES ('hello world'); \ No newline at end of file diff --git a/modules/presto/build.gradle b/modules/presto/build.gradle index 07aad11168e..51c5bf4345e 100644 --- a/modules/presto/build.gradle +++ b/modules/presto/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: JDBC :: Presto" dependencies { compile project(':jdbc') - testCompile 'io.prestosql:presto-jdbc:329' - testCompile 'commons-dbutils:commons-dbutils:1.7' + testCompile project(':jdbc-test') + testCompile 'io.prestosql:presto-jdbc:331' } diff --git a/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java b/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java new file mode 100644 index 00000000000..88939c62939 --- /dev/null +++ b/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.jdbc.presto; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class PrestoJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:presto:329://hostname/", EnumSet.of(Options.PmdKnownBroken)}, + }); + } +} diff --git a/test-support/build.gradle b/test-support/build.gradle index 7cc1bb6d1d4..4c6fdd2bed1 100644 --- a/test-support/build.gradle +++ b/test-support/build.gradle @@ -1,4 +1,4 @@ dependencies { implementation 'junit:junit:4.12' - implementation 'org.slf4j:slf4j-api:1.7.26' + implementation 'org.slf4j:slf4j-api:1.7.30' } From fbda093796fec3eb6aed369b3699e426faf19ad7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 11:49:11 +0100 Subject: [PATCH 0724/4969] Bump r2dbc-mariadb from 0.8.1-alpha1 to 0.8.2-alpha2 in /modules/mariadb (#2702) --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 71f2417f2ad..38862c7f03c 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' + compileOnly 'org.mariadb:r2dbc-mariadb:0.8.2-alpha2' testCompile project(':jdbc-test') testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' From d1bf6b836d0e3e78845b9650076a8a3388a540f3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 11:54:40 +0100 Subject: [PATCH 0725/4969] Bump aws-java-sdk-logs from 1.11.777 to 1.11.782 in /modules/localstack (#2730) --- modules/localstack/build.gradle | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 44b732d4c60..3f88f41c176 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,10 +3,9 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.778' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.775' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.782' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.782' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.777' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.775' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.782' testCompile 'software.amazon.awssdk:s3:2.13.16' } From 1ed8d81d5eaf8293b1fe6659060e790cbe88e6ce Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 11:56:40 +0100 Subject: [PATCH 0726/4969] Bump mssql-jdbc from 6.1.0.jre8 to 8.3.0.jre8-preview in /modules/mssqlserver (#2733) --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index c21bc43c869..5d72209b27e 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -17,5 +17,5 @@ dependencies { // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) - testCompile 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.0.jre8-preview' } From f84bcd6136a33a336ecf6139b2f85b8bf19512d5 Mon Sep 17 00:00:00 2001 From: Simon Schneider <10846939+raynigon@users.noreply.github.com> Date: Thu, 14 May 2020 14:25:00 +0200 Subject: [PATCH 0727/4969] Add Apache Solr Module (#2123) --- docs/modules/solr.md | 34 +++++ examples/settings.gradle | 3 +- examples/solr-container/build.gradle | 18 +++ .../main/java/com/example/SearchEngine.java | 6 + .../main/java/com/example/SearchResult.java | 20 +++ .../java/com/example/SolrSearchEngine.java | 39 +++++ .../test/java/com/example/SolrQueryTest.java | 88 ++++++++++++ mkdocs.yml | 1 + modules/solr/build.gradle | 7 + .../containers/SolrClientUtils.java | 133 +++++++++++++++++ .../containers/SolrClientUtilsException.java | 7 + .../containers/SolrContainer.java | 135 ++++++++++++++++++ .../SolrContainerConfiguration.java | 18 +++ .../containers/SolrContainerTest.java | 76 ++++++++++ 14 files changed, 584 insertions(+), 1 deletion(-) create mode 100644 docs/modules/solr.md create mode 100644 examples/solr-container/build.gradle create mode 100644 examples/solr-container/src/main/java/com/example/SearchEngine.java create mode 100644 examples/solr-container/src/main/java/com/example/SearchResult.java create mode 100644 examples/solr-container/src/main/java/com/example/SolrSearchEngine.java create mode 100644 examples/solr-container/src/test/java/com/example/SolrQueryTest.java create mode 100644 modules/solr/build.gradle create mode 100644 modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java create mode 100644 modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java create mode 100644 modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java create mode 100644 modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java create mode 100644 modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java diff --git a/docs/modules/solr.md b/docs/modules/solr.md new file mode 100644 index 00000000000..4776ffa608b --- /dev/null +++ b/docs/modules/solr.md @@ -0,0 +1,34 @@ +# Solr Container + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + + +This module helps running [solr](https://lucene.apache.org/solr/) using Testcontainers. + +Note that it's based on the [official Docker image](https://hub.docker.com/_/solr/). + +## Usage example + +You can start a solr container instance from any Java application by using: + + +[Using a Solr container](../../modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java) inside_block:solrContainerUsage + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:solr:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + solr + {{latest_version}} + test + +``` diff --git a/examples/settings.gradle b/examples/settings.gradle index 9efbf097344..ef47a61f807 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -10,7 +10,8 @@ include 'redis-backed-cache' include 'redis-backed-cache-testng' include 'selenium-container' include 'singleton-container' +include 'solr-container' include 'spring-boot' include 'cucumber' include 'spring-boot-kotlin-redis' -include 'spock' \ No newline at end of file +include 'spock' diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle new file mode 100644 index 00000000000..62ed7d1153a --- /dev/null +++ b/examples/solr-container/build.gradle @@ -0,0 +1,18 @@ +plugins { + id 'java' +} + +repositories { + jcenter() +} + +dependencies { + compileOnly "org.projectlombok:lombok:1.18.10" + annotationProcessor "org.projectlombok:lombok:1.18.10" + + implementation 'org.apache.solr:solr-solrj:8.3.0' + + testImplementation 'org.testcontainers:testcontainers' + testImplementation 'org.testcontainers:solr' + +} diff --git a/examples/solr-container/src/main/java/com/example/SearchEngine.java b/examples/solr-container/src/main/java/com/example/SearchEngine.java new file mode 100644 index 00000000000..c05bc23aad2 --- /dev/null +++ b/examples/solr-container/src/main/java/com/example/SearchEngine.java @@ -0,0 +1,6 @@ +package com.example; + +public interface SearchEngine { + + public SearchResult search(String term); +} diff --git a/examples/solr-container/src/main/java/com/example/SearchResult.java b/examples/solr-container/src/main/java/com/example/SearchResult.java new file mode 100644 index 00000000000..06544f0ba34 --- /dev/null +++ b/examples/solr-container/src/main/java/com/example/SearchResult.java @@ -0,0 +1,20 @@ +package com.example; + +import java.util.List; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SearchResult { + + private long totalHits; + + private List> results; +} diff --git a/examples/solr-container/src/main/java/com/example/SolrSearchEngine.java b/examples/solr-container/src/main/java/com/example/SolrSearchEngine.java new file mode 100644 index 00000000000..8a7f38e455d --- /dev/null +++ b/examples/solr-container/src/main/java/com/example/SolrSearchEngine.java @@ -0,0 +1,39 @@ +package com.example; + +import java.util.stream.Collectors; + +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.client.solrj.util.ClientUtils; +import org.apache.solr.common.SolrDocument; + +@RequiredArgsConstructor +public class SolrSearchEngine implements SearchEngine { + + public static final String COLLECTION_NAME = "products"; + + private final SolrClient client; + + @SneakyThrows + public SearchResult search(String term) { + + SolrQuery query = new SolrQuery(); + query.setQuery("title:" + ClientUtils.escapeQueryChars(term)); + QueryResponse response = client.query(COLLECTION_NAME, query); + return createResult(response); + } + + private SearchResult createResult(QueryResponse response) { + return SearchResult.builder() + .totalHits(response.getResults().getNumFound()) + .results(response.getResults() + .stream() + .map(SolrDocument::getFieldValueMap) + .collect(Collectors.toList())) + .build(); + } +} diff --git a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java new file mode 100644 index 00000000000..413d7937853 --- /dev/null +++ b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java @@ -0,0 +1,88 @@ +package com.example; + +import static com.example.SolrSearchEngine.COLLECTION_NAME; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.Http2SolrClient; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.SolrInputField; +import org.junit.BeforeClass; +import org.junit.Test; +import org.testcontainers.containers.SolrContainer; + +public class SolrQueryTest { + + public static final SolrContainer solrContainer = new SolrContainer() + .withCollection(COLLECTION_NAME); + + private static SolrClient solrClient; + + @BeforeClass + public static void setUp() throws IOException, SolrServerException { + solrContainer.start(); + solrClient = new Http2SolrClient.Builder("http://" + solrContainer.getContainerIpAddress() + ":" + solrContainer.getSolrPort() + "/solr").build(); + + // Add Sample Data + solrClient.add(COLLECTION_NAME, Collections.singletonList( + new SolrInputDocument(createMap( + "id", createInputField("id", "1"), + "title", createInputField("title", "old skool - trainers - shoes") + )) + )); + + solrClient.add(COLLECTION_NAME, Collections.singletonList( + new SolrInputDocument(createMap( + "id", createInputField("id", "2"), + "title", createInputField("title", "print t-shirt") + )) + )); + + solrClient.commit(COLLECTION_NAME); + } + + @Test + public void testQueryForShoes() { + SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); + + SearchResult result = searchEngine.search("shoes"); + assertEquals("When searching for shoes we expect one result", 1L, result.getTotalHits()); + assertEquals("The result should have the id 1", "1", result.getResults().get(0).get("id")); + } + + @Test + public void testQueryForTShirt() { + SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); + + SearchResult result = searchEngine.search("t-shirt"); + assertEquals("When searching for t-shirt we expect one result", 1L, result.getTotalHits()); + assertEquals("The result should have the id 2", "2", result.getResults().get(0).get("id")); + } + + @Test + public void testQueryForAsterisk() { + SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); + + SearchResult result = searchEngine.search("*"); + assertEquals("When searching for * we expect no results", 0L, result.getTotalHits()); + } + + private static SolrInputField createInputField(String key, String value) { + SolrInputField inputField = new SolrInputField(key); + inputField.setValue(value); + return inputField; + } + + private static Map createMap(String k0, SolrInputField v0, String k1, SolrInputField v1) { + Map result = new HashMap<>(); + result.put(k0, v0); + result.put(k1, v1); + return result; + } +} diff --git a/mkdocs.yml b/mkdocs.yml index e1b21d80811..48b63c59631 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -66,6 +66,7 @@ nav: - modules/nginx.md - modules/pulsar.md - modules/rabbitmq.md + - modules/solr.md - modules/toxiproxy.md - modules/vault.md - modules/webdriver_containers.md diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle new file mode 100644 index 00000000000..af3193be52a --- /dev/null +++ b/modules/solr/build.gradle @@ -0,0 +1,7 @@ +description = "Testcontainers :: Solr" + +dependencies { + compile project(':testcontainers') + testCompile 'org.apache.solr:solr-solrj:8.3.0' + +} diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java new file mode 100644 index 00000000000..4492ca0befe --- /dev/null +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java @@ -0,0 +1,133 @@ +package org.testcontainers.containers; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.apache.commons.io.IOUtils; + +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +/** + * Utils class which can create collections and configurations. + * + * @author Simon Schneider + */ +public class SolrClientUtils { + + private static OkHttpClient httpClient = new OkHttpClient(); + + /** + * Creates a new configuration and uploads the solrconfig.xml and schema.xml + * + * @param hostname the Hostname under which solr is reachable + * @param port the Port on which solr is running + * @param configurationName the name of the configuration which should be created + * @param solrConfig the url under which the solrconfig.xml can be found + * @param solrSchema the url under which the schema.xml can be found or null if the default schema should be used + */ + public static void uploadConfiguration(String hostname, int port, String configurationName, URL solrConfig, URL solrSchema) throws URISyntaxException, IOException { + Map parameters = new HashMap<>(); + parameters.put("action", "UPLOAD"); + parameters.put("name", configurationName); + HttpUrl url = generateSolrURL(hostname, port, Arrays.asList("admin", "configs"), parameters); + + byte[] configurationZipFile = generateConfigZipFile(solrConfig, solrSchema); + executePost(url, configurationZipFile); + + } + + /** + * Creates a new collection + * + * @param hostname the Hostname under which solr is reachable + * @param port The Port on which solr is running + * @param collectionName the name of the collection which should be created + * @param configurationName the name of the configuration which should used to create the collection + * or null if the default configuration should be used + */ + public static void createCollection(String hostname, int port, String collectionName, String configurationName) throws URISyntaxException, IOException { + Map parameters = new HashMap<>(); + parameters.put("action", "CREATE"); + parameters.put("name", collectionName); + parameters.put("numShards", "1"); + parameters.put("replicationFactor", "1"); + parameters.put("wt", "json"); + if (configurationName != null) { + parameters.put("collection.configName", configurationName); + } + HttpUrl url = generateSolrURL(hostname, port, Arrays.asList("admin", "collections"), parameters); + executePost(url, null); + } + + private static void executePost(HttpUrl url, byte[] data) throws IOException { + + RequestBody requestBody = data == null ? + RequestBody.create(MediaType.parse("text/plain"), "") : + RequestBody.create(MediaType.parse("application/octet-stream"), data); + ; + + Request request = new Request.Builder() + .url(url) + .post(requestBody) + .build(); + Response response = httpClient.newCall(request).execute(); + if (!response.isSuccessful()) { + String responseBody = ""; + if (response.body() != null) { + responseBody = response.body().string(); + response.close(); + } + throw new SolrClientUtilsException(response.code(), "Unable to upload binary\n" + responseBody); + } + if (response.body() != null) { + response.close(); + } + } + + private static HttpUrl generateSolrURL(String hostname, int port, List pathSegments, Map parameters) throws URISyntaxException { + HttpUrl.Builder builder = new HttpUrl.Builder(); + builder.scheme("http"); + builder.host(hostname); + builder.port(port); + // Path + builder.addPathSegment("solr"); + if (pathSegments != null) { + pathSegments.forEach(builder::addPathSegment); + } + // Query Parameters + parameters.forEach(builder::addQueryParameter); + return builder.build(); + } + + private static byte[] generateConfigZipFile(URL solrConfiguration, URL solrSchema) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zipOutputStream = new ZipOutputStream(bos); + // SolrConfig + zipOutputStream.putNextEntry(new ZipEntry("solrconfig.xml")); + IOUtils.copy(solrConfiguration.openStream(), zipOutputStream); + zipOutputStream.closeEntry(); + + // Solr Schema + if (solrSchema != null) { + zipOutputStream.putNextEntry(new ZipEntry("schema.xml")); + IOUtils.copy(solrSchema.openStream(), zipOutputStream); + zipOutputStream.closeEntry(); + } + + zipOutputStream.close(); + return bos.toByteArray(); + } +} diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java new file mode 100644 index 00000000000..5ba0865502c --- /dev/null +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java @@ -0,0 +1,7 @@ +package org.testcontainers.containers; + +public class SolrClientUtilsException extends RuntimeException { + public SolrClientUtilsException(int statusCode, String msg) { + super("Http Call Status: " + statusCode + "\n" + msg); + } +} diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java new file mode 100644 index 00000000000..90fd674dfda --- /dev/null +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java @@ -0,0 +1,135 @@ +package org.testcontainers.containers; + +import static java.time.temporal.ChronoUnit.SECONDS; + +import java.net.URL; +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; + +import com.github.dockerjava.api.command.InspectContainerResponse; + +import lombok.SneakyThrows; + +import org.apache.commons.lang.StringUtils; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; + +/** + * SolrContainer allows a solr container to be launched and controlled. + */ +public class SolrContainer extends GenericContainer { + + public static final String IMAGE = "solr"; + public static final String DEFAULT_TAG = "8.3.0"; + + public static final Integer ZOOKEEPER_PORT = 9983; + public static final Integer SOLR_PORT = 8983; + + private SolrContainerConfiguration configuration; + + public SolrContainer() { + this(IMAGE + ":" + DEFAULT_TAG); + } + + public SolrContainer(final String dockerImageName) { + super(dockerImageName); + this.waitStrategy = new LogMessageWaitStrategy() + .withRegEx(".*o\\.e\\.j\\.s\\.Server Started.*") + .withStartupTimeout(Duration.of(60, SECONDS)); + this.configuration = new SolrContainerConfiguration(); + } + + public SolrContainer withZookeeper(boolean zookeeper) { + configuration.setZookeeper(zookeeper); + return self(); + } + + public SolrContainer withCollection(String collection) { + if (StringUtils.isEmpty(collection)) { + throw new IllegalArgumentException("Collection name must not be empty"); + } + configuration.setCollectionName(collection); + return self(); + } + + public SolrContainer withConfiguration(String name, URL solrConfig) { + if (StringUtils.isEmpty(name) || solrConfig == null) { + throw new IllegalArgumentException(); + } + configuration.setConfigurationName(name); + configuration.setSolrConfiguration(solrConfig); + return self(); + } + + public SolrContainer withSchema(URL schema) { + configuration.setSolrSchema(schema); + return self(); + } + + public int getSolrPort() { + return getMappedPort(SOLR_PORT); + } + + public int getZookeeperPort() { + return getMappedPort(ZOOKEEPER_PORT); + } + + @Override + @SneakyThrows + protected void configure() { + if (configuration.getSolrSchema() != null && configuration.getSolrConfiguration() == null) { + throw new IllegalStateException("Solr needs to have a configuration is you want to use a schema"); + } + // Generate Command Builder + String command = "solr -f"; + // Add Default Ports + this.addExposedPort(SOLR_PORT); + + // Configure Zookeeper + if (configuration.isZookeeper()) { + this.addExposedPort(ZOOKEEPER_PORT); + command = "-DzkRun -h localhost"; + } + + // Apply generated Command + this.setCommand(command); + } + + @Override + public Set getLivenessCheckPortNumbers() { + return new HashSet<>(getSolrPort()); + } + + @Override + protected void waitUntilContainerStarted() { + getWaitStrategy().waitUntilReady(this); + } + + @Override + @SneakyThrows + protected void containerIsStarted(InspectContainerResponse containerInfo) { + if (!configuration.isZookeeper()) { + ExecResult result = execInContainer("solr", "create_core", "-c", configuration.getCollectionName()); + if (result.getExitCode() != 0) { + throw new IllegalStateException("Unable to create solr core:\nStdout: " + result.getStdout() + "\nStderr:" + result.getStderr()); + } + return; + } + + if (StringUtils.isNotEmpty(configuration.getConfigurationName())) { + SolrClientUtils.uploadConfiguration( + getContainerIpAddress(), + getSolrPort(), + configuration.getConfigurationName(), + configuration.getSolrConfiguration(), + configuration.getSolrSchema()); + } + + SolrClientUtils.createCollection( + getContainerIpAddress(), + getSolrPort(), + configuration.getCollectionName(), + configuration.getConfigurationName()); + } +} + diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java new file mode 100644 index 00000000000..1f35ce2a810 --- /dev/null +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java @@ -0,0 +1,18 @@ +package org.testcontainers.containers; + +import java.net.URL; + +import lombok.Data; + +/** + * @author Simon Schneider + */ +@Data +public class SolrContainerConfiguration { + + private boolean zookeeper = true; + private String collectionName = "dummy"; + private String configurationName; + private URL solrConfiguration; + private URL solrSchema; +} diff --git a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java new file mode 100644 index 00000000000..48cb04b7053 --- /dev/null +++ b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java @@ -0,0 +1,76 @@ +package org.testcontainers.containers; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.IOException; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.Http2SolrClient; +import org.apache.solr.client.solrj.response.SolrPingResponse; +import org.junit.After; +import org.junit.Test; + +/** + * @author Simon Schneider + */ +public class SolrContainerTest { + + private SolrClient client = null; + + @After + public void stopRestClient() throws IOException { + if (client != null) { + client.close(); + client = null; + } + } + + @Test + public void solrCloudTest() throws IOException, SolrServerException { + try (SolrContainer container = new SolrContainer()) { + container.start(); + SolrPingResponse response = getClient(container).ping("dummy"); + assertThat(response.getStatus(), is(0)); + assertThat(response.jsonStr(), containsString("zkConnected\":true")); + } + } + + @Test + public void solrStandaloneTest() throws IOException, SolrServerException { + try (SolrContainer container = new SolrContainer().withZookeeper(false)) { + container.start(); + SolrPingResponse response = getClient(container).ping("dummy"); + assertThat(response.getStatus(), is(0)); + assertThat(response.jsonStr(), containsString("zkConnected\":null")); + } + } + + @Test + public void solrCloudPingTest() throws IOException, SolrServerException { + // solrContainerUsage { + // Create the solr container. + SolrContainer container = new SolrContainer(); + + // Start the container. This step might take some time... + container.start(); + + // Do whatever you want with the client ... + SolrClient client = new Http2SolrClient.Builder("http://" + container.getContainerIpAddress() + ":" + container.getSolrPort() + "/solr").build(); + SolrPingResponse response = client.ping("dummy"); + + // Stop the container. + container.stop(); + // } + } + + private SolrClient getClient(SolrContainer container) { + if (client == null) { + client = new Http2SolrClient.Builder("http://" + container.getContainerIpAddress() + ":" + container.getSolrPort() + "/solr").build(); + } + return client; + } + +} From a2a59bcf9592f1a6d8a1efbaea443ac5e2714f62 Mon Sep 17 00:00:00 2001 From: Martin Vysny Date: Thu, 14 May 2020 18:34:41 +0300 Subject: [PATCH 0728/4969] Implement DockerClientFactory.isDockerAvailable() (#2605) --- .../org/testcontainers/DockerClientFactory.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 8d9da8825d2..4e16a7edf9d 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -101,6 +101,19 @@ public synchronized static DockerClientFactory instance() { return instance; } + /** + * Checks whether Docker is accessible and {@link #client()} is able to produce a client. + * @return true if Docker is available, false if not. + */ + public synchronized boolean isDockerAvailable() { + try { + client(); + return true; + } catch (IllegalStateException ex) { + return false; + } + } + @Synchronized private DockerClientProviderStrategy getOrInitializeStrategy() { if (strategy != null) { From ede19c8a4efd48ed20f32105d81fb71249e386af Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 15 May 2020 15:10:36 +0200 Subject: [PATCH 0729/4969] Update example to Spring Boot 2.3.0 (#2743) --- examples/spring-boot/build.gradle | 6 +++--- .../src/test/java/com/example/AbstractIntegrationTest.java | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index c7b0c63d7ba..ad8d8252fb6 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.7.RELEASE' + id 'org.springframework.boot' version '2.3.0.RELEASE' } apply plugin: 'io.spring.dependency-management' @@ -9,8 +9,8 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.12" - annotationProcessor "org.projectlombok:lombok:1.18.10" + compileOnly "org.projectlombok:lombok" + annotationProcessor "org.projectlombok:lombok" implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' diff --git a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java index 29a1f51ffcc..79828923d7d 100644 --- a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java +++ b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java @@ -12,7 +12,6 @@ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "spring.datasource.url=jdbc:tc:postgresql:11-alpine:///databasename", - "spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver" }) @ActiveProfiles("test") public abstract class AbstractIntegrationTest { From 672cbeebcac6310caab90383bce11a0b753b1106 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 15 May 2020 15:11:57 +0200 Subject: [PATCH 0730/4969] Add `ContainerState#getHost` replacing `getContainerIpAddress` (#2742) * Add `ContainerState#getHost` replacing `getContainerIpAddress` * post-merge fixes * Ignore `METHOD_NEW_DEFAULT` in japicmp * Update docs/features/networking.md Co-authored-by: Richard North * Add a tip about `getContainerIpAddress()` * Fix the codeincludes Co-authored-by: Richard North --- core/build.gradle | 12 +++--------- .../ComposeServiceWaitStrategyTarget.java | 4 ++-- .../containers/ContainerState.java | 12 ++++++++++++ .../containers/DockerComposeContainer.java | 2 +- .../containers/GenericContainer.java | 2 +- .../containers/PortForwardingContainer.java | 4 ++-- .../internal/ExternalPortListeningCheck.java | 2 +- .../wait/strategy/HostPortWaitStrategy.java | 2 +- .../wait/strategy/HttpWaitStrategy.java | 2 +- .../internal/ExternalPortListeningCheckTest.java | 2 +- .../images/ImagePullPolicyTest.java | 2 +- .../junit/DockerfileContainerTest.java | 2 +- .../junit/FixedHostPortContainerTest.java | 2 +- .../junit/GenericContainerRuleTest.java | 6 +++--- .../utility/AuthenticatedImagePullTest.java | 2 +- .../java/generic/MultiplePortsExposedTest.java | 8 ++++---- .../java/quickstart/RedisBackedCacheIntTest.java | 2 +- .../java/quickstart/RedisBackedCacheIntTest.java | 2 +- .../quickstart/RedisBackedCacheIntTest.groovy | 2 +- docs/features/networking.md | 16 ++++++++++------ docs/modules/vault.md | 2 +- docs/quickstart/junit_4_quickstart.md | 4 ++-- docs/quickstart/junit_5_quickstart.md | 4 ++-- .../containers/CassandraContainer.java | 2 +- .../containers/CassandraContainerTest.java | 2 +- .../containers/ClickHouseContainer.java | 2 +- .../containers/CockroachContainer.java | 2 +- .../couchbase/CouchbaseContainer.java | 10 +++++----- .../couchbase/CouchbaseContainerTest.java | 2 +- .../testcontainers/containers/Db2Container.java | 10 +--------- .../dynamodb/DynaliteContainer.java | 2 +- .../elasticsearch/ElasticsearchContainer.java | 4 ++-- .../containers/InfluxDBContainer.java | 2 +- .../jupiter/inheritance/RedisContainer.java | 2 +- .../containers/KafkaContainer.java | 2 +- .../localstack/LocalStackContainer.java | 4 ++-- .../containers/MariaDBContainer.java | 2 +- .../MariaDBR2DBCDatabaseContainer.java | 2 +- .../containers/MockServerContainer.java | 2 +- .../containers/MockServerContainerTest.java | 4 ++-- .../containers/MSSQLR2DBCDatabaseContainer.java | 2 +- .../containers/MSSQLServerContainer.java | 2 +- .../containers/MySQLContainer.java | 2 +- .../containers/MySQLR2DBCDatabaseContainer.java | 2 +- .../containers/Neo4jContainer.java | 6 +++--- .../containers/NginxContainer.java | 2 +- .../containers/OracleContainer.java | 2 +- .../containers/OrientDBContainer.java | 2 +- .../containers/OrientDBContainerTest.java | 2 +- .../containers/PostgreSQLContainer.java | 2 +- .../PostgreSQLR2DBCDatabaseContainer.java | 2 +- .../containers/PostgreSQLConnectionURLTest.java | 2 +- .../containers/PrestoContainer.java | 2 +- .../containers/PulsarContainer.java | 4 ++-- .../containers/RabbitMQContainer.java | 8 ++++---- .../containers/RabbitMQContainerTest.java | 8 ++++---- .../containers/BrowserWebDriverContainer.java | 4 ++-- .../spock/TestcontainersSharedContainerIT.groovy | 2 +- .../containers/ToxiproxyContainer.java | 4 ++-- .../testcontainers/containers/ToxiproxyTest.java | 2 +- .../testcontainers/vault/VaultClientTest.java | 3 +-- .../testcontainers/vault/VaultContainerTest.java | 2 +- 62 files changed, 111 insertions(+), 110 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 4c62a2416ef..39495e59dce 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -84,20 +84,14 @@ task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { failOnModification = true failOnSourceIncompatibility = true - // TODO cleanup excludes after we release the version based on docker-java 3.2.0 - packageExcludes = [ "com.github.dockerjava.*", "org.testcontainers.shaded.*", ] - classExcludes = [ - // 'METHOD_REMOVED_IN_SUPERCLASS' - "org.testcontainers.containers.output.FrameConsumerResultCallback", - "org.testcontainers.dockerclient.LogToStringContainerCallback", - - // 'METHOD_RETURN_TYPE_CHANGED', exposed `com.github.dockerjava.core.command.PullImageResultCallback` to the public API - "org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback", + methodExcludes = [ + // METHOD_NEW_DEFAULT + "org.testcontainers.containers.ContainerState#getHost()" ] onlyBinaryIncompatibleModified = true diff --git a/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java b/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java index d4ad51dc1da..2fb953b4aee 100644 --- a/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java +++ b/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java @@ -54,8 +54,8 @@ public Integer getMappedPort(int originalPort) { * {@inheritDoc} */ @Override - public String getContainerIpAddress() { - return proxyContainer.getContainerIpAddress(); + public String getHost() { + return proxyContainer.getHost(); } /** diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index ad006aa3b43..1565b4e7e3e 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -43,8 +43,18 @@ public interface ContainerState { * Get the IP address that this container may be reached on (may not be the local machine). * * @return an IP address + * @see #getHost() */ default String getContainerIpAddress() { + return getHost(); + } + + /** + * Get the host that this container may be reached on (may not be the local machine). + * + * @return a host + */ + default String getHost() { return DockerClientFactory.instance().dockerHostIpAddress(); } @@ -107,6 +117,7 @@ default InspectContainerResponse getCurrentContainerInfo() { /** * Get the actual mapped port for a first port exposed by the container. + * Should be used in conjunction with {@link #getHost()}. * * @return the port that the exposed port is mapped to * @throws IllegalStateException if there are no exposed ports @@ -121,6 +132,7 @@ default Integer getFirstMappedPort() { /** * Get the actual mapped port for a given port exposed by the container. + * Should be used in conjunction with {@link #getHost()}. * * @param originalPort the original TCP port that is exposed * @return the port that the exposed port is mapped to, or null if it is not exposed diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 7bf8d3c916b..651bd9c8526 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -402,7 +402,7 @@ public SELF waitingFor(String serviceName, @NonNull WaitStrategy waitStrategy) { * @return a host IP address or hostname that can be used for accessing the service container. */ public String getServiceHost(String serviceName, Integer servicePort) { - return ambassadorContainer.getContainerIpAddress(); + return ambassadorContainer.getHost(); } /** diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 23e5f9bf173..89938cdfe56 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1244,7 +1244,7 @@ public SELF withCopyFileToContainer(MountableFile mountableFile, String containe */ @Deprecated public String getIpAddress() { - return getContainerIpAddress(); + return getHost(); } /** diff --git a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java index 852a986b58f..09f1d98bd2d 100644 --- a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java @@ -40,7 +40,7 @@ private Connection createSSHSession() { ); container.start(); - Connection connection = new Connection(container.getContainerIpAddress(), container.getMappedPort(22)); + Connection connection = new Connection(container.getHost(), container.getMappedPort(22)); connection.setTCPNoDelay(true); connection.connect( @@ -60,7 +60,7 @@ private Connection createSSHSession() { public void exposeHostPort(int port) { exposeHostPort(port, port); } - + @SneakyThrows public void exposeHostPort(int hostPort, int containerPort) { if (exposedPorts.add(new AbstractMap.SimpleEntry<>(hostPort, containerPort))) { diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java index 2aae12bab8d..b9b63eeee5c 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java @@ -18,7 +18,7 @@ public class ExternalPortListeningCheck implements Callable { @Override public Boolean call() { - String address = containerState.getContainerIpAddress(); + String address = containerState.getHost(); externalLivenessCheckPorts.parallelStream().forEach(externalPort -> { try { diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java index 91f4e91fadf..a0ba1e9950c 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java @@ -46,7 +46,7 @@ protected void waitUntilReady() { } catch (TimeoutException e) { throw new ContainerLaunchException("Timed out waiting for container port to open (" + - waitStrategyTarget.getContainerIpAddress() + + waitStrategyTarget.getHost() + " ports: " + externalLivenessCheckPorts + " should be listening)"); diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java index a44fc46e4b0..5fd7834b12d 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java @@ -225,7 +225,7 @@ protected void waitUntilReady() { */ private URI buildLivenessUri(int livenessCheckPort) { final String scheme = (tlsEnabled ? "https" : "http") + "://"; - final String host = waitStrategyTarget.getContainerIpAddress(); + final String host = waitStrategyTarget.getHost(); final String portSuffix; if ((tlsEnabled && 443 == livenessCheckPort) || (!tlsEnabled && 80 == livenessCheckPort)) { diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java index 69bf9d06ce7..19f3a772d41 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java @@ -29,7 +29,7 @@ public void setUp() throws Exception { nonListeningSocket.close(); mockContainer = mock(WaitStrategyTarget.class); - when(mockContainer.getContainerIpAddress()).thenReturn("127.0.0.1"); + when(mockContainer.getHost()).thenReturn("127.0.0.1"); } @Test diff --git a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java index 59b7486c75e..69e68f7f225 100644 --- a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java @@ -33,7 +33,7 @@ public class ImagePullPolicyTest { @BeforeClass public static void beforeClass() throws Exception { - String testRegistryAddress = registry.getContainerIpAddress() + ":" + registry.getFirstMappedPort(); + String testRegistryAddress = registry.getHost() + ":" + registry.getFirstMappedPort(); String testImageName = testRegistryAddress + "/image-pull-policy-test"; String tag = UUID.randomUUID().toString(); imageName = testImageName + ":" + tag; diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java index 8f601b2e737..6ad7c3ea26e 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java @@ -31,7 +31,7 @@ public class DockerfileContainerTest { @Test public void simpleDslTest() throws IOException { - String address = String.format("http://%s:%s", dslContainer.getContainerIpAddress(), dslContainer.getMappedPort(80)); + String address = String.format("http://%s:%s", dslContainer.getHost(), dslContainer.getMappedPort(80)); CloseableHttpClient httpClient = HttpClientBuilder.create().build(); HttpGet get = new HttpGet(address); diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index dba48da4db1..5fe49756ba1 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -85,7 +85,7 @@ private String readResponse(GenericContainer container, Integer port) throws IOE final BufferedReader reader = Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); - final Socket socket = new Socket(container.getContainerIpAddress(), port); + final Socket socket = new Socket(container.getHost(), port); return new BufferedReader(new InputStreamReader(socket.getInputStream())); } ) diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index 6c51713b6b1..1f4a3ff121d 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -162,7 +162,7 @@ public void withTmpFsTest() throws Exception { @Test public void simpleRabbitMqTest() throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); - factory.setHost(rabbitMq.getContainerIpAddress()); + factory.setHost(rabbitMq.getHost()); factory.setPort(rabbitMq.getMappedPort(RABBITMQ_PORT)); Connection connection = factory.newConnection(); @@ -194,7 +194,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp @Test public void simpleMongoDbTest() { - MongoClient mongoClient = new MongoClient(mongo.getContainerIpAddress(), mongo.getMappedPort(MONGO_PORT)); + MongoClient mongoClient = new MongoClient(mongo.getHost(), mongo.getMappedPort(MONGO_PORT)); MongoDatabase database = mongoClient.getDatabase("test"); MongoCollection collection = database.getCollection("testCollection"); @@ -366,7 +366,7 @@ private BufferedReader getReaderForContainerPort80(GenericContainer container) { return Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); - Socket socket = new Socket(container.getContainerIpAddress(), container.getFirstMappedPort()); + Socket socket = new Socket(container.getHost(), container.getFirstMappedPort()); return new BufferedReader(new InputStreamReader(socket.getInputStream())); }); } diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 5f4417f218b..31f098bab16 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -65,7 +65,7 @@ public static void setUp() throws InterruptedException { originalAuthLocatorSingleton = RegistryAuthLocator.instance(); client = DockerClientFactory.instance().client(); - String testRegistryAddress = authenticatedRegistry.getContainerIpAddress() + ":" + authenticatedRegistry.getFirstMappedPort(); + String testRegistryAddress = authenticatedRegistry.getHost() + ":" + authenticatedRegistry.getFirstMappedPort(); testImageName = testRegistryAddress + "/alpine"; testImageNameWithTag = testImageName + ":latest"; diff --git a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java index f22bc55defd..f5a92423b6c 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java @@ -31,13 +31,13 @@ public void fetchFirstMappedPort() { } @Test - public void getContainerIpAddressOnly() { - String ipAddress = container.getContainerIpAddress(); + public void getHostOnly() { + String ipAddress = container.getHost(); } @Test - public void getContainerIpAddressAndMappedPort() { + public void getHostAndMappedPort() { String address = - container.getContainerIpAddress() + ":" + container.getMappedPort(2424); + container.getHost() + ":" + container.getMappedPort(2424); } } diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index ac3ae7746b4..f2ef1ab0220 100644 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -21,7 +21,7 @@ public class RedisBackedCacheIntTest { @Before public void setUp() { - String address = redis.getContainerIpAddress(); + String address = redis.getHost(); Integer port = redis.getFirstMappedPort(); // Now we have an address and port for Redis, no matter where it is running diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index 7c3968a724e..0f4f98fb669 100644 --- a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -24,7 +24,7 @@ public class RedisBackedCacheIntTest { @BeforeEach public void setUp() { - String address = redis.getContainerIpAddress(); + String address = redis.getHost(); Integer port = redis.getFirstMappedPort(); // Now we have an address and port for Redis, no matter where it is running diff --git a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy index c2537a948d5..068c8079a7d 100644 --- a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy +++ b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy @@ -15,7 +15,7 @@ class RedisBackedCacheIntTest extends Specification { // } void setup() { - String address = redis.containerIpAddress + String address = redis.host Integer port = redis.firstMappedPort // Now we have an address and port for Redis, no matter where it is running diff --git a/docs/features/networking.md b/docs/features/networking.md index 5de0c9dfa96..2fe039b74ef 100644 --- a/docs/features/networking.md +++ b/docs/features/networking.md @@ -33,23 +33,27 @@ There is also a `getFirstMappedPort` method for convenience, for the fairly comm [Retrieving the first mapped port](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchFirstMappedPort -## Getting the container IP address +## Getting the container host When running with a local Docker daemon, exposed ports will usually be reachable on `localhost`. However, in some CI environments they may instead be reachable on a different host. -As such, Testcontainers provides a convenience method to obtain an IP address on which the container should be reachable from the host machine. +As such, Testcontainers provides a convenience method to obtain an address on which the container should be reachable from the host machine. -[Getting the container IP address](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getContainerIpAddressOnly +[Getting the container host](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getHostOnly -It is normally advisable to use `getContainerIpAddress` and `getMappedPort` together when constructing addresses - for example: +It is normally advisable to use `getHost` and `getMappedPort` together when constructing addresses - for example: -[Getting the container IP address and mapped port](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getContainerIpAddressAndMappedPort +[Getting the container host and mapped port](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getHostAndMappedPort +!!! tip + `getHost()` is a replacement for `getContainerIpAddress()` and returns the same result. + `getContainerIpAddress()` is believed to be confusingly named, and will eventually be deprecated. + ## Exposing host ports to the container In some cases it is necessary to make a network connection from a container to a socket that is listening on the host machine. @@ -86,4 +90,4 @@ Docker provides the ability for you to create custom networks and place containe [Creating custom networks](../../core/src/test/java/org/testcontainers/containers/NetworkTest.java) inside_block:useCustomNetwork - \ No newline at end of file + diff --git a/docs/modules/vault.md b/docs/modules/vault.md index 43d8ff57468..1f58c0ab836 100644 --- a/docs/modules/vault.md +++ b/docs/modules/vault.md @@ -21,7 +21,7 @@ public class SomeTest { //There are many integration clients for Vault so let's just define a general one here: VaultClient client = new VaultClient( - vaultContainer.getContainerIpAddress(), + vaultContainer.getHost(), vaultContainer.getMappedPort(8200), "my-root-token"); diff --git a/docs/quickstart/junit_4_quickstart.md b/docs/quickstart/junit_4_quickstart.md index 86cd720942b..a3fecb1a14d 100644 --- a/docs/quickstart/junit_4_quickstart.md +++ b/docs/quickstart/junit_4_quickstart.md @@ -65,10 +65,10 @@ We can do this in our test `setUp` method, to set up our component under test: !!! tip - Notice that we also ask Testcontainers for the container's actual address with `redis.getContainerIpAddress();`, + Notice that we also ask Testcontainers for the container's actual address with `redis.getHost();`, rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use - `getContainerIpAddress()` instead. + `getHost()` instead. ## 4. Run the tests! diff --git a/docs/quickstart/junit_5_quickstart.md b/docs/quickstart/junit_5_quickstart.md index 179a87a5448..efd52b6c523 100644 --- a/docs/quickstart/junit_5_quickstart.md +++ b/docs/quickstart/junit_5_quickstart.md @@ -94,10 +94,10 @@ We can do this in our test `setUp` method, to set up our component under test: !!! tip - Notice that we also ask Testcontainers for the container's actual address with `redis.getContainerIpAddress();`, + Notice that we also ask Testcontainers for the container's actual address with `redis.getHost();`, rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use - `getContainerIpAddress()` instead. + `getHost()` instead. ## 4. Run the tests! diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index a78d23e4b4b..27c2f182e9e 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -161,7 +161,7 @@ public Cluster getCluster() { public static Cluster getCluster(ContainerState containerState, boolean enableJmxReporting) { final Cluster.Builder builder = Cluster.builder() - .addContactPoint(containerState.getContainerIpAddress()) + .addContactPoint(containerState.getHost()) .withPort(containerState.getMappedPort(CQL_PORT)); if (!enableJmxReporting) { builder.withoutJMXReporting(); diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java index 6105aa275c9..5bc68aa9972 100644 --- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java @@ -116,7 +116,7 @@ private void testInitScript(CassandraContainer cassandraContainer) { private ResultSet performQuery(CassandraContainer cassandraContainer, String cql) { Cluster explicitCluster = Cluster.builder() - .addContactPoint(cassandraContainer.getContainerIpAddress()) + .addContactPoint(cassandraContainer.getHost()) .withPort(cassandraContainer.getMappedPort(CassandraContainer.CQL_PORT)) .build(); return performQuery(explicitCluster, cql); diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 9364ecc4d14..4d4ea2d11a9 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -48,7 +48,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return JDBC_URL_PREFIX + getContainerIpAddress() + ":" + getMappedPort(HTTP_PORT) + "/" + databaseName; + return JDBC_URL_PREFIX + getHost() + ":" + getMappedPort(HTTP_PORT) + "/" + databaseName; } @Override diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index fb13ced60d7..3768ca7a008 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -43,7 +43,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return JDBC_URL_PREFIX + "://" + getContainerIpAddress() + ":" + getMappedPort(DB_PORT) + "/" + databaseName; + return JDBC_URL_PREFIX + "://" + getHost() + ":" + getMappedPort(DB_PORT) + "/" + databaseName; } @Override diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 14e5744bb6d..33f87359a92 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -141,7 +141,7 @@ public int getBootstrapHttpDirectPort() { } public String getConnectionString() { - return String.format("couchbase://%s:%d", getContainerIpAddress(), getBootstrapCarrierDirectPort()); + return String.format("couchbase://%s:%d", getHost(), getBootstrapCarrierDirectPort()); } @Override @@ -201,7 +201,7 @@ protected void containerIsStarting(final InspectContainerResponse containerInfo) @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { createBuckets(); - logger().info("Couchbase container is ready! UI available at http://{}:{}", getContainerIpAddress(), getMappedPort(MGMT_PORT)); + logger().info("Couchbase container is ready! UI available at http://{}:{}", getHost(), getMappedPort(MGMT_PORT)); } /** @@ -222,7 +222,7 @@ private void waitUntilNodeIsOnline() { * up automatically, we bind the internal hostname to the internal IP address. */ private void renameNode() { - logger().debug("Renaming Couchbase Node from localhost to {}", getContainerIpAddress()); + logger().debug("Renaming Couchbase Node from localhost to {}", getHost()); Response response = doHttpRequest(MGMT_PORT, "/node/controller/rename", "POST", new FormBody.Builder() .add("hostname", getInternalIpAddress()) @@ -284,7 +284,7 @@ private void configureExternalPorts() { logger().debug("Mapping external ports to the alternate address configuration"); final FormBody.Builder builder = new FormBody.Builder(); - builder.add("hostname", getContainerIpAddress()); + builder.add("hostname", getHost()); builder.add("mgmt", Integer.toString(getMappedPort(MGMT_PORT))); builder.add("mgmtSSL", Integer.toString(getMappedPort(MGMT_SSL_PORT))); @@ -418,7 +418,7 @@ private Response doHttpRequest(final int port, final String path, final String m final boolean auth) { try { Request.Builder requestBuilder = new Request.Builder() - .url("http://" + getContainerIpAddress() + ":" + getMappedPort(port) + path); + .url("http://" + getHost() + ":" + getMappedPort(port) + path); if (auth) { requestBuilder = requestBuilder.header("Authorization", Credentials.basic(username, password)); diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index 27ad0f6265a..c5c9f18a58b 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -53,7 +53,7 @@ public void testBasicContainerUsage() { Cluster cluster = CouchbaseCluster.create( environment, - container.getContainerIpAddress() + container.getHost() ); // } diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index 13ef72c328e..b1472b21c6c 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -1,20 +1,12 @@ package org.testcontainers.containers; -import com.github.dockerjava.api.command.InspectContainerResponse; -import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.WaitingConsumer; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.LicenseAcceptance; -import org.testcontainers.utility.LogUtils; -import java.io.IOException; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.TimeoutException; -import java.util.function.Predicate; public class Db2Container extends JdbcDatabaseContainer { @@ -81,7 +73,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:db2://" + getContainerIpAddress() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName; + return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName; } @Override diff --git a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java index 66397452921..6280ddb9421 100644 --- a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java +++ b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java @@ -46,7 +46,7 @@ public AmazonDynamoDB getClient() { */ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration() { return new AwsClientBuilder.EndpointConfiguration("http://" + - this.getContainerIpAddress() + ":" + + this.getHost() + ":" + this.getMappedPort(MAPPED_PORT), null); } diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index 3eb12969bed..e9a0b95d7ed 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -57,10 +57,10 @@ public ElasticsearchContainer(String dockerImageName) { } public String getHttpHostAddress() { - return getContainerIpAddress() + ":" + getMappedPort(ELASTICSEARCH_DEFAULT_PORT); + return getHost() + ":" + getMappedPort(ELASTICSEARCH_DEFAULT_PORT); } public InetSocketAddress getTcpHost() { - return new InetSocketAddress(getContainerIpAddress(), getMappedPort(ELASTICSEARCH_DEFAULT_TCP_PORT)); + return new InetSocketAddress(getHost(), getMappedPort(ELASTICSEARCH_DEFAULT_TCP_PORT)); } } diff --git a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java index c3ac909f2d4..68efc516504 100644 --- a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java +++ b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java @@ -131,7 +131,7 @@ public SELF withPassword(final String password) { * @return a url to influxDb */ public String getUrl() { - return "http://" + getContainerIpAddress() + ":" + getLivenessCheckPort(); + return "http://" + getHost() + ":" + getLivenessCheckPort(); } /** diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java index bae3885527d..177a48bb9d0 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java @@ -15,6 +15,6 @@ public RedisContainer(String dockerImageName) { } public Jedis getJedis() { - return new Jedis(getContainerIpAddress(), getMappedPort(6379)); + return new Jedis(getHost(), getMappedPort(6379)); } } diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 5aab0f52ffa..bb92f85b03c 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -88,7 +88,7 @@ public String getBootstrapServers() { if (port == PORT_NOT_ASSIGNED) { throw new IllegalStateException("You should start Kafka container first"); } - return String.format("PLAINTEXT://%s:%s", getContainerIpAddress(), port); + return String.format("PLAINTEXT://%s:%s", getHost(), port); } @Override diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index c649d322ead..96cedb37726 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -63,7 +63,7 @@ protected void configure() { withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getNetworkAliases().get(getNetworkAliases().size() - 1)); // use the last network alias set hostnameExternalReason = "to match last network alias on container with non-default network"; } else { - withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getContainerIpAddress()); + withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getHost()); hostnameExternalReason = "to match host-routable address for container"; } logger().info("{} environment variable set to {} ({})", HOSTNAME_EXTERNAL_ENV_VAR, getEnvMap().get(HOSTNAME_EXTERNAL_ENV_VAR), hostnameExternalReason); @@ -134,7 +134,7 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service s */ public URI getEndpointOverride(Service service) { try { - final String address = getContainerIpAddress(); + final String address = getHost(); String ipAddress = address; // resolve IP address and use that as the endpoint so that path-style access is automatically used for S3 ipAddress = InetAddress.getByName(address).getHostAddress(); diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index fb21dd9a1a9..1b4cb3344e4 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -60,7 +60,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:mariadb://" + getContainerIpAddress() + ":" + getMappedPort(MARIADB_PORT) + "/" + databaseName; + return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + "/" + databaseName; } @Override diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java index 4ddbed997d4..e37e9b0b6bf 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java @@ -23,7 +23,7 @@ public static ConnectionFactoryOptions getOptions(MariaDBContainer container) @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { return options.mutate() - .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MariaDBContainer.MARIADB_PORT)) .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) .option(ConnectionFactoryOptions.USER, container.getUsername()) diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index f1f9dc42d19..e35370f4b27 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -20,7 +20,7 @@ public MockServerContainer(String version) { } public String getEndpoint() { - return String.format("http://%s:%d", getContainerIpAddress(), getMappedPort(PORT)); + return String.format("http://%s:%d", getHost(), getMappedPort(PORT)); } public Integer getServerPort() { diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index be1495a04c7..91f740b4bd8 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -33,7 +33,7 @@ private static String responseFromMockserver(MockServerContainer mockServer, Str @Test public void shouldReturnExpectation() throws Exception { // testSimpleExpectation { - new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort()) + new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) .when(request() .withPath("/person") .withQueryStringParameter("name", "peter")) @@ -57,7 +57,7 @@ public void shouldCallActualMockserverVersion() throws Exception { String expectedBody = "Hello World!"; - new MockServerClient(mockServer.getContainerIpAddress(), mockServer.getServerPort()) + new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) .when(request().withPath("/hello")) .respond(response().withBody(expectedBody)); diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java index 27c486c218c..59c3ed0de68 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java @@ -23,7 +23,7 @@ public static ConnectionFactoryOptions getOptions(MSSQLServerContainer contai @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { return options.mutate() - .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MSSQLServerContainer.MS_SQL_SERVER_PORT)) // TODO enable if/when MSSQLServerContainer adds support for customizing the DB name // .option(ConnectionFactoryOptions.DATABASE, container.getDatabasseName()) diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index 2219a5aaf61..631228aeef2 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -62,7 +62,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:sqlserver://" + getContainerIpAddress() + ":" + getMappedPort(MS_SQL_SERVER_PORT); + return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT); } @Override diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index b8bbe225617..79d29234b99 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -70,7 +70,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:mysql://" + getContainerIpAddress() + ":" + getMappedPort(MYSQL_PORT) + "/" + databaseName; + return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + "/" + databaseName; } @Override diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java index c43ffcca1b2..274224352a8 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java @@ -23,7 +23,7 @@ public static ConnectionFactoryOptions getOptions(MySQLContainer container) { @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { return options.mutate() - .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MySQLContainer.MYSQL_PORT)) .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) .option(ConnectionFactoryOptions.USER, container.getUsername()) diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index 0c16927dba8..10545da43d6 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -111,21 +111,21 @@ protected void configure() { * @return Bolt URL for use with Neo4j's Java-Driver. */ public String getBoltUrl() { - return String.format("bolt://" + getContainerIpAddress() + ":" + getMappedPort(DEFAULT_BOLT_PORT)); + return String.format("bolt://" + getHost() + ":" + getMappedPort(DEFAULT_BOLT_PORT)); } /** * @return URL of the transactional HTTP endpoint. */ public String getHttpUrl() { - return String.format("http://" + getContainerIpAddress() + ":" + getMappedPort(DEFAULT_HTTP_PORT)); + return String.format("http://" + getHost() + ":" + getMappedPort(DEFAULT_HTTP_PORT)); } /** * @return URL of the transactional HTTPS endpoint. */ public String getHttpsUrl() { - return String.format("https://" + getContainerIpAddress() + ":" + getMappedPort(DEFAULT_HTTPS_PORT)); + return String.format("https://" + getHost() + ":" + getMappedPort(DEFAULT_HTTPS_PORT)); } /** diff --git a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java index bedf040869f..fb931bce409 100644 --- a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java +++ b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java @@ -33,7 +33,7 @@ protected Set getLivenessCheckPorts() { } public URL getBaseUrl(String scheme, int port) throws MalformedURLException { - return new URL(scheme + "://" + getContainerIpAddress() + ":" + getMappedPort(port)); + return new URL(scheme + "://" + getHost() + ":" + getMappedPort(port)); } public void setCustomContent(String htmlContentPath) { diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index e86768bc383..60603a7e222 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -64,7 +64,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:oracle:thin:" + getUsername() + "/" + getPassword() + "@" + getContainerIpAddress() + ":" + getOraclePort() + ":" + getSid(); + return "jdbc:oracle:thin:" + getUsername() + "/" + getPassword() + "@" + getHost() + ":" + getOraclePort() + ":" + getSid(); } @Override diff --git a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java index ca0180640ce..b7fcc85573a 100644 --- a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java +++ b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java @@ -108,7 +108,7 @@ public OrientDB getOrientDB() { } public String getServerUrl() { - return "remote:" + getContainerIpAddress() + ":" + getMappedPort(2424); + return "remote:" + getHost() + ":" + getMappedPort(2424); } public String getDbUrl() { diff --git a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java index 0a067b375b6..54b0661cae2 100644 --- a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java +++ b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java @@ -63,7 +63,7 @@ public void shouldInitializeDatabaseFromScript() { container.start(); assertThat(container.getDbUrl()) - .isEqualTo("remote:" + container.getContainerIpAddress() + ":" + container.getMappedPort(2424) + "/persons"); + .isEqualTo("remote:" + container.getHost() + ":" + container.getMappedPort(2424) + "/persons"); final ODatabaseSession session = container.getSession(); diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 06cdd7ebc8d..8634f9d70fa 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -68,7 +68,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { // Disable Postgres driver use of java.util.logging to reduce noise at startup time - return format("jdbc:postgresql://%s:%d/%s?loggerLevel=OFF", getContainerIpAddress(), getMappedPort(POSTGRESQL_PORT), databaseName); + return format("jdbc:postgresql://%s:%d/%s?loggerLevel=OFF", getHost(), getMappedPort(POSTGRESQL_PORT), databaseName); } @Override diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java index 9bfb9fdee05..88b5497f5d3 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java @@ -23,7 +23,7 @@ public static ConnectionFactoryOptions getOptions(PostgreSQLContainer contain @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { return options.mutate() - .option(ConnectionFactoryOptions.HOST, container.getContainerIpAddress()) + .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT)) .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) .option(ConnectionFactoryOptions.USER, container.getUsername()) diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index 3b887cedbec..05f6ea204a8 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -48,7 +48,7 @@ public void shouldRejectInvalidQueryString() { static class FixedJdbcUrlPostgreSQLContainer extends PostgreSQLContainer { @Override - public String getContainerIpAddress() { + public String getHost() { return "localhost"; } diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index 0f2a82b9b9d..56488525734 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -49,7 +49,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return format("jdbc:presto://%s:%s/%s", getContainerIpAddress(), getMappedPort(PRESTO_PORT), nullToEmpty(catalog)); + return format("jdbc:presto://%s:%s/%s", getHost(), getMappedPort(PRESTO_PORT), nullToEmpty(catalog)); } @Override diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 49f0437f95a..c9532979057 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -26,11 +26,11 @@ public PulsarContainer(String pulsarVersion) { } public String getPulsarBrokerUrl() { - return String.format("pulsar://%s:%s", getContainerIpAddress(), getMappedPort(BROKER_PORT)); + return String.format("pulsar://%s:%s", getHost(), getMappedPort(BROKER_PORT)); } public String getHttpServiceUrl() { - return String.format("http://%s:%s", getContainerIpAddress(), getMappedPort(BROKER_HTTP_PORT)); + return String.format("http://%s:%s", getHost(), getMappedPort(BROKER_HTTP_PORT)); } } diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index aba71e25a7e..49423201d14 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -114,28 +114,28 @@ public Integer getHttpPort() { * @return AMQP URL for use with AMQP clients. */ public String getAmqpUrl() { - return "amqp://" + getContainerIpAddress() + ":" + getAmqpPort(); + return "amqp://" + getHost() + ":" + getAmqpPort(); } /** * @return AMQPS URL for use with AMQPS clients. */ public String getAmqpsUrl() { - return "amqps://" + getContainerIpAddress() + ":" + getAmqpsPort(); + return "amqps://" + getHost() + ":" + getAmqpsPort(); } /** * @return URL of the HTTP management endpoint. */ public String getHttpUrl() { - return "http://" + getContainerIpAddress() + ":" + getHttpPort(); + return "http://" + getHost() + ":" + getHttpPort(); } /** * @return URL of the HTTPS management endpoint. */ public String getHttpsUrl() { - return "https://" + getContainerIpAddress() + ":" + getHttpsPort(); + return "https://" + getHost() + ":" + getHttpsPort(); } /** diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index 6f283c7451f..27ac38f55ce 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -49,13 +49,13 @@ public void shouldCreateRabbitMQContainer() container.start(); assertThat(container.getAmqpsUrl()).isEqualTo( - String.format("amqps://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQPS_PORT))); + String.format("amqps://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_AMQPS_PORT))); assertThat(container.getAmqpUrl()).isEqualTo( - String.format("amqp://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQP_PORT))); + String.format("amqp://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_AMQP_PORT))); assertThat(container.getHttpsUrl()).isEqualTo( - String.format("https://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTPS_PORT))); + String.format("https://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_HTTPS_PORT))); assertThat(container.getHttpUrl()).isEqualTo( - String.format("http://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTP_PORT))); + String.format("http://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_HTTP_PORT))); assertThat(container.getHttpsPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTPS_PORT)); assertThat(container.getHttpPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTP_PORT)); diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 49218dfb990..397f6c4a2cf 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -207,7 +207,7 @@ public static String getImageForCapabilities(Capabilities capabilities, String s public URL getSeleniumAddress() { try { - return new URL("http", getContainerIpAddress(), getMappedPort(SELENIUM_PORT), "/wd/hub"); + return new URL("http", getHost(), getMappedPort(SELENIUM_PORT), "/wd/hub"); } catch (MalformedURLException e) { e.printStackTrace();// TODO return null; @@ -216,7 +216,7 @@ public URL getSeleniumAddress() { @Override public String getVncAddress() { - return "vnc://vnc:secret@" + getContainerIpAddress() + ":" + getMappedPort(VNC_PORT); + return "vnc://vnc:secret@" + getHost() + ":" + getMappedPort(VNC_PORT); } @Override diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy index 014b25eac1f..5a12ce25b71 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy @@ -38,7 +38,7 @@ class TestcontainersSharedContainerIT extends Specification { } private CloseableHttpResponse performHttpRequest(CloseableHttpClient client) { - String ip = genericContainer.containerIpAddress + String ip = genericContainer.host String port = genericContainer.getMappedPort(80) def response = client.execute(new HttpGet("http://$ip:$port")) response diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index 1b631fa9d6d..f2915b5af11 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -47,7 +47,7 @@ public ToxiproxyContainer(String imageName) { @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { - client = new ToxiproxyClient(getContainerIpAddress(), getMappedPort(TOXIPROXY_CONTROL_PORT)); + client = new ToxiproxyClient(getHost(), getMappedPort(TOXIPROXY_CONTROL_PORT)); } /** @@ -88,7 +88,7 @@ public ContainerProxy getProxy(String hostname, int port) { final Proxy proxy = client.createProxy(upstream, "0.0.0.0:" + toxiPort, upstream); final int mappedPort = getMappedPort(toxiPort); - return new ContainerProxy(proxy, getContainerIpAddress(), mappedPort, toxiPort); + return new ContainerProxy(proxy, getHost(), mappedPort, toxiPort); } catch (IOException e) { throw new RuntimeException("Proxy could not be created", e); } diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index 366f425b5b5..d76851f57b5 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -40,7 +40,7 @@ public class ToxiproxyTest { @Test public void testDirect() { - final Jedis jedis = createJedis(redis.getContainerIpAddress(), redis.getFirstMappedPort()); + final Jedis jedis = createJedis(redis.getHost(), redis.getFirstMappedPort()); jedis.set("somekey", "somevalue"); final String s = jedis.get("somekey"); diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java index 8091980d234..dfe73cae4b9 100644 --- a/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java @@ -5,7 +5,6 @@ import com.bettercloud.vault.VaultException; import com.bettercloud.vault.response.LogicalResponse; import org.junit.Test; -import org.testcontainers.containers.wait.strategy.Wait; import java.util.HashMap; import java.util.Map; @@ -26,7 +25,7 @@ public void writeAndReadMultipleValues() throws VaultException { vaultContainer.start(); final VaultConfig config = new VaultConfig() - .address("http://" + vaultContainer.getContainerIpAddress() + ":" + vaultContainer.getFirstMappedPort()) + .address("http://" + vaultContainer.getHost() + ":" + vaultContainer.getFirstMappedPort()) .token(VAULT_TOKEN) .build(); diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java index fae9209c8e7..d7ac5ca8686 100644 --- a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java @@ -71,7 +71,7 @@ public void readSecondSecretPathOverHttpApi() throws InterruptedException { } private String getHostAndPort() { - return vaultContainer.getContainerIpAddress() + ":" + vaultContainer.getMappedPort(8200); + return vaultContainer.getHost() + ":" + vaultContainer.getMappedPort(8200); } From 1eef935529564c0f2df1384bd5d55999f849bf5c Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 15 May 2020 15:14:28 +0200 Subject: [PATCH 0731/4969] Store `GenericContainer#exposedPorts` as an order-preserving `Set` (#2613) * Store `GenericContainer#exposedPorts` as an order-preserving `Set` * Update core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java Co-authored-by: Richard North Co-authored-by: Richard North --- .../containers/GenericContainer.java | 18 +++++++++++++++--- .../junit/GenericContainerRuleTest.java | 9 +++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 89938cdfe56..d906c320bd5 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -77,6 +77,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -118,7 +119,7 @@ public class GenericContainer> * Default settings */ @NonNull - private List exposedPorts = new ArrayList<>(); + private LinkedHashSet exposedPorts = new LinkedHashSet<>(); @NonNull private List portBindings = new ArrayList<>(); @@ -256,6 +257,16 @@ public void setImage(Future image) { this.image = new RemoteDockerImage(image); } + @Override + public List getExposedPorts() { + return new ArrayList<>(exposedPorts); + } + + @Override + public void setExposedPorts(List exposedPorts) { + this.exposedPorts = new LinkedHashSet<>(exposedPorts); + } + /** * @see #dependsOn(Iterable) */ @@ -671,8 +682,9 @@ protected void containerIsStopped(InspectContainerResponse containerInfo) { @Deprecated protected Integer getLivenessCheckPort() { // legacy implementation for backwards compatibility - if (exposedPorts.size() > 0) { - return getMappedPort(exposedPorts.get(0)); + Iterator exposedPortsIterator = exposedPorts.iterator(); + if (exposedPortsIterator.hasNext()) { + return getMappedPort(exposedPortsIterator.next()); } else if (portBindings.size() > 0) { return Integer.valueOf(PortBinding.parse(portBindings.get(0)).getBinding().getHostPortSpec()); } else { diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index 1f4a3ff121d..b450244a84d 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -379,6 +379,15 @@ public void addExposedPortAfterWithExposedPortsTest() { assertTrue("addExposedPort should be exposed", redis.getExposedPorts().contains(8987)); } + @Test + public void addingExposedPortTwiceShouldNotFail() { + redis.addExposedPort(8987); + redis.addExposedPort(8987); + assertThat("Both ports should be exposed", redis.getExposedPorts().size(), equalTo(2)); // 2 ports = de-duplicated port 8897 and original port 6379 + assertTrue("withExposedPort should be exposed", redis.getExposedPorts().contains(REDIS_PORT)); + assertTrue("addExposedPort should be exposed", redis.getExposedPorts().contains(8987)); + } + @Test public void sharedMemorySetTest() { try (GenericContainer containerWithSharedMemory = new GenericContainer() From 8c7c769cdfd3848457e0a70de8518f08ad7053b4 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 16 May 2020 20:43:00 +0100 Subject: [PATCH 0732/4969] Dynamic CI jobs for examples (#2677) --- .../{ci-dind.yml => ci-docker-wormhole.yml} | 2 +- .github/workflows/ci-examples.yml | 73 +++++++++++++++++++ .github/workflows/ci.yml | 27 ------- examples/build.gradle | 5 ++ examples/settings.gradle | 36 +++++++++ gradle/ci-support.gradle | 6 +- settings.gradle | 38 +++++----- 7 files changed, 137 insertions(+), 50 deletions(-) rename .github/workflows/{ci-dind.yml => ci-docker-wormhole.yml} (96%) create mode 100644 .github/workflows/ci-examples.yml diff --git a/.github/workflows/ci-dind.yml b/.github/workflows/ci-docker-wormhole.yml similarity index 96% rename from .github/workflows/ci-dind.yml rename to .github/workflows/ci-docker-wormhole.yml index 15bd5ec76ee..3c6da54dc1f 100644 --- a/.github/workflows/ci-dind.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -1,4 +1,4 @@ -name: in-container +name: CI-Docker-Wormhole on: pull_request: {} diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml new file mode 100644 index 00000000000..bec794dc167 --- /dev/null +++ b/.github/workflows/ci-examples.yml @@ -0,0 +1,73 @@ +name: CI-Examples + +on: + pull_request: {} + push: { branches: [ master ] } + +env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + +jobs: + find_gradle_jobs: + runs-on: ubuntu-18.04 + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '1.8' + - name: Cache Gradle Home files + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-home-testmatrix-examples-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle-home-testmatrix-examples- + ${{ runner.os }}-gradle-home- + - id: set-matrix + working-directory: ./examples/ + env: + # Since we override the tests executor, + # we should not push empty results to the cache + READ_ONLY_REMOTE_GRADLE_CACHE: true + run: | + TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) + echo $TASKS + echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" + check: + needs: find_gradle_jobs + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '1.8' + - name: Cache Gradle Home files + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check- + ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check- + ${{ runner.os }}-gradle-home-examples- + - name: Clear existing docker image cache + run: docker image prune -af + - name: Build and test Examples with Gradle (${{matrix.gradle_args}}) + working-directory: ./examples/ + run: | + ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} + - name: Aggregate Examples test reports with ciMate + if: always() + env: + CIMATE_PROJECT_ID: 2348n4vl + CIMATE_CI_KEY: "Examples / ${{ runner.os }} / ${{matrix.gradle_args}}" + run: | + wget -q https://get.cimate.io/release/linux/cimate + chmod +x cimate + ./cimate "**/TEST-*.xml" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6baaf7e92d..90e64dde133 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,30 +69,3 @@ jobs: wget -q https://get.cimate.io/release/linux/cimate chmod +x cimate ./cimate "**/TEST-*.xml" - examples: - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: '1.8' - - name: Cache Gradle Home files - uses: actions/cache@v1 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-home-examples-${{ hashFiles('**/*.gradle*') }} - restore-keys: | - ${{ runner.os }}-gradle-home-examples- - - name: Build and test Examples with Gradle - working-directory: ./examples/ - run: | - ./gradlew --no-daemon --scan --info check - - name: Aggregate test reports with ciMate - if: always() - env: - CIMATE_PROJECT_ID: 2348n4vl - CIMATE_CI_KEY: examples - run: | - wget -q https://get.cimate.io/release/linux/cimate - chmod +x cimate - ./cimate "**/TEST-*.xml" diff --git a/examples/build.gradle b/examples/build.gradle index b2ecf1b0be3..25b7c1fcf29 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -1 +1,6 @@ // empty build.gradle for dependabot +apply from: "$rootDir/../gradle/ci-support.gradle" + +subprojects { + apply plugin:"java" +} diff --git a/examples/settings.gradle b/examples/settings.gradle index ef47a61f807..25da14a0931 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -1,3 +1,18 @@ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.2.1" + } +} + +apply plugin: 'ch.myniva.s3-build-cache' +apply plugin: 'com.gradle.enterprise' + rootProject.name = 'testcontainers-examples' includeBuild '..' @@ -15,3 +30,24 @@ include 'spring-boot' include 'cucumber' include 'spring-boot-kotlin-redis' include 'spock' + +ext.isMasterBuild = false || + (System.getenv("GITHUB_REF") == "refs/heads/master") || + (System.getenv("BUILD_SOURCEBRANCHNAME") == "master") + +buildCache { + local { + enabled = !isMasterBuild + } + + remote(ch.myniva.gradle.caching.s3.AwsS3BuildCache) { + endpoint = 'fra1.digitaloceanspaces.com' + region = 'fra1' + bucket = 'testcontainers' + path = 'cache' + push = isMasterBuild && !System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") + headers = [ + 'x-amz-acl': 'public-read' + ] + } +} diff --git a/gradle/ci-support.gradle b/gradle/ci-support.gradle index 7c3408068b3..e83c936f2f3 100644 --- a/gradle/ci-support.gradle +++ b/gradle/ci-support.gradle @@ -28,9 +28,9 @@ gradle.taskGraph.whenReady { subproject.tasks.withType(Test).all { testExecuter([execute: { spec, processor -> }, stopNow:{}] as org.gradle.api.internal.tasks.testing.TestExecuter) } - subproject.tasks.findByName("shadowJar").enabled = false - subproject.tasks.findByName("javadoc").enabled = false - subproject.tasks.findByName("delombok").enabled = false + subproject.tasks.findByName("shadowJar")?.enabled = false + subproject.tasks.findByName("javadoc")?.enabled = false + subproject.tasks.findByName("delombok")?.enabled = false subproject.tasks.findByName("japicmp")?.enabled = false } } diff --git a/settings.gradle b/settings.gradle index 150d79f89fe..2ea21599ceb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,6 +13,25 @@ buildscript { apply plugin: 'ch.myniva.s3-build-cache' apply plugin: 'com.gradle.enterprise' +rootProject.name = 'testcontainers-java' + +include "bom" + +include "testcontainers" +project(':testcontainers').projectDir = "$rootDir/core" as File + +file('modules').eachDir { dir -> + include dir.name + project(":${dir.name}").projectDir = dir +} + +include ':docs:examples:junit4:generic' +include ':docs:examples:junit4:redis' +include ':docs:examples:junit5:redis' +include ':docs:examples:spock:redis' + +include 'test-support' + ext.isMasterBuild = false || (System.getenv("GITHUB_REF") == "refs/heads/master") || (System.getenv("BUILD_SOURCEBRANCHNAME") == "master") @@ -34,25 +53,6 @@ buildCache { } } -rootProject.name = 'testcontainers-java' - -include "bom" - -include "testcontainers" -project(':testcontainers').projectDir = "$rootDir/core" as File - -file('modules').eachDir { dir -> - include dir.name - project(":${dir.name}").projectDir = dir -} - -include ':docs:examples:junit4:generic' -include ':docs:examples:junit4:redis' -include ':docs:examples:junit5:redis' -include ':docs:examples:spock:redis' - -include 'test-support' - gradleEnterprise { buildScan { termsOfServiceUrl = 'https://gradle.com/terms-of-service' From bf233cd62b610491f9007c7aa94e087298f0109b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 16 May 2020 21:49:03 +0100 Subject: [PATCH 0733/4969] Bump testcontainers from 1.14.1 to 1.14.2 in /core (#2751) --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 39495e59dce..48bbf57d7e9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -104,7 +104,7 @@ if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { } dependencies { - baseline 'org.testcontainers:testcontainers:1.14.1', { + baseline 'org.testcontainers:testcontainers:1.14.2', { exclude group: "*", module: "*" } From 1e0625cea385f8c1e1864a365a471ac7dcdd86a2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 16 May 2020 21:49:27 +0100 Subject: [PATCH 0734/4969] Bump guava from 28.2-jre to 29.0-jre in /modules/jdbc-test (#2754) --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 8b36f126b86..df9c26fcd72 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -2,7 +2,7 @@ dependencies { compile project(':jdbc') compile project(':test-support') - compile 'com.google.guava:guava:28.2-jre' + compile 'com.google.guava:guava:29.0-jre' compile 'org.apache.commons:commons-lang3:3.10' compile 'com.zaxxer:HikariCP-java6:2.3.13' compile 'commons-dbutils:commons-dbutils:1.7' From e465f5d836922a1b3f5853a65a57d349574f62e3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 16 May 2020 21:49:45 +0100 Subject: [PATCH 0735/4969] Bump mssql-jdbc from 8.2.2.jre8 to 8.3.0.jre8-preview in /modules/mssqlserver (#2755) --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 5d72209b27e..8cdfa35dee1 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.2.RELEASE' testCompile project(':jdbc-test') - testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.2.2.jre8' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.0.jre8-preview' testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' From 421f67bff6b5d814ec4b92c7c9b6086e00e4c886 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 16 May 2020 21:50:25 +0100 Subject: [PATCH 0736/4969] Bump tomcat-jdbc from 9.0.33 to 9.0.35 in /modules/jdbc (#2744) --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index aa21939c769..1cfdeab73b2 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.33' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.35' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' } From 6b6feeb39baf0328628925821bbb40a90e7dafbd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 16 May 2020 21:51:05 +0100 Subject: [PATCH 0737/4969] Bump tomcat-jdbc from 9.0.33 to 9.0.35 in /modules/jdbc-test (#2752) --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index df9c26fcd72..eb3e4ed222d 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -15,7 +15,7 @@ dependencies { } compile 'commons-dbutils:commons-dbutils:1.7' - compile 'org.apache.tomcat:tomcat-jdbc:9.0.33' + compile 'org.apache.tomcat:tomcat-jdbc:9.0.35' compile 'org.vibur:vibur-dbcp:25.0' compile 'mysql:mysql-connector-java:8.0.19' } From 2a9b875fcad74251abad8c7b874714ad17e9082e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 16 May 2020 21:51:19 +0100 Subject: [PATCH 0738/4969] Bump mysql-connector-java from 8.0.19 to 8.0.20 in /modules/jdbc-test (#2750) --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index eb3e4ed222d..23564279332 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -17,5 +17,5 @@ dependencies { compile 'commons-dbutils:commons-dbutils:1.7' compile 'org.apache.tomcat:tomcat-jdbc:9.0.35' compile 'org.vibur:vibur-dbcp:25.0' - compile 'mysql:mysql-connector-java:8.0.19' + compile 'mysql:mysql-connector-java:8.0.20' } From 3bdd665048b3a7f13d6c2acf75f687a4f076f50a Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 17 May 2020 06:45:03 +0100 Subject: [PATCH 0739/4969] Add gradle.properties to examples to enable caching --- examples/gradle.properties | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 examples/gradle.properties diff --git a/examples/gradle.properties b/examples/gradle.properties new file mode 100644 index 00000000000..dad41a4425a --- /dev/null +++ b/examples/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.parallel=false +org.gradle.caching=true From 4450294c6cd2a01233f1baa2ba9723c5c1c2ef54 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 17 May 2020 07:17:43 +0100 Subject: [PATCH 0740/4969] Bump aws-java-sdk-s3 from 1.11.782 to 1.11.784 in /modules/localstack (#2747) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3f88f41c176..67b9d6e79f8 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.782' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.782' From a1a8c4c212587692fcf64dd9cd0b8336a7aff4ea Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 17 May 2020 07:35:37 +0100 Subject: [PATCH 0741/4969] Bump aws-java-sdk-sqs from 1.11.782 to 1.11.784 in /modules/localstack (#2746) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 67b9d6e79f8..9b4133c6d4d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.782' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.782' testCompile 'software.amazon.awssdk:s3:2.13.16' } From 0fafaa909e5b2f434b5846dfc8719d0460cac779 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 17 May 2020 07:35:45 +0100 Subject: [PATCH 0742/4969] Bump solr-solrj from 8.3.0 to 8.5.1 in /examples (#2749) --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 62ed7d1153a..7e9b7a8c71f 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.10" annotationProcessor "org.projectlombok:lombok:1.18.10" - implementation 'org.apache.solr:solr-solrj:8.3.0' + implementation 'org.apache.solr:solr-solrj:8.5.1' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From f88eb3f4f28b5b74bdb725e143a9db89c72afbfb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 17 May 2020 07:35:56 +0100 Subject: [PATCH 0743/4969] Bump org.springframework.boot from 2.2.7.RELEASE to 2.3.0.RELEASE in /examples (#2753) --- examples/selenium-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 04888a55c65..49e015f1af3 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.2.7.RELEASE' + id 'org.springframework.boot' version '2.3.0.RELEASE' } apply plugin: 'io.spring.dependency-management' From eb30647d19ceb87c0303e40341a4dd6dd28f9c81 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 17 May 2020 07:36:08 +0100 Subject: [PATCH 0744/4969] Bump s3 from 2.13.16 to 2.13.18 in /modules/localstack (#2748) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9b4133c6d4d..482b977792d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.782' - testCompile 'software.amazon.awssdk:s3:2.13.16' + testCompile 'software.amazon.awssdk:s3:2.13.18' } From 206c5f65482475e14e9fc1eba5edd7d20ae25aea Mon Sep 17 00:00:00 2001 From: "Roman S.A" Date: Thu, 21 May 2020 18:36:24 +0300 Subject: [PATCH 0745/4969] Added additional url params in JdbcDatabaseContainer (#1802) (#1874) --- .../containers/ClickHouseContainer.java | 4 + .../containers/CockroachContainer.java | 4 +- .../cockroachdb/SimpleCockroachDBTest.java | 20 +++++ .../containers/Db2Container.java | 4 +- .../junit/db2/SimpleDb2Test.java | 15 ++++ .../containers/JdbcDatabaseContainer.java | 23 +++++ .../containers/MariaDBContainer.java | 4 +- .../junit/mariadb/SimpleMariaDBTest.java | 20 +++++ .../containers/MSSQLServerContainer.java | 3 +- .../mssqlserver/SimpleMSSQLServerTest.java | 16 ++++ .../containers/MySQLContainer.java | 6 +- .../junit/mysql/SimpleMySQLTest.java | 83 ++++++++++++++++++- .../containers/OracleContainer.java | 5 ++ .../containers/PostgreSQLContainer.java | 24 ++---- .../PostgreSQLConnectionURLTest.java | 2 +- .../postgresql/SimplePostgreSQLTest.java | 15 ++++ 16 files changed, 222 insertions(+), 26 deletions(-) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 4d4ea2d11a9..10c0e1835c2 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -66,4 +66,8 @@ public String getTestQueryString() { return TEST_QUERY; } + @Override + public ClickHouseContainer withUrlParam(String paramName, String paramValue) { + throw new UnsupportedOperationException("The ClickHouse does not support this"); + } } diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index 3768ca7a008..de64902c88a 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -43,7 +43,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return JDBC_URL_PREFIX + "://" + getHost() + ":" + getMappedPort(DB_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters("?", "&"); + return JDBC_URL_PREFIX + "://" + getHost() + ":" + getMappedPort(DB_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java index 7c62b2f6bcf..14fe20222a3 100644 --- a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java +++ b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java @@ -9,6 +9,8 @@ import java.util.logging.Level; import java.util.logging.LogManager; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleCockroachDBTest extends AbstractContainerDatabaseTest { @@ -42,4 +44,22 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + CockroachContainer cockroach = new CockroachContainer() + .withUrlParam("sslmode", "disable") + .withUrlParam("application_name", "cockroach"); + + try { + cockroach.start(); + String jdbcUrl = cockroach.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("sslmode=disable")); + assertThat(jdbcUrl, containsString("application_name=cockroach")); + } finally { + cockroach.stop(); + } + } } diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index b1472b21c6c..05edcb2c3ed 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -73,7 +73,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters(":", ";", ";"); + return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java index 08f427cf12b..6cc7535f785 100644 --- a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -7,6 +7,8 @@ import java.sql.ResultSet; import java.sql.SQLException; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleDb2Test extends AbstractContainerDatabaseTest { @@ -24,4 +26,17 @@ public void testSimple() throws SQLException { assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + try (Db2Container db2 = new Db2Container() + .withUrlParam("sslConnection", "false") + .acceptLicense()) { + + db2.start(); + + String jdbcUrl = db2.getJdbcUrl(); + assertThat(jdbcUrl, containsString(":sslConnection=false;")); + } + } } diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 36a6461aa74..6c265bc6943 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import lombok.NonNull; +import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.delegate.DatabaseDelegate; @@ -17,6 +18,8 @@ import java.util.Properties; import java.util.concurrent.Future; +import static java.util.stream.Collectors.joining; + /** * Base class for containers that expose a JDBC connection * @@ -28,6 +31,7 @@ public abstract class JdbcDatabaseContainer parameters = new HashMap<>(); + protected Map urlParameters = new HashMap<>(); private int startupTimeoutSeconds = 120; private int connectTimeoutSeconds = 120; @@ -82,7 +86,11 @@ public SELF withPassword(String password) { public SELF withDatabaseName(String dbName) { throw new UnsupportedOperationException(); + } + public SELF withUrlParam(String paramName, String paramValue) { + urlParameters.put(paramName, paramValue); + return self(); } /** @@ -223,6 +231,21 @@ protected String constructUrlForConnection(String queryString) { return getJdbcUrl() + queryString; } + protected String constructUrlParameters(String startCharacter, String delimiter) { + return constructUrlParameters(startCharacter, delimiter, StringUtils.EMPTY); + } + + protected String constructUrlParameters(String startCharacter, String delimiter, String endCharacter) { + String urlParameters = ""; + if (!this.urlParameters.isEmpty()) { + String additionalParameters = this.urlParameters.entrySet().stream() + .map(Object::toString) + .collect(joining(delimiter)); + urlParameters = startCharacter + additionalParameters + endCharacter; + } + return urlParameters; + } + protected void optionallyMapResourceParameterAsVolume(@NotNull String paramName, @NotNull String pathNameInContainer, @NotNull String defaultResource) { String resourceName = parameters.getOrDefault(paramName, defaultResource); diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index 1b4cb3344e4..04d745a9efe 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -60,7 +60,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index 646fbb40947..af503ce424b 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -8,6 +8,8 @@ import java.sql.ResultSet; import java.sql.SQLException; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; @@ -68,4 +70,22 @@ public void testMariaDBWithCommandOverride() throws SQLException { assertEquals("Auto increment increment should be overriden by command line", "10", result); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + MariaDBContainer mariaDBContainer = (MariaDBContainer) new MariaDBContainer() + .withUrlParam("connectTimeout", "40000") + .withUrlParam("rewriteBatchedStatements", "true"); + + try { + mariaDBContainer.start(); + String jdbcUrl = mariaDBContainer.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); + assertThat(jdbcUrl, containsString("connectTimeout=40000")); + } finally { + mariaDBContainer.stop(); + } + } } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index 631228aeef2..b500e6fddf0 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -62,7 +62,8 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT); + String additionalUrlParams = constructUrlParameters(";", ";"); + return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT) + additionalUrlParams; } @Override diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index c1699d2473a..71e12a6d864 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -9,6 +9,8 @@ import java.sql.SQLException; import java.sql.Statement; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { @@ -24,6 +26,20 @@ public void testSimple() throws SQLException { } } + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>() + .withUrlParam("integratedSecurity", "false") + .withUrlParam("applicationName", "MyApp")) { + + mssqlServer.start(); + + String jdbcUrl = mssqlServer.getJdbcUrl(); + assertThat(jdbcUrl, containsString(";integratedSecurity=false;applicationName=MyApp")); + } + } + + @Test public void testSetupDatabase() throws SQLException { try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>()) { diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 79d29234b99..1ef574cbd5e 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -5,6 +5,8 @@ import java.util.HashSet; import java.util.Set; +import static java.util.stream.Collectors.joining; + /** * @author richardnorth */ @@ -70,7 +72,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index ee6c3ab6993..6d6f8d26453 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -9,9 +9,17 @@ import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.db.AbstractContainerDatabaseTest; +import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; - +import java.sql.Statement; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; @@ -142,4 +150,77 @@ public void testEmptyPasswordWithRootUser() throws SQLException { assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } + + @Test + public void testWithAdditionalUrlParamTimeZone() throws SQLException { + MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + .withUrlParam("serverTimezone", "Europe/Zurich") + .withEnv("TZ", "Europe/Zurich") + .withLogConsumer(new Slf4jLogConsumer(logger)); + mysql.start(); + + try(Connection connection = mysql.createConnection("")) { + Statement statement = connection.createStatement(); + statement.execute("SELECT NOW();"); + try (ResultSet resultSet = statement.getResultSet()) { + resultSet.next(); + + // checking that the time_zone MySQL is Europe/Zurich + LocalDateTime localDateTime = resultSet.getObject(1, LocalDateTime.class); + ZonedDateTime actualDateTime = localDateTime.atZone(ZoneId.of("Europe/Zurich")) + .truncatedTo(ChronoUnit.MINUTES); + ZonedDateTime expectedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Zurich")) + .truncatedTo(ChronoUnit.MINUTES); + + String message = String.format("MySQL time zone is not Europe/Zurich. MySQL date:%s, current date:%s", + actualDateTime, expectedDateTime); + assertTrue(message, actualDateTime.equals(expectedDateTime)); + } + } finally { + mysql.stop(); + } + } + + @Test + public void testWithAdditionalUrlParamMultiQueries() throws SQLException { + MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + .withUrlParam("allowMultiQueries", "true") + .withLogConsumer(new Slf4jLogConsumer(logger)); + mysql.start(); + + try(Connection connection = mysql.createConnection("")) { + Statement statement = connection.createStatement(); + String multiQuery = "DROP TABLE IF EXISTS bar; " + + "CREATE TABLE bar (foo VARCHAR(20)); " + + "INSERT INTO bar (foo) VALUES ('hello world');"; + statement.execute(multiQuery); + statement.execute("SELECT foo FROM bar;"); + try(ResultSet resultSet = statement.getResultSet()) { + resultSet.next(); + String firstColumnValue = resultSet.getString(1); + assertEquals("Value from bar should equal real value", "hello world", firstColumnValue); + } + } finally { + mysql.stop(); + } + } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + .withUrlParam("allowMultiQueries", "true") + .withUrlParam("rewriteBatchedStatements", "true") + .withLogConsumer(new Slf4jLogConsumer(logger)); + + try { + mysql.start(); + String jdbcUrl = mysql.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); + assertThat(jdbcUrl, containsString("allowMultiQueries=true")); + } finally { + mysql.stop(); + } + } } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index 60603a7e222..d263a141d4f 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -89,6 +89,11 @@ public OracleContainer withPassword(String password) { return self(); } + @Override + public OracleContainer withUrlParam(String paramName, String paramValue) { + throw new UnsupportedOperationException("The OracleDb does not support this"); + } + @SuppressWarnings("SameReturnValue") public String getSid() { return "xe"; diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 8634f9d70fa..6ba7390878e 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -55,6 +55,8 @@ protected Set getLivenessCheckPorts() { @Override protected void configure() { + // Disable Postgres driver use of java.util.logging to reduce noise at startup time + withUrlParam("loggerLevel", "OFF"); addEnv("POSTGRES_DB", databaseName); addEnv("POSTGRES_USER", username); addEnv("POSTGRES_PASSWORD", password); @@ -67,25 +69,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - // Disable Postgres driver use of java.util.logging to reduce noise at startup time - return format("jdbc:postgresql://%s:%d/%s?loggerLevel=OFF", getHost(), getMappedPort(POSTGRESQL_PORT), databaseName); - } - - @Override - protected String constructUrlForConnection(String queryString) { - String baseUrl = getJdbcUrl(); - - if ("".equals(queryString)) { - return baseUrl; - } - - if (!queryString.startsWith("?")) { - throw new IllegalArgumentException("The '?' character must be included"); - } - - return baseUrl.contains("?") - ? baseUrl + QUERY_PARAM_SEPARATOR + queryString.substring(1) - : baseUrl + queryString; + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index 05f6ea204a8..c0ba7e40d44 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -15,7 +15,7 @@ public void shouldCorrectlyAppendQueryString() { String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); - assertTrue("Query String contains expected params", queryString.contains("&stringtype=unspecified&stringtype=unspecified")); + assertTrue("Query String contains expected params", queryString.contains("?stringtype=unspecified&stringtype=unspecified")); assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); } diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 9c97f51e64e..36ece03b604 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -9,6 +9,8 @@ import java.util.logging.Level; import java.util.logging.LogManager; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; @@ -63,4 +65,17 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>() + .withUrlParam("charSet", "UNICODE")) { + + postgres.start(); + String jdbcUrl = postgres.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("charSet=UNICODE")); + } + } } From c0fc42ff60bdf639ce28ab6dc3d97117548f1e0a Mon Sep 17 00:00:00 2001 From: vcvitaly Date: Thu, 21 May 2020 20:02:23 +0300 Subject: [PATCH 0746/4969] Add docs for startup strategy information/examples (#1157) (#2565) * Add startup strategy information/examples to mkdocs #1157 * Update docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java Co-authored-by: Sergei Egorov Co-authored-by: Richard North --- docs/examples/junit4/generic/build.gradle | 1 + .../StartupCheckStrategyTest.java | 90 +++++++++++++++++++ docs/features/startup_and_waits.md | 49 ++++++++++ 3 files changed, 140 insertions(+) create mode 100644 docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle index 97902d5d9ca..5ce878c7ba2 100644 --- a/docs/examples/junit4/generic/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -5,4 +5,5 @@ dependencies { testCompile project(":testcontainers") testCompile project(":selenium") testCompile "org.seleniumhq.selenium:selenium-api:3.141.59" + testCompile 'org.assertj:assertj-core:3.15.0' } diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java new file mode 100644 index 00000000000..5ab32919bb2 --- /dev/null +++ b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java @@ -0,0 +1,90 @@ +package org.testcontainers.containers.startupcheck; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import lombok.SneakyThrows; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.WaitingConsumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; +import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.IndefiniteOneShotStrategyTest; +import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.MinimumDurationStrategyTest; +import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.OneShotStrategyTest; + +@RunWith(Suite.class) +@Suite.SuiteClasses({OneShotStrategyTest.class, IndefiniteOneShotStrategyTest.class, MinimumDurationStrategyTest.class}) +public class StartupCheckStrategyTest { + + private static final String HELLO_TESTCONTAINERS = "Hello Testcontainers!"; + + private static void waitForHello(GenericContainer container) throws TimeoutException { + WaitingConsumer consumer = new WaitingConsumer(); + container.followOutput(consumer, STDOUT); + + consumer.waitUntil(frame -> + frame.getUtf8String().contains(HELLO_TESTCONTAINERS), 30, TimeUnit.SECONDS); + } + + public static class OneShotStrategyTest { + @Rule + // withOneShotStrategy { + public GenericContainer bboxWithOneShot = new GenericContainer("busybox:1.31.1") + .withCommand(String.format("echo %s", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(3)) + ); + // } + + @SneakyThrows + @Test + public void testCommandIsExecuted() { + waitForHello(bboxWithOneShot); + + assertThat(bboxWithOneShot.isRunning()).isFalse(); + } + } + + public static class IndefiniteOneShotStrategyTest { + @Rule + // withIndefiniteOneShotStrategy { + public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer("busybox:1.31.1") + .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new IndefiniteWaitOneShotStartupCheckStrategy() + ); + // } + + @SneakyThrows + @Test + public void testCommandIsExecuted() { + waitForHello(bboxWithIndefiniteOneShot); + + assertThat(bboxWithIndefiniteOneShot.isRunning()).isFalse(); + } + } + + public static class MinimumDurationStrategyTest { + @Rule + // withMinimumDurationStrategy { + public GenericContainer bboxWithMinimumDuration = new GenericContainer("busybox:1.31.1") + .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(5)) + ); + // } + + @SneakyThrows + @Test + public void testCommandIsExecuted() { + waitForHello(bboxWithMinimumDuration); + + assertThat(bboxWithMinimumDuration.isRunning()).isTrue(); + } + } +} diff --git a/docs/features/startup_and_waits.md b/docs/features/startup_and_waits.md index e1d30457e5c..3cbec97af0d 100644 --- a/docs/features/startup_and_waits.md +++ b/docs/features/startup_and_waits.md @@ -74,3 +74,52 @@ If none of these options meet your requirements, you can create your own subclas appropriate wait mechanism in `waitUntilReady()`. The `GenericContainer.waitingFor()` method accepts any valid [`WaitStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/wait/strategy/WaitStrategy.html). + +## Startup check Strategies + +Ordinarily Testcontainers will check that the container has reached the running state and has not exited. +In order to do that inspect is executed against the container and state parameter is extracted. + +All logic is implemented in [`StartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/startupcheck/StartupCheckStrategy.html) child classes. + +### Running startup strategy example + +This is the strategy used by default. Testcontainers just checks if container is running. + +Implemented in [`IsRunningStartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.html) class. + +### One shot startup strategy example + +This strategy is intended for use with containers that only run briefly and exit of their own accord. As such, success is deemed to be when +the container has stopped with exit code 0. + + +[Using one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withOneShotStrategy + + +### Indefinite one shot startup strategy example + +Variant of one shot strategy that does not impose a timeout. Intended for situation such as when a long running task forms part of + container startup. + +It has to be assumed that the container will stop of its own accord, either with a success or failure exit code. + + +[Using indefinite one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withIndefiniteOneShotStrategy + + +### Minimum duration startup strategy example + +Checks that the container is running and has been running for a defined minimum period of time. + + +[Using minimum duration strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withMinimumDurationStrategy + + +### Other startup strategies + +If none of these options meet your requirements, you can create your own subclass of +[`StartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers +/startupcheck/StartupCheckStrategy.html) with an appropriate startup check mechanism in `waitUntilStartupSuccessful()`. +Or you can leave it as is and just implement the `checkStartupState(DockerClient dockerClient, String containerId)` if you still want to check state + periodically. From 0385030aa4307c7041a0150edbbd2159f9060e16 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 21 May 2020 19:25:02 +0100 Subject: [PATCH 0747/4969] Revert "Added additional url params in JdbcDatabaseContainer (#1802)" (#2775) --- .../containers/ClickHouseContainer.java | 4 - .../containers/CockroachContainer.java | 4 +- .../cockroachdb/SimpleCockroachDBTest.java | 20 ----- .../containers/Db2Container.java | 4 +- .../junit/db2/SimpleDb2Test.java | 15 ---- .../containers/JdbcDatabaseContainer.java | 23 ----- .../containers/MariaDBContainer.java | 4 +- .../junit/mariadb/SimpleMariaDBTest.java | 20 ----- .../containers/MSSQLServerContainer.java | 3 +- .../mssqlserver/SimpleMSSQLServerTest.java | 16 ---- .../containers/MySQLContainer.java | 6 +- .../junit/mysql/SimpleMySQLTest.java | 83 +------------------ .../containers/OracleContainer.java | 5 -- .../containers/PostgreSQLContainer.java | 24 ++++-- .../PostgreSQLConnectionURLTest.java | 2 +- .../postgresql/SimplePostgreSQLTest.java | 15 ---- 16 files changed, 26 insertions(+), 222 deletions(-) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 10c0e1835c2..4d4ea2d11a9 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -66,8 +66,4 @@ public String getTestQueryString() { return TEST_QUERY; } - @Override - public ClickHouseContainer withUrlParam(String paramName, String paramValue) { - throw new UnsupportedOperationException("The ClickHouse does not support this"); - } } diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index de64902c88a..3768ca7a008 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -43,9 +43,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - String additionalUrlParams = constructUrlParameters("?", "&"); - return JDBC_URL_PREFIX + "://" + getHost() + ":" + getMappedPort(DB_PORT) + - "/" + databaseName + additionalUrlParams; + return JDBC_URL_PREFIX + "://" + getHost() + ":" + getMappedPort(DB_PORT) + "/" + databaseName; } @Override diff --git a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java index 14fe20222a3..7c62b2f6bcf 100644 --- a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java +++ b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java @@ -9,8 +9,6 @@ import java.util.logging.Level; import java.util.logging.LogManager; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleCockroachDBTest extends AbstractContainerDatabaseTest { @@ -44,22 +42,4 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } } - - @Test - public void testWithAdditionalUrlParamInJdbcUrl() { - CockroachContainer cockroach = new CockroachContainer() - .withUrlParam("sslmode", "disable") - .withUrlParam("application_name", "cockroach"); - - try { - cockroach.start(); - String jdbcUrl = cockroach.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("sslmode=disable")); - assertThat(jdbcUrl, containsString("application_name=cockroach")); - } finally { - cockroach.stop(); - } - } } diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index 05edcb2c3ed..b1472b21c6c 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -73,9 +73,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - String additionalUrlParams = constructUrlParameters(":", ";", ";"); - return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + - "/" + databaseName + additionalUrlParams; + return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName; } @Override diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java index 6cc7535f785..08f427cf12b 100644 --- a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -7,8 +7,6 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleDb2Test extends AbstractContainerDatabaseTest { @@ -26,17 +24,4 @@ public void testSimple() throws SQLException { assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } - - @Test - public void testWithAdditionalUrlParamInJdbcUrl() { - try (Db2Container db2 = new Db2Container() - .withUrlParam("sslConnection", "false") - .acceptLicense()) { - - db2.start(); - - String jdbcUrl = db2.getJdbcUrl(); - assertThat(jdbcUrl, containsString(":sslConnection=false;")); - } - } } diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 6c265bc6943..36a6461aa74 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -2,7 +2,6 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import lombok.NonNull; -import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.delegate.DatabaseDelegate; @@ -18,8 +17,6 @@ import java.util.Properties; import java.util.concurrent.Future; -import static java.util.stream.Collectors.joining; - /** * Base class for containers that expose a JDBC connection * @@ -31,7 +28,6 @@ public abstract class JdbcDatabaseContainer parameters = new HashMap<>(); - protected Map urlParameters = new HashMap<>(); private int startupTimeoutSeconds = 120; private int connectTimeoutSeconds = 120; @@ -86,11 +82,7 @@ public SELF withPassword(String password) { public SELF withDatabaseName(String dbName) { throw new UnsupportedOperationException(); - } - public SELF withUrlParam(String paramName, String paramValue) { - urlParameters.put(paramName, paramValue); - return self(); } /** @@ -231,21 +223,6 @@ protected String constructUrlForConnection(String queryString) { return getJdbcUrl() + queryString; } - protected String constructUrlParameters(String startCharacter, String delimiter) { - return constructUrlParameters(startCharacter, delimiter, StringUtils.EMPTY); - } - - protected String constructUrlParameters(String startCharacter, String delimiter, String endCharacter) { - String urlParameters = ""; - if (!this.urlParameters.isEmpty()) { - String additionalParameters = this.urlParameters.entrySet().stream() - .map(Object::toString) - .collect(joining(delimiter)); - urlParameters = startCharacter + additionalParameters + endCharacter; - } - return urlParameters; - } - protected void optionallyMapResourceParameterAsVolume(@NotNull String paramName, @NotNull String pathNameInContainer, @NotNull String defaultResource) { String resourceName = parameters.getOrDefault(paramName, defaultResource); diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index 04d745a9efe..1b4cb3344e4 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -60,9 +60,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - String additionalUrlParams = constructUrlParameters("?", "&"); - return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + - "/" + databaseName + additionalUrlParams; + return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + "/" + databaseName; } @Override diff --git a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index af503ce424b..646fbb40947 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -8,8 +8,6 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; @@ -70,22 +68,4 @@ public void testMariaDBWithCommandOverride() throws SQLException { assertEquals("Auto increment increment should be overriden by command line", "10", result); } } - - @Test - public void testWithAdditionalUrlParamInJdbcUrl() { - MariaDBContainer mariaDBContainer = (MariaDBContainer) new MariaDBContainer() - .withUrlParam("connectTimeout", "40000") - .withUrlParam("rewriteBatchedStatements", "true"); - - try { - mariaDBContainer.start(); - String jdbcUrl = mariaDBContainer.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); - assertThat(jdbcUrl, containsString("connectTimeout=40000")); - } finally { - mariaDBContainer.stop(); - } - } } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index b500e6fddf0..631228aeef2 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -62,8 +62,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - String additionalUrlParams = constructUrlParameters(";", ";"); - return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT) + additionalUrlParams; + return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT); } @Override diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index 71e12a6d864..c1699d2473a 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -9,8 +9,6 @@ import java.sql.SQLException; import java.sql.Statement; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { @@ -26,20 +24,6 @@ public void testSimple() throws SQLException { } } - @Test - public void testWithAdditionalUrlParamInJdbcUrl() { - try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>() - .withUrlParam("integratedSecurity", "false") - .withUrlParam("applicationName", "MyApp")) { - - mssqlServer.start(); - - String jdbcUrl = mssqlServer.getJdbcUrl(); - assertThat(jdbcUrl, containsString(";integratedSecurity=false;applicationName=MyApp")); - } - } - - @Test public void testSetupDatabase() throws SQLException { try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>()) { diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 1ef574cbd5e..79d29234b99 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -5,8 +5,6 @@ import java.util.HashSet; import java.util.Set; -import static java.util.stream.Collectors.joining; - /** * @author richardnorth */ @@ -72,9 +70,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - String additionalUrlParams = constructUrlParameters("?", "&"); - return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + - "/" + databaseName + additionalUrlParams; + return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + "/" + databaseName; } @Override diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index 6d6f8d26453..ee6c3ab6993 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -9,17 +9,9 @@ import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.db.AbstractContainerDatabaseTest; -import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; + import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; @@ -150,77 +142,4 @@ public void testEmptyPasswordWithRootUser() throws SQLException { assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } - - @Test - public void testWithAdditionalUrlParamTimeZone() throws SQLException { - MySQLContainer mysql = (MySQLContainer) new MySQLContainer() - .withUrlParam("serverTimezone", "Europe/Zurich") - .withEnv("TZ", "Europe/Zurich") - .withLogConsumer(new Slf4jLogConsumer(logger)); - mysql.start(); - - try(Connection connection = mysql.createConnection("")) { - Statement statement = connection.createStatement(); - statement.execute("SELECT NOW();"); - try (ResultSet resultSet = statement.getResultSet()) { - resultSet.next(); - - // checking that the time_zone MySQL is Europe/Zurich - LocalDateTime localDateTime = resultSet.getObject(1, LocalDateTime.class); - ZonedDateTime actualDateTime = localDateTime.atZone(ZoneId.of("Europe/Zurich")) - .truncatedTo(ChronoUnit.MINUTES); - ZonedDateTime expectedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Zurich")) - .truncatedTo(ChronoUnit.MINUTES); - - String message = String.format("MySQL time zone is not Europe/Zurich. MySQL date:%s, current date:%s", - actualDateTime, expectedDateTime); - assertTrue(message, actualDateTime.equals(expectedDateTime)); - } - } finally { - mysql.stop(); - } - } - - @Test - public void testWithAdditionalUrlParamMultiQueries() throws SQLException { - MySQLContainer mysql = (MySQLContainer) new MySQLContainer() - .withUrlParam("allowMultiQueries", "true") - .withLogConsumer(new Slf4jLogConsumer(logger)); - mysql.start(); - - try(Connection connection = mysql.createConnection("")) { - Statement statement = connection.createStatement(); - String multiQuery = "DROP TABLE IF EXISTS bar; " + - "CREATE TABLE bar (foo VARCHAR(20)); " + - "INSERT INTO bar (foo) VALUES ('hello world');"; - statement.execute(multiQuery); - statement.execute("SELECT foo FROM bar;"); - try(ResultSet resultSet = statement.getResultSet()) { - resultSet.next(); - String firstColumnValue = resultSet.getString(1); - assertEquals("Value from bar should equal real value", "hello world", firstColumnValue); - } - } finally { - mysql.stop(); - } - } - - @Test - public void testWithAdditionalUrlParamInJdbcUrl() { - MySQLContainer mysql = (MySQLContainer) new MySQLContainer() - .withUrlParam("allowMultiQueries", "true") - .withUrlParam("rewriteBatchedStatements", "true") - .withLogConsumer(new Slf4jLogConsumer(logger)); - - try { - mysql.start(); - String jdbcUrl = mysql.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); - assertThat(jdbcUrl, containsString("allowMultiQueries=true")); - } finally { - mysql.stop(); - } - } } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index d263a141d4f..60603a7e222 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -89,11 +89,6 @@ public OracleContainer withPassword(String password) { return self(); } - @Override - public OracleContainer withUrlParam(String paramName, String paramValue) { - throw new UnsupportedOperationException("The OracleDb does not support this"); - } - @SuppressWarnings("SameReturnValue") public String getSid() { return "xe"; diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 6ba7390878e..8634f9d70fa 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -55,8 +55,6 @@ protected Set getLivenessCheckPorts() { @Override protected void configure() { - // Disable Postgres driver use of java.util.logging to reduce noise at startup time - withUrlParam("loggerLevel", "OFF"); addEnv("POSTGRES_DB", databaseName); addEnv("POSTGRES_USER", username); addEnv("POSTGRES_PASSWORD", password); @@ -69,9 +67,25 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - String additionalUrlParams = constructUrlParameters("?", "&"); - return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) - + "/" + databaseName + additionalUrlParams; + // Disable Postgres driver use of java.util.logging to reduce noise at startup time + return format("jdbc:postgresql://%s:%d/%s?loggerLevel=OFF", getHost(), getMappedPort(POSTGRESQL_PORT), databaseName); + } + + @Override + protected String constructUrlForConnection(String queryString) { + String baseUrl = getJdbcUrl(); + + if ("".equals(queryString)) { + return baseUrl; + } + + if (!queryString.startsWith("?")) { + throw new IllegalArgumentException("The '?' character must be included"); + } + + return baseUrl.contains("?") + ? baseUrl + QUERY_PARAM_SEPARATOR + queryString.substring(1) + : baseUrl + queryString; } @Override diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index c0ba7e40d44..05f6ea204a8 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -15,7 +15,7 @@ public void shouldCorrectlyAppendQueryString() { String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); - assertTrue("Query String contains expected params", queryString.contains("?stringtype=unspecified&stringtype=unspecified")); + assertTrue("Query String contains expected params", queryString.contains("&stringtype=unspecified&stringtype=unspecified")); assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); } diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 36ece03b604..9c97f51e64e 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -9,8 +9,6 @@ import java.util.logging.Level; import java.util.logging.LogManager; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; @@ -65,17 +63,4 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } } - - @Test - public void testWithAdditionalUrlParamInJdbcUrl() { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>() - .withUrlParam("charSet", "UNICODE")) { - - postgres.start(); - String jdbcUrl = postgres.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("charSet=UNICODE")); - } - } } From 4ba01a655353dd22c8384a8d00dfc53749666109 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 21 May 2020 19:26:30 +0100 Subject: [PATCH 0748/4969] Revert "Add docs for startup strategy information/examples (#1157)" (#2776) --- docs/examples/junit4/generic/build.gradle | 1 - .../StartupCheckStrategyTest.java | 90 ------------------- docs/features/startup_and_waits.md | 49 ---------- 3 files changed, 140 deletions(-) delete mode 100644 docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle index 5ce878c7ba2..97902d5d9ca 100644 --- a/docs/examples/junit4/generic/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -5,5 +5,4 @@ dependencies { testCompile project(":testcontainers") testCompile project(":selenium") testCompile "org.seleniumhq.selenium:selenium-api:3.141.59" - testCompile 'org.assertj:assertj-core:3.15.0' } diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java deleted file mode 100644 index 5ab32919bb2..00000000000 --- a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.testcontainers.containers.startupcheck; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import lombok.SneakyThrows; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.WaitingConsumer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; -import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.IndefiniteOneShotStrategyTest; -import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.MinimumDurationStrategyTest; -import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.OneShotStrategyTest; - -@RunWith(Suite.class) -@Suite.SuiteClasses({OneShotStrategyTest.class, IndefiniteOneShotStrategyTest.class, MinimumDurationStrategyTest.class}) -public class StartupCheckStrategyTest { - - private static final String HELLO_TESTCONTAINERS = "Hello Testcontainers!"; - - private static void waitForHello(GenericContainer container) throws TimeoutException { - WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); - - consumer.waitUntil(frame -> - frame.getUtf8String().contains(HELLO_TESTCONTAINERS), 30, TimeUnit.SECONDS); - } - - public static class OneShotStrategyTest { - @Rule - // withOneShotStrategy { - public GenericContainer bboxWithOneShot = new GenericContainer("busybox:1.31.1") - .withCommand(String.format("echo %s", HELLO_TESTCONTAINERS)) - .withStartupCheckStrategy( - new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(3)) - ); - // } - - @SneakyThrows - @Test - public void testCommandIsExecuted() { - waitForHello(bboxWithOneShot); - - assertThat(bboxWithOneShot.isRunning()).isFalse(); - } - } - - public static class IndefiniteOneShotStrategyTest { - @Rule - // withIndefiniteOneShotStrategy { - public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer("busybox:1.31.1") - .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) - .withStartupCheckStrategy( - new IndefiniteWaitOneShotStartupCheckStrategy() - ); - // } - - @SneakyThrows - @Test - public void testCommandIsExecuted() { - waitForHello(bboxWithIndefiniteOneShot); - - assertThat(bboxWithIndefiniteOneShot.isRunning()).isFalse(); - } - } - - public static class MinimumDurationStrategyTest { - @Rule - // withMinimumDurationStrategy { - public GenericContainer bboxWithMinimumDuration = new GenericContainer("busybox:1.31.1") - .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) - .withStartupCheckStrategy( - new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(5)) - ); - // } - - @SneakyThrows - @Test - public void testCommandIsExecuted() { - waitForHello(bboxWithMinimumDuration); - - assertThat(bboxWithMinimumDuration.isRunning()).isTrue(); - } - } -} diff --git a/docs/features/startup_and_waits.md b/docs/features/startup_and_waits.md index 3cbec97af0d..e1d30457e5c 100644 --- a/docs/features/startup_and_waits.md +++ b/docs/features/startup_and_waits.md @@ -74,52 +74,3 @@ If none of these options meet your requirements, you can create your own subclas appropriate wait mechanism in `waitUntilReady()`. The `GenericContainer.waitingFor()` method accepts any valid [`WaitStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/wait/strategy/WaitStrategy.html). - -## Startup check Strategies - -Ordinarily Testcontainers will check that the container has reached the running state and has not exited. -In order to do that inspect is executed against the container and state parameter is extracted. - -All logic is implemented in [`StartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/startupcheck/StartupCheckStrategy.html) child classes. - -### Running startup strategy example - -This is the strategy used by default. Testcontainers just checks if container is running. - -Implemented in [`IsRunningStartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.html) class. - -### One shot startup strategy example - -This strategy is intended for use with containers that only run briefly and exit of their own accord. As such, success is deemed to be when -the container has stopped with exit code 0. - - -[Using one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withOneShotStrategy - - -### Indefinite one shot startup strategy example - -Variant of one shot strategy that does not impose a timeout. Intended for situation such as when a long running task forms part of - container startup. - -It has to be assumed that the container will stop of its own accord, either with a success or failure exit code. - - -[Using indefinite one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withIndefiniteOneShotStrategy - - -### Minimum duration startup strategy example - -Checks that the container is running and has been running for a defined minimum period of time. - - -[Using minimum duration strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withMinimumDurationStrategy - - -### Other startup strategies - -If none of these options meet your requirements, you can create your own subclass of -[`StartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers -/startupcheck/StartupCheckStrategy.html) with an appropriate startup check mechanism in `waitUntilStartupSuccessful()`. -Or you can leave it as is and just implement the `checkStartupState(DockerClient dockerClient, String containerId)` if you still want to check state - periodically. From 74a88ad6498b800b0e76d28ca41dc02369d870b9 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 22 May 2020 09:36:20 +0100 Subject: [PATCH 0749/4969] Prevent Local gradle build cache collisions (#2778) --- .github/workflows/ci-examples.yml | 3 --- .github/workflows/ci.yml | 3 --- 2 files changed, 6 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index bec794dc167..8dab14e831c 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -25,7 +25,6 @@ jobs: key: ${{ runner.os }}-gradle-home-testmatrix-examples-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle-home-testmatrix-examples- - ${{ runner.os }}-gradle-home- - id: set-matrix working-directory: ./examples/ env: @@ -54,8 +53,6 @@ jobs: key: ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check- - ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check- - ${{ runner.os }}-gradle-home-examples- - name: Clear existing docker image cache run: docker image prune -af - name: Build and test Examples with Gradle (${{matrix.gradle_args}}) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90e64dde133..6ea2319193d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,6 @@ jobs: key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle-home-testmatrix- - ${{ runner.os }}-gradle-home- - id: set-matrix env: # Since we override the tests executor, @@ -53,8 +52,6 @@ jobs: key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check- - ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check- - ${{ runner.os }}-gradle-home- - name: Clear existing docker image cache run: docker image prune -af - name: Build and test with Gradle (${{matrix.gradle_args}}) From af077e91508cf7bbdb179053c479af7d4b068b83 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 22 May 2020 10:08:02 +0100 Subject: [PATCH 0750/4969] Reinstate "Add docs for startup strategy information/examples" (#2779) --- docs/examples/junit4/generic/build.gradle | 1 + .../StartupCheckStrategyTest.java | 90 +++++++++++++++++++ docs/features/startup_and_waits.md | 49 ++++++++++ 3 files changed, 140 insertions(+) create mode 100644 docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle index 97902d5d9ca..5ce878c7ba2 100644 --- a/docs/examples/junit4/generic/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -5,4 +5,5 @@ dependencies { testCompile project(":testcontainers") testCompile project(":selenium") testCompile "org.seleniumhq.selenium:selenium-api:3.141.59" + testCompile 'org.assertj:assertj-core:3.15.0' } diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java new file mode 100644 index 00000000000..5ab32919bb2 --- /dev/null +++ b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java @@ -0,0 +1,90 @@ +package org.testcontainers.containers.startupcheck; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import lombok.SneakyThrows; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.WaitingConsumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; +import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.IndefiniteOneShotStrategyTest; +import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.MinimumDurationStrategyTest; +import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.OneShotStrategyTest; + +@RunWith(Suite.class) +@Suite.SuiteClasses({OneShotStrategyTest.class, IndefiniteOneShotStrategyTest.class, MinimumDurationStrategyTest.class}) +public class StartupCheckStrategyTest { + + private static final String HELLO_TESTCONTAINERS = "Hello Testcontainers!"; + + private static void waitForHello(GenericContainer container) throws TimeoutException { + WaitingConsumer consumer = new WaitingConsumer(); + container.followOutput(consumer, STDOUT); + + consumer.waitUntil(frame -> + frame.getUtf8String().contains(HELLO_TESTCONTAINERS), 30, TimeUnit.SECONDS); + } + + public static class OneShotStrategyTest { + @Rule + // withOneShotStrategy { + public GenericContainer bboxWithOneShot = new GenericContainer("busybox:1.31.1") + .withCommand(String.format("echo %s", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(3)) + ); + // } + + @SneakyThrows + @Test + public void testCommandIsExecuted() { + waitForHello(bboxWithOneShot); + + assertThat(bboxWithOneShot.isRunning()).isFalse(); + } + } + + public static class IndefiniteOneShotStrategyTest { + @Rule + // withIndefiniteOneShotStrategy { + public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer("busybox:1.31.1") + .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new IndefiniteWaitOneShotStartupCheckStrategy() + ); + // } + + @SneakyThrows + @Test + public void testCommandIsExecuted() { + waitForHello(bboxWithIndefiniteOneShot); + + assertThat(bboxWithIndefiniteOneShot.isRunning()).isFalse(); + } + } + + public static class MinimumDurationStrategyTest { + @Rule + // withMinimumDurationStrategy { + public GenericContainer bboxWithMinimumDuration = new GenericContainer("busybox:1.31.1") + .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(5)) + ); + // } + + @SneakyThrows + @Test + public void testCommandIsExecuted() { + waitForHello(bboxWithMinimumDuration); + + assertThat(bboxWithMinimumDuration.isRunning()).isTrue(); + } + } +} diff --git a/docs/features/startup_and_waits.md b/docs/features/startup_and_waits.md index e1d30457e5c..3cbec97af0d 100644 --- a/docs/features/startup_and_waits.md +++ b/docs/features/startup_and_waits.md @@ -74,3 +74,52 @@ If none of these options meet your requirements, you can create your own subclas appropriate wait mechanism in `waitUntilReady()`. The `GenericContainer.waitingFor()` method accepts any valid [`WaitStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/wait/strategy/WaitStrategy.html). + +## Startup check Strategies + +Ordinarily Testcontainers will check that the container has reached the running state and has not exited. +In order to do that inspect is executed against the container and state parameter is extracted. + +All logic is implemented in [`StartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/startupcheck/StartupCheckStrategy.html) child classes. + +### Running startup strategy example + +This is the strategy used by default. Testcontainers just checks if container is running. + +Implemented in [`IsRunningStartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.html) class. + +### One shot startup strategy example + +This strategy is intended for use with containers that only run briefly and exit of their own accord. As such, success is deemed to be when +the container has stopped with exit code 0. + + +[Using one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withOneShotStrategy + + +### Indefinite one shot startup strategy example + +Variant of one shot strategy that does not impose a timeout. Intended for situation such as when a long running task forms part of + container startup. + +It has to be assumed that the container will stop of its own accord, either with a success or failure exit code. + + +[Using indefinite one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withIndefiniteOneShotStrategy + + +### Minimum duration startup strategy example + +Checks that the container is running and has been running for a defined minimum period of time. + + +[Using minimum duration strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withMinimumDurationStrategy + + +### Other startup strategies + +If none of these options meet your requirements, you can create your own subclass of +[`StartupCheckStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers +/startupcheck/StartupCheckStrategy.html) with an appropriate startup check mechanism in `waitUntilStartupSuccessful()`. +Or you can leave it as is and just implement the `checkStartupState(DockerClient dockerClient, String containerId)` if you still want to check state + periodically. From a6e8be1066b837fa666ca492233b1f97cc62234f Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 22 May 2020 11:00:40 +0100 Subject: [PATCH 0751/4969] Fix flaky StartupCheckStrategyTest --- .../startupcheck/StartupCheckStrategyTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java index 5ab32919bb2..deef64bc59b 100644 --- a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java +++ b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java @@ -1,8 +1,5 @@ package org.testcontainers.containers.startupcheck; -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import lombok.SneakyThrows; import org.junit.Rule; import org.junit.Test; @@ -11,6 +8,10 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.WaitingConsumer; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + import static org.assertj.core.api.Assertions.assertThat; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.IndefiniteOneShotStrategyTest; @@ -75,7 +76,7 @@ public static class MinimumDurationStrategyTest { public GenericContainer bboxWithMinimumDuration = new GenericContainer("busybox:1.31.1") .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) .withStartupCheckStrategy( - new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(5)) + new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(1)) ); // } From f401b1c202bd05cb2cab78c2949f3ba15b7682b4 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 22 May 2020 12:33:29 +0100 Subject: [PATCH 0752/4969] Reinstate #1874 "Added additional url params in JdbcDatabaseContainer" (#2777) --- .../containers/ClickHouseContainer.java | 4 + .../containers/CockroachContainer.java | 4 +- .../cockroachdb/SimpleCockroachDBTest.java | 20 +++++ .../containers/Db2Container.java | 4 +- .../junit/db2/SimpleDb2Test.java | 15 ++++ .../containers/JdbcDatabaseContainer.java | 39 ++++++++- .../containers/MariaDBContainer.java | 4 +- .../junit/mariadb/SimpleMariaDBTest.java | 20 +++++ .../containers/MSSQLServerContainer.java | 3 +- .../mssqlserver/SimpleMSSQLServerTest.java | 16 ++++ .../containers/MySQLContainer.java | 6 +- .../junit/mysql/SimpleMySQLTest.java | 83 ++++++++++++++++++- .../containers/OracleContainer.java | 5 ++ .../containers/PostgreSQLContainer.java | 24 ++---- .../PostgreSQLConnectionURLTest.java | 2 +- .../postgresql/SimplePostgreSQLTest.java | 15 ++++ 16 files changed, 237 insertions(+), 27 deletions(-) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 4d4ea2d11a9..10c0e1835c2 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -66,4 +66,8 @@ public String getTestQueryString() { return TEST_QUERY; } + @Override + public ClickHouseContainer withUrlParam(String paramName, String paramValue) { + throw new UnsupportedOperationException("The ClickHouse does not support this"); + } } diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index 3768ca7a008..de64902c88a 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -43,7 +43,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return JDBC_URL_PREFIX + "://" + getHost() + ":" + getMappedPort(DB_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters("?", "&"); + return JDBC_URL_PREFIX + "://" + getHost() + ":" + getMappedPort(DB_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java index 7c62b2f6bcf..14fe20222a3 100644 --- a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java +++ b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java @@ -9,6 +9,8 @@ import java.util.logging.Level; import java.util.logging.LogManager; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleCockroachDBTest extends AbstractContainerDatabaseTest { @@ -42,4 +44,22 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + CockroachContainer cockroach = new CockroachContainer() + .withUrlParam("sslmode", "disable") + .withUrlParam("application_name", "cockroach"); + + try { + cockroach.start(); + String jdbcUrl = cockroach.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("sslmode=disable")); + assertThat(jdbcUrl, containsString("application_name=cockroach")); + } finally { + cockroach.stop(); + } + } } diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index b1472b21c6c..05edcb2c3ed 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -73,7 +73,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters(":", ";", ";"); + return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java index 08f427cf12b..6cc7535f785 100644 --- a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -7,6 +7,8 @@ import java.sql.ResultSet; import java.sql.SQLException; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleDb2Test extends AbstractContainerDatabaseTest { @@ -24,4 +26,17 @@ public void testSimple() throws SQLException { assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + try (Db2Container db2 = new Db2Container() + .withUrlParam("sslConnection", "false") + .acceptLicense()) { + + db2.start(); + + String jdbcUrl = db2.getJdbcUrl(); + assertThat(jdbcUrl, containsString(":sslConnection=false;")); + } + } } diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 36a6461aa74..62fe43e7932 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import lombok.NonNull; +import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.delegate.DatabaseDelegate; @@ -17,6 +18,8 @@ import java.util.Properties; import java.util.concurrent.Future; +import static java.util.stream.Collectors.joining; + /** * Base class for containers that expose a JDBC connection * @@ -28,10 +31,13 @@ public abstract class JdbcDatabaseContainer parameters = new HashMap<>(); + protected Map urlParameters = new HashMap<>(); private int startupTimeoutSeconds = 120; private int connectTimeoutSeconds = 120; + private static final String QUERY_PARAM_SEPARATOR = "&"; + public JdbcDatabaseContainer(@NonNull final String dockerImageName) { super(dockerImageName); } @@ -82,7 +88,11 @@ public SELF withPassword(String password) { public SELF withDatabaseName(String dbName) { throw new UnsupportedOperationException(); + } + public SELF withUrlParam(String paramName, String paramValue) { + urlParameters.put(paramName, paramValue); + return self(); } /** @@ -220,7 +230,34 @@ public Connection createConnection(String queryString) throws SQLException, NoDr * @return a full JDBC URL including queryString */ protected String constructUrlForConnection(String queryString) { - return getJdbcUrl() + queryString; + String baseUrl = getJdbcUrl(); + + if ("".equals(queryString)) { + return baseUrl; + } + + if (!queryString.startsWith("?")) { + throw new IllegalArgumentException("The '?' character must be included"); + } + + return baseUrl.contains("?") + ? baseUrl + QUERY_PARAM_SEPARATOR + queryString.substring(1) + : baseUrl + queryString; + } + + protected String constructUrlParameters(String startCharacter, String delimiter) { + return constructUrlParameters(startCharacter, delimiter, StringUtils.EMPTY); + } + + protected String constructUrlParameters(String startCharacter, String delimiter, String endCharacter) { + String urlParameters = ""; + if (!this.urlParameters.isEmpty()) { + String additionalParameters = this.urlParameters.entrySet().stream() + .map(Object::toString) + .collect(joining(delimiter)); + urlParameters = startCharacter + additionalParameters + endCharacter; + } + return urlParameters; } protected void optionallyMapResourceParameterAsVolume(@NotNull String paramName, @NotNull String pathNameInContainer, @NotNull String defaultResource) { diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index 1b4cb3344e4..04d745a9efe 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -60,7 +60,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index 646fbb40947..af503ce424b 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -8,6 +8,8 @@ import java.sql.ResultSet; import java.sql.SQLException; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; @@ -68,4 +70,22 @@ public void testMariaDBWithCommandOverride() throws SQLException { assertEquals("Auto increment increment should be overriden by command line", "10", result); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + MariaDBContainer mariaDBContainer = (MariaDBContainer) new MariaDBContainer() + .withUrlParam("connectTimeout", "40000") + .withUrlParam("rewriteBatchedStatements", "true"); + + try { + mariaDBContainer.start(); + String jdbcUrl = mariaDBContainer.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); + assertThat(jdbcUrl, containsString("connectTimeout=40000")); + } finally { + mariaDBContainer.stop(); + } + } } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index 631228aeef2..b500e6fddf0 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -62,7 +62,8 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT); + String additionalUrlParams = constructUrlParameters(";", ";"); + return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT) + additionalUrlParams; } @Override diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index c1699d2473a..71e12a6d864 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -9,6 +9,8 @@ import java.sql.SQLException; import java.sql.Statement; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { @@ -24,6 +26,20 @@ public void testSimple() throws SQLException { } } + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>() + .withUrlParam("integratedSecurity", "false") + .withUrlParam("applicationName", "MyApp")) { + + mssqlServer.start(); + + String jdbcUrl = mssqlServer.getJdbcUrl(); + assertThat(jdbcUrl, containsString(";integratedSecurity=false;applicationName=MyApp")); + } + } + + @Test public void testSetupDatabase() throws SQLException { try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>()) { diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 79d29234b99..1ef574cbd5e 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -5,6 +5,8 @@ import java.util.HashSet; import java.util.Set; +import static java.util.stream.Collectors.joining; + /** * @author richardnorth */ @@ -70,7 +72,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + "/" + databaseName; + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index ee6c3ab6993..6d6f8d26453 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -9,9 +9,17 @@ import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.db.AbstractContainerDatabaseTest; +import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; - +import java.sql.Statement; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; @@ -142,4 +150,77 @@ public void testEmptyPasswordWithRootUser() throws SQLException { assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } + + @Test + public void testWithAdditionalUrlParamTimeZone() throws SQLException { + MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + .withUrlParam("serverTimezone", "Europe/Zurich") + .withEnv("TZ", "Europe/Zurich") + .withLogConsumer(new Slf4jLogConsumer(logger)); + mysql.start(); + + try(Connection connection = mysql.createConnection("")) { + Statement statement = connection.createStatement(); + statement.execute("SELECT NOW();"); + try (ResultSet resultSet = statement.getResultSet()) { + resultSet.next(); + + // checking that the time_zone MySQL is Europe/Zurich + LocalDateTime localDateTime = resultSet.getObject(1, LocalDateTime.class); + ZonedDateTime actualDateTime = localDateTime.atZone(ZoneId.of("Europe/Zurich")) + .truncatedTo(ChronoUnit.MINUTES); + ZonedDateTime expectedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Zurich")) + .truncatedTo(ChronoUnit.MINUTES); + + String message = String.format("MySQL time zone is not Europe/Zurich. MySQL date:%s, current date:%s", + actualDateTime, expectedDateTime); + assertTrue(message, actualDateTime.equals(expectedDateTime)); + } + } finally { + mysql.stop(); + } + } + + @Test + public void testWithAdditionalUrlParamMultiQueries() throws SQLException { + MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + .withUrlParam("allowMultiQueries", "true") + .withLogConsumer(new Slf4jLogConsumer(logger)); + mysql.start(); + + try(Connection connection = mysql.createConnection("")) { + Statement statement = connection.createStatement(); + String multiQuery = "DROP TABLE IF EXISTS bar; " + + "CREATE TABLE bar (foo VARCHAR(20)); " + + "INSERT INTO bar (foo) VALUES ('hello world');"; + statement.execute(multiQuery); + statement.execute("SELECT foo FROM bar;"); + try(ResultSet resultSet = statement.getResultSet()) { + resultSet.next(); + String firstColumnValue = resultSet.getString(1); + assertEquals("Value from bar should equal real value", "hello world", firstColumnValue); + } + } finally { + mysql.stop(); + } + } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + .withUrlParam("allowMultiQueries", "true") + .withUrlParam("rewriteBatchedStatements", "true") + .withLogConsumer(new Slf4jLogConsumer(logger)); + + try { + mysql.start(); + String jdbcUrl = mysql.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); + assertThat(jdbcUrl, containsString("allowMultiQueries=true")); + } finally { + mysql.stop(); + } + } } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index 60603a7e222..d263a141d4f 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -89,6 +89,11 @@ public OracleContainer withPassword(String password) { return self(); } + @Override + public OracleContainer withUrlParam(String paramName, String paramValue) { + throw new UnsupportedOperationException("The OracleDb does not support this"); + } + @SuppressWarnings("SameReturnValue") public String getSid() { return "xe"; diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 8634f9d70fa..6ba7390878e 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -55,6 +55,8 @@ protected Set getLivenessCheckPorts() { @Override protected void configure() { + // Disable Postgres driver use of java.util.logging to reduce noise at startup time + withUrlParam("loggerLevel", "OFF"); addEnv("POSTGRES_DB", databaseName); addEnv("POSTGRES_USER", username); addEnv("POSTGRES_PASSWORD", password); @@ -67,25 +69,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - // Disable Postgres driver use of java.util.logging to reduce noise at startup time - return format("jdbc:postgresql://%s:%d/%s?loggerLevel=OFF", getHost(), getMappedPort(POSTGRESQL_PORT), databaseName); - } - - @Override - protected String constructUrlForConnection(String queryString) { - String baseUrl = getJdbcUrl(); - - if ("".equals(queryString)) { - return baseUrl; - } - - if (!queryString.startsWith("?")) { - throw new IllegalArgumentException("The '?' character must be included"); - } - - return baseUrl.contains("?") - ? baseUrl + QUERY_PARAM_SEPARATOR + queryString.substring(1) - : baseUrl + queryString; + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index 05f6ea204a8..c0ba7e40d44 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -15,7 +15,7 @@ public void shouldCorrectlyAppendQueryString() { String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); - assertTrue("Query String contains expected params", queryString.contains("&stringtype=unspecified&stringtype=unspecified")); + assertTrue("Query String contains expected params", queryString.contains("?stringtype=unspecified&stringtype=unspecified")); assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); } diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 9c97f51e64e..36ece03b604 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -9,6 +9,8 @@ import java.util.logging.Level; import java.util.logging.LogManager; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; @@ -63,4 +65,17 @@ public void testExplicitInitScript() throws SQLException { assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); } } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>() + .withUrlParam("charSet", "UNICODE")) { + + postgres.start(); + String jdbcUrl = postgres.getJdbcUrl(); + assertThat(jdbcUrl, containsString("?")); + assertThat(jdbcUrl, containsString("&")); + assertThat(jdbcUrl, containsString("charSet=UNICODE")); + } + } } From 289fb50f06d1ee99c036858b8b0889e96c1396a8 Mon Sep 17 00:00:00 2001 From: AElMehdi Date: Fri, 22 May 2020 13:34:35 +0200 Subject: [PATCH 0753/4969] Update version #2757 (#2758) --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 48b63c59631..c28e0827f7c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -90,4 +90,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.14.1 + latest_version: 1.14.2 From 647d1fe9f5766e5aeaa8a238e553976eeaf16bbb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 23 May 2020 13:14:35 +0100 Subject: [PATCH 0754/4969] Bump influxdb-java from 2.18 to 2.19 in /modules/influxdb (#2784) --- modules/influxdb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index 02af2e924a9..2deacd3a149 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { compile project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.18' - testCompile 'org.influxdb:influxdb-java:2.17' + compileOnly 'org.influxdb:influxdb-java:2.19' + testCompile 'org.influxdb:influxdb-java:2.19' } From 066a1bdf4219cd0ea5e31abcdf07faab5e9c1eee Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 23 May 2020 13:14:48 +0100 Subject: [PATCH 0755/4969] Bump pulsar-client from 2.5.1 to 2.5.2 in /modules/pulsar (#2787) --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 74626006ba0..4082197b8ea 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.2' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.1' } From b3cd937da000bf92f0428cbb2ba2e92c2d95fa93 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 23 May 2020 13:14:57 +0100 Subject: [PATCH 0756/4969] Bump aws-java-sdk-sqs from 1.11.784 to 1.11.789 in /modules/localstack (#2785) --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 482b977792d..ce921607844 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.784' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.789' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.782' testCompile 'software.amazon.awssdk:s3:2.13.18' } From fe2102a99ce323a1fa00913104954264bda44a86 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 28 May 2020 22:08:35 +0100 Subject: [PATCH 0757/4969] Move away from using quay.io for default images (#2805) --- .../utility/TestcontainersConfiguration.java | 21 ++++++++++++++----- docs/features/configuration.md | 8 +++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 64ee03efb06..44691cfb6fb 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -1,11 +1,22 @@ package org.testcontainers.utility; import com.google.common.annotations.VisibleForTesting; -import lombok.*; +import lombok.AccessLevel; +import lombok.Data; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.testcontainers.UnstableAPI; -import java.io.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Objects; @@ -56,7 +67,7 @@ public String getSocatContainerImage() { } public String getVncRecordedContainerImage() { - return (String) properties.getOrDefault("vncrecorder.container.image", "quay.io/testcontainers/vnc-recorder:1.1.0"); + return (String) properties.getOrDefault("vncrecorder.container.image", "testcontainersofficial/vnc-recorder:1.1.0"); } public String getDockerComposeContainerImage() { @@ -72,11 +83,11 @@ public boolean isRyukPrivileged() { } public String getRyukImage() { - return (String) properties.getOrDefault("ryuk.container.image", "quay.io/testcontainers/ryuk:0.2.3"); + return (String) properties.getOrDefault("ryuk.container.image", "testcontainersofficial/ryuk:0.3.0"); } public String getSSHdImage() { - return (String) properties.getOrDefault("sshd.container.image", "quay.io/testcontainers/sshd:1.0.0"); + return (String) properties.getOrDefault("sshd.container.image", "testcontainersofficial/sshd:1.0.0"); } public Integer getRyukTimeout() { diff --git a/docs/features/configuration.md b/docs/features/configuration.md index ad039528b5d..f0172b3c978 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -32,7 +32,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **tinyimage.container.image = alpine:3.5** > Used by Testcontainers' core -> **vncrecorder.container.image = quay.io/testcontainers/vnc-recorder:1.1.0** +> **vncrecorder.container.image = testcontainersofficial/vnc-recorder:1.1.0** > Used by VNC recorder in Testcontainers' Seleniun integration > **ambassador.container.image = richnorth/ambassador:latest** @@ -49,13 +49,11 @@ Another possibility is to set up a registry mirror in your environment so that a For more information, see the [official Docker documentation about "Registry as a pull through cache"](https://docs.docker.com/registry/recipes/mirror/). !!!tip - Registry mirror currently only works for Docker images with image name that has no registry specified (for example, for Docker image `mariadb:10.3.6`, it works, for Docker image `quay.io/testcontainers/ryuk:0.2.3`, not). - Workaround is to to configure the affected Docker image in `.testcontainers.properties`. - For example: `ryuk.container.image = testcontainers/ryuk:0.2.3` or `ryuk.container.image = /testcontainers/ryuk:0.2.3` + Registry mirror currently only works for Docker images with image name that has no registry specified (for example, for Docker image `mariadb:10.3.6`, it works, for Docker image `quay.io/something/else`, not). ## Customizing Ryuk resource reaper -> **ryuk.container.image = quay.io/testcontainers/ryuk:0.2.3** +> **ryuk.container.image = testcontainersofficial/ryuk:0.3.0** > The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown > **ryuk.container.privileged = false** From 3a2462cbeb5fee3cafcd885eeb10f2514f6d096b Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 28 May 2020 23:13:46 +0100 Subject: [PATCH 0758/4969] Ensure that ParsedDockerfile supports platform args (#2780) --- .../images/ParsedDockerfile.java | 4 ++-- .../images/ParsedDockerfileTest.java | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java b/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java index 1ad43813757..d4574d17c34 100644 --- a/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java @@ -21,7 +21,7 @@ @Slf4j public class ParsedDockerfile { - private static final Pattern FROM_LINE_PATTERN = Pattern.compile("FROM ([^\\s]+).*"); + private static final Pattern FROM_LINE_PATTERN = Pattern.compile("FROM (?--[^\\s]+\\s)*(?[^\\s]+).*", Pattern.CASE_INSENSITIVE); private final Path dockerFilePath; @@ -57,7 +57,7 @@ private void parse(List lines) { dependencyImageNames = lines.stream() .map(FROM_LINE_PATTERN::matcher) .filter(Matcher::matches) - .map(matcher -> matcher.group(1)) + .map(matcher -> matcher.group("image")) .collect(Collectors.toSet()); if (!dependencyImageNames.isEmpty()) { diff --git a/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java index e2b97f9fab7..52a22c83b00 100644 --- a/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java +++ b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java @@ -16,6 +16,12 @@ public void doesSimpleParsing() { assertEquals("extracts a single image name", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); } + @Test + public void isCaseInsensitive() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("from someimage", "RUN something")); + assertEquals("extracts a single image name", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + } + @Test public void handlesTags() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage:tag", "RUN something")); @@ -40,6 +46,18 @@ public void ignoringBuildStageNames() { assertEquals("ignores build stage names and allows multiple images to be extracted", Sets.newHashSet("someimage", "nextimage"), parsedDockerfile.getDependencyImageNames()); } + @Test + public void ignoringPlatformArgs() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM --platform=linux/amd64 someimage", "RUN something")); + assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + } + + @Test + public void ignoringExtraPlatformArgs() { + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM --platform=linux/amd64 --somethingelse=value someimage", "RUN something")); + assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + } + @Test public void handlesGracefullyIfNoFromLine() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("RUN something", "# is this even a valid Dockerfile?")); From 77a662c19d524ce3d714df79bf3994368252c109 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 May 2020 23:16:57 +0100 Subject: [PATCH 0759/4969] Bump aws-java-sdk-logs from 1.11.782 to 1.11.789 in /modules/localstack (#2788) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ce921607844..2ad0552bdb3 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,6 +6,6 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.789' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.782' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.789' testCompile 'software.amazon.awssdk:s3:2.13.18' } From f2109fc33a760242942cc869b7914e88336fe5f7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 May 2020 23:17:32 +0100 Subject: [PATCH 0760/4969] Bump s3 from 2.13.18 to 2.13.23 in /modules/localstack (#2786) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 2ad0552bdb3..857b752ec1e 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.789' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.789' - testCompile 'software.amazon.awssdk:s3:2.13.18' + testCompile 'software.amazon.awssdk:s3:2.13.23' } From 71b9bcefafbe77ec462eeca2444ca3786ce205b0 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 29 May 2020 10:05:18 +0100 Subject: [PATCH 0761/4969] Always clean Azure pipelines builds --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5780a01bb83..185240ae7eb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,7 +14,7 @@ jobs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' options: "--no-daemon --continue" - tasks: "testcontainers:test --tests GenericContainerRuleTest" + tasks: "clean testcontainers:test --tests GenericContainerRuleTest" publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" @@ -31,6 +31,6 @@ jobs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' options: '--no-daemon --continue' - tasks: 'check' + tasks: 'clean check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' From 785bdf567f2e771de5613bbeeda419f33b4bdecf Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 29 May 2020 10:36:03 +0100 Subject: [PATCH 0762/4969] Temporarily disable use of build cache --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 185240ae7eb..1e3715bec7c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,7 +13,7 @@ jobs: inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' - options: "--no-daemon --continue" + options: "--no-daemon --continue --no-build-cache" tasks: "clean testcontainers:test --tests GenericContainerRuleTest" publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' @@ -30,7 +30,7 @@ jobs: inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' - options: '--no-daemon --continue' + options: '--no-daemon --continue --no-build-cache' tasks: 'clean check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' From 892d84db66b8e99b140aecd863111cb0b0527e5d Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 29 May 2020 11:39:20 +0100 Subject: [PATCH 0763/4969] Re-enable build cache --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1e3715bec7c..185240ae7eb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,7 +13,7 @@ jobs: inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' - options: "--no-daemon --continue --no-build-cache" + options: "--no-daemon --continue" tasks: "clean testcontainers:test --tests GenericContainerRuleTest" publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' @@ -30,7 +30,7 @@ jobs: inputs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' - options: '--no-daemon --continue --no-build-cache' + options: '--no-daemon --continue' tasks: 'clean check' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' From 6ac18b2b882f4c1a8b5d550d9ca79de339ce0265 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 May 2020 12:43:11 +0200 Subject: [PATCH 0764/4969] Add default labels to images created with `ImageFromDockerfile` (#2809) --- .../images/builder/ImageFromDockerfile.java | 6 +++++ .../builder/ImageFromDockerfileTest.java | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 11a7e2f4cb6..638db2e351d 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -107,6 +107,12 @@ public void onNext(BuildResponseItem item) { BuildImageCmd buildImageCmd = dockerClient.buildImageCmd(in); configure(buildImageCmd); + Map labels = new HashMap<>(); + if (buildImageCmd.getLabels() != null) { + labels.putAll(buildImageCmd.getLabels()); + } + labels.putAll(DockerClientFactory.DEFAULT_LABELS); + buildImageCmd.withLabels(labels); prePullDependencyImages(dependencyImageNames); diff --git a/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java b/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java new file mode 100644 index 00000000000..93ec5cb5cd1 --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java @@ -0,0 +1,27 @@ +package org.testcontainers.images.builder; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.InspectImageResponse; +import org.junit.Test; +import org.testcontainers.DockerClientFactory; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ImageFromDockerfileTest { + + @Test + public void shouldAddDefaultLabels() { + ImageFromDockerfile image = new ImageFromDockerfile() + .withDockerfileFromBuilder(it -> it.from("scratch")); + + String imageId = image.resolve(); + + DockerClient dockerClient = DockerClientFactory.instance().client(); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + + assertThat(inspectImageResponse.getConfig().getLabels()) + .containsAllEntriesOf(DockerClientFactory.DEFAULT_LABELS); + } + +} From 6e1f8a03699076a54e79e037f7ad34b06202f2f2 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 29 May 2020 12:43:27 +0200 Subject: [PATCH 0765/4969] Record and dump Ryuk's logs on timeout (#2810) --- .../utility/ResourceReaper.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index f74905e60ef..2f668d80426 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -1,10 +1,12 @@ package org.testcontainers.utility; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Network; import com.github.dockerjava.api.model.Ports; @@ -28,6 +30,7 @@ import java.io.UnsupportedEncodingException; import java.net.Socket; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; @@ -93,6 +96,20 @@ public static String start(String hostIpAddress, DockerClient client) { client.startContainerCmd(ryukContainerId).exec(); + StringBuilder ryukLog = new StringBuilder(); + + client.logContainerCmd(ryukContainerId) + .withSince(0) + .withFollowStream(true) + .withStdOut(true) + .withStdErr(true) + .exec(new ResultCallback.Adapter() { + @Override + public void onNext(Frame frame) { + ryukLog.append(new String(frame.getPayload(), StandardCharsets.UTF_8)); + } + }); + InspectContainerResponse inspectedContainer = client.inspectContainerCmd(ryukContainerId).exec(); Integer ryukPort = inspectedContainer.getNetworkSettings().getPorts().getBindings().values().stream() @@ -155,7 +172,8 @@ public static String start(String hostIpAddress, DockerClient client) { // We need to wait before we can start any containers to make sure that we delete them if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { - throw new IllegalStateException("Can not connect to Ryuk"); + log.error("Timeout out waiting for Ryuk. Ryuk's log:\n{}", ryukLog); + throw new IllegalStateException(String.format("Can not connect to Ryuk at %s:%s", hostIpAddress, ryukPort)); } return ryukContainerId; From 835ac71d8ddcf206146af08b2e4efc56532d878f Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Fri, 29 May 2020 14:56:07 +0200 Subject: [PATCH 0766/4969] =?UTF-8?q?couchbase:=20wait=20until=20query=20e?= =?UTF-8?q?ngine=20knows=20about=20bucket=20before=20creating=E2=80=A6=20(?= =?UTF-8?q?#2662)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The motivation for this change is that in slow environments, it could be that the query engine is not aware of the just created bucket yet and so the create primary index will take longer than the 10s read timeout for the subsequent http request. As a result, this is just another precaution to minimize the chances that in slow environments the create primary index call times out with a read timeout. --- .../couchbase/CouchbaseContainer.java | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 33f87359a92..92b35da3361 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -19,12 +19,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.ContainerNetwork; +import lombok.Cleanup; import okhttp3.Credentials; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; +import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; @@ -36,6 +38,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -224,7 +227,7 @@ private void waitUntilNodeIsOnline() { private void renameNode() { logger().debug("Renaming Couchbase Node from localhost to {}", getHost()); - Response response = doHttpRequest(MGMT_PORT, "/node/controller/rename", "POST", new FormBody.Builder() + @Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/rename", "POST", new FormBody.Builder() .add("hostname", getInternalIpAddress()) .build(), false ); @@ -248,7 +251,7 @@ private void initializeServices() { } }).collect(Collectors.joining(",")); - Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder() + @Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder() .add("services", services) .build(), false ); @@ -264,7 +267,7 @@ private void initializeServices() { private void configureAdminUser() { logger().debug("Configuring couchbase admin user with username: \"{}\"", username); - Response response = doHttpRequest(MGMT_PORT, "/settings/web", "POST", new FormBody.Builder() + @Cleanup Response response = doHttpRequest(MGMT_PORT, "/settings/web", "POST", new FormBody.Builder() .add("username", username) .add("password", password) .add("port", Integer.toString(MGMT_PORT)) @@ -305,7 +308,7 @@ private void configureExternalPorts() { builder.add("ftsSSL", Integer.toString(getMappedPort(SEARCH_SSL_PORT))); } - final Response response = doHttpRequest( + @Cleanup Response response = doHttpRequest( MGMT_PORT, "/node/controller/setupAlternateAddresses/external", "PUT", @@ -322,7 +325,7 @@ private void configureExternalPorts() { private void configureIndexer() { logger().debug("Configuring the indexer service"); - Response response = doHttpRequest(MGMT_PORT, "/settings/indexes", "POST", new FormBody.Builder() + @Cleanup Response response = doHttpRequest(MGMT_PORT, "/settings/indexes", "POST", new FormBody.Builder() .add("storageMode", "memory_optimized") .build(), true ); @@ -339,7 +342,7 @@ private void createBuckets() { for (BucketDefinition bucket : buckets) { logger().debug("Creating bucket \"" + bucket.getName() + "\""); - Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder() + @Cleanup Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder() .add("name", bucket.getName()) .add("ramQuotaMB", Integer.toString(bucket.getQuota())) .build(), true); @@ -353,9 +356,27 @@ private void createBuckets() { .forStatusCode(200) .waitUntilReady(this); + if (enabledServices.contains(CouchbaseService.QUERY)) { + // If the query service is enabled, make sure that we only proceed if the query engine also + // knows about the bucket in its metadata configuration. + Unreliables.retryUntilTrue(1, TimeUnit.MINUTES, () -> { + @Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() + .add("statement", "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" + bucket.getName() + "\"") + .build(), true); + + String body = queryResponse.body() != null ? queryResponse.body().string() : null; + checkSuccessfulResponse(queryResponse, "Could not poll query service state for bucket: " + bucket.getName()); + + return Optional.of(MAPPER.readTree(body)) + .map(n -> n.at("/results/0/present")) + .map(JsonNode::asBoolean) + .orElse(false); + }); + } + if (bucket.hasPrimaryIndex()) { if (enabledServices.contains(CouchbaseService.QUERY)) { - Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() + @Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() .add("statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`") .build(), true); @@ -384,14 +405,8 @@ private String getInternalIpAddress() { * @param message the message that should be part of the exception of not successful. */ private void checkSuccessfulResponse(final Response response, final String message) { - try { - if (!response.isSuccessful()) { - throw new IllegalStateException(message + ": " + response.toString()); - } - } finally { - if (response.body() != null) { - response.body().close(); - } + if (!response.isSuccessful()) { + throw new IllegalStateException(message + ": " + response.toString()); } } From 48534069037e17147208e65c3c7d3d03e3c83a47 Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Fri, 29 May 2020 15:02:06 +0200 Subject: [PATCH 0767/4969] Bump Couchbase Server Image Version (#2804) 6.5.1 got released in april 2020 and brings bugfixes and enhancements. Let's make sure users pick that up by default. --- .../java/org/testcontainers/couchbase/CouchbaseContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 92b35da3361..ee4b3212cac 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -71,7 +71,7 @@ public class CouchbaseContainer extends GenericContainer { private static final String DOCKER_IMAGE_NAME = "couchbase/server"; - private static final String VERSION = "6.5.0"; + private static final String VERSION = "6.5.1"; private static final ObjectMapper MAPPER = new ObjectMapper(); From c8edde492d76899abe3a4abd2faeef7d23b6801c Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 29 May 2020 15:49:51 +0100 Subject: [PATCH 0768/4969] Update mkdocs.yml --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index c28e0827f7c..795a2bdb4e2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -90,4 +90,4 @@ nav: - contributing.md - contributing_docs.md extra: - latest_version: 1.14.2 + latest_version: 1.14.3 From ee37dfce15f1be44e93123362c791466716bcffe Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 15:48:17 +0100 Subject: [PATCH 0769/4969] Bump aws-java-sdk-logs from 1.11.789 to 1.11.792 in /modules/localstack (#2822) Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.789 to 1.11.792. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.789...1.11.792) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 857b752ec1e..a6a73430c17 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,6 +6,6 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.789' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.789' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.792' testCompile 'software.amazon.awssdk:s3:2.13.23' } From 904337623fd75653e580faefce57dab854148b33 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 15:48:51 +0100 Subject: [PATCH 0770/4969] Bump aws-java-sdk-sqs from 1.11.789 to 1.11.792 in /modules/localstack (#2820) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index a6a73430c17..f3e093a49b8 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.784' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.789' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.792' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.792' testCompile 'software.amazon.awssdk:s3:2.13.23' } From 0a6e4159005db2b350041017422b175782ca7246 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 15:57:42 +0100 Subject: [PATCH 0771/4969] Bump solr-solrj from 8.5.1 to 8.5.2 in /examples (#2819) Bumps solr-solrj from 8.5.1 to 8.5.2. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 7e9b7a8c71f..5845753cb08 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.10" annotationProcessor "org.projectlombok:lombok:1.18.10" - implementation 'org.apache.solr:solr-solrj:8.5.1' + implementation 'org.apache.solr:solr-solrj:8.5.2' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From 46f085d0fe54a3a55ca5f80410911c73b98c4ea3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 15:57:51 +0100 Subject: [PATCH 0772/4969] Bump mssql-jdbc from 8.3.0.jre8-preview to 8.3.1.jre8-preview in /modules/mssqlserver (#2823) Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 8.3.0.jre8-preview to 8.3.1.jre8-preview. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/dev/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 8cdfa35dee1..bfb9777ddfa 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,12 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.2.RELEASE' testCompile project(':jdbc-test') - testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.0.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.1.jre8-preview' testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) - testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.0.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.1.jre8-preview' } From 289188be6d58c20b042fa7016453fe39875b6e28 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 15:58:02 +0100 Subject: [PATCH 0773/4969] Bump r2dbc-postgresql from 0.8.2.RELEASE to 0.8.3.RELEASE in /modules/postgresql (#2824) Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.2.RELEASE to 0.8.3.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-postgresql/blob/v0.8.3.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.2.RELEASE...v0.8.3.RELEASE) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 380a3f86a80..1d808b1555d 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -7,12 +7,12 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.2.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' testCompile project(':jdbc-test') testCompile project(':test-support') testCompile 'org.postgresql:postgresql:42.2.12' testCompile testFixtures(project(':r2dbc')) - testCompile 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' + testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' } From f6e48a49963be968b4662cfe8493c219daf82d29 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 15:59:17 +0100 Subject: [PATCH 0774/4969] Bump aws-java-sdk-s3 from 1.11.784 to 1.11.792 in /modules/localstack (#2817) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index f3e093a49b8..f35d38c3530 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.784' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.782' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.792' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.792' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.792' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.792' testCompile 'software.amazon.awssdk:s3:2.13.23' From 9a4a4a971eed573f77629ec025aeea10cb9114c8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 16:10:06 +0100 Subject: [PATCH 0775/4969] Bump r2dbc-mssql from 0.8.2.RELEASE to 0.8.3.RELEASE in /modules/mssqlserver (#2821) Bumps [r2dbc-mssql](https://github.com/r2dbc/r2dbc-mssql) from 0.8.2.RELEASE to 0.8.3.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-mssql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-mssql/blob/v0.8.3.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-mssql/compare/v0.8.2.RELEASE...v0.8.3.RELEASE) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index bfb9777ddfa..d9e01fe3a57 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -7,13 +7,13 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-mssql:0.8.2.RELEASE' + compileOnly 'io.r2dbc:r2dbc-mssql:0.8.3.RELEASE' testCompile project(':jdbc-test') testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.1.jre8-preview' testCompile project(':r2dbc') - testCompile 'io.r2dbc:r2dbc-mssql:0.8.1.RELEASE' + testCompile 'io.r2dbc:r2dbc-mssql:0.8.3.RELEASE' // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) From a5b4f2c6f8d9ee778389358040464fa1ca6f156e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 16:18:07 +0100 Subject: [PATCH 0776/4969] Bump testcontainers from 1.14.2 to 1.14.3 in /core (#2818) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 48bbf57d7e9..efe90a8b68d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -104,7 +104,7 @@ if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { } dependencies { - baseline 'org.testcontainers:testcontainers:1.14.2', { + baseline 'org.testcontainers:testcontainers:1.14.3', { exclude group: "*", module: "*" } From 0eb2dea4298088e35c59f7bf947812d807f9006e Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Mon, 1 Jun 2020 19:22:27 +0200 Subject: [PATCH 0777/4969] Switch to latest v5 release of release-drafter (#2815) Co-authored-by: Kevin Wittek --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 6f4e849bd5b..3123c3f6fac 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -9,6 +9,6 @@ jobs: update_release_draft: runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@v5.2.0 + - uses: release-drafter/release-drafter@v5.9.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From c3b85deb8a7bafac64bc47a01531522bfd7ba3b5 Mon Sep 17 00:00:00 2001 From: Erhun Baycelik Date: Thu, 4 Jun 2020 15:51:05 +0300 Subject: [PATCH 0778/4969] [Documentation Update] Update Mysql and Postgres tests example URLs (#2832) Tests url was outdated. --- docs/modules/databases/jdbc.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 5f83d7fcdeb..21393455a9f 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -115,5 +115,5 @@ Note that if you use `@Rule`, you will be given an isolated container for each t Examples/Tests: - * [MySQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimpleMySQLTest.java) - * [PostgreSQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/jdbc-test/src/test/java/org/testcontainers/junit/SimplePostgreSQLTest.java) \ No newline at end of file + * [MySQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java) + * [PostgreSQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java) From e94e13e67a9dadcc5e0fffb32d4827a25d176d89 Mon Sep 17 00:00:00 2001 From: Alexander Zapasnik Date: Thu, 4 Jun 2020 23:19:00 +0300 Subject: [PATCH 0779/4969] Migrate default postgis image to use the new docker hub repo (#2797) Co-authored-by: Kevin Wittek --- .../testcontainers/containers/PostgisContainerProvider.java | 4 ++-- .../testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java index 83f15e3fd6f..54c87a84648 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java @@ -10,8 +10,8 @@ public class PostgisContainerProvider extends JdbcDatabaseContainerProvider { private static final String NAME = "postgis"; - private static final String DEFAULT_TAG = "10"; - private static final String DEFAULT_IMAGE = "mdillon/postgis"; + private static final String DEFAULT_TAG = "12-3.0"; + private static final String DEFAULT_IMAGE = "postgis/postgis"; public static final String USER_PARAM = "user"; public static final String PASSWORD_PARAM = "password"; diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java index 551ba86e185..b1d01441016 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java @@ -16,7 +16,7 @@ public static Iterable data() { return asList( new Object[][]{ {"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - {"jdbc:tc:postgis:9.6://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + {"jdbc:tc:postgis:9.6-2.5://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, }); } } From 617cb73acb05d8f1fd8d2d626313d16fb8bff7ca Mon Sep 17 00:00:00 2001 From: SahilWadhwa Date: Fri, 5 Jun 2020 20:11:48 +0530 Subject: [PATCH 0780/4969] Enable AWS KMS For LocalStack 0.10.8 (#2812) Co-authored-by: Sahil --- .../localstack/LocalStackContainer.java | 3 ++- .../localstack/LocalstackContainerTest.java | 26 ++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 96cedb37726..72eb320c729 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -252,7 +252,8 @@ public enum Service { STEPFUNCTIONS("stepfunctions", 4585), CLOUDWATCHLOGS("logs", 4586), STS("sts", 4592), - IAM("iam", 4593); + IAM("iam", 4593), + KMS("kms", 4599); String localStackName; diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index ee5945d0aff..d4e2f0c2864 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -1,6 +1,11 @@ package org.testcontainers.containers.localstack; +import com.amazonaws.services.kms.AWSKMS; +import com.amazonaws.services.kms.AWSKMSClientBuilder; +import com.amazonaws.services.kms.model.CreateKeyRequest; +import com.amazonaws.services.kms.model.CreateKeyResult; +import com.amazonaws.services.kms.model.Tag; import com.amazonaws.services.logs.AWSLogs; import com.amazonaws.services.logs.AWSLogsClientBuilder; import com.amazonaws.services.logs.model.CreateLogGroupRequest; @@ -38,9 +43,7 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCHLOGS; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.*; /** * Tests for Localstack Container, used both in bridge network (exposed to host) and docker network modes. @@ -58,7 +61,7 @@ public static class WithoutNetwork { // without_network { @ClassRule public static LocalStackContainer localstack = new LocalStackContainer() - .withServices(S3, SQS, CLOUDWATCHLOGS); + .withServices(S3, SQS, CLOUDWATCHLOGS, KMS); // } @Test @@ -135,6 +138,21 @@ public void cloudWatchLogsTestOverBridgeNetwork() { assertEquals("One log group should be created", 1, groups.size()); assertEquals("Name of created log group is [foo]", "foo", groups.get(0).getLogGroupName()); } + + @Test + public void kmsKeyCreationTest() { + AWSKMS awskms = AWSKMSClientBuilder.standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(KMS)) + .withCredentials(localstack.getDefaultCredentialsProvider()) + .build(); + + String desc = String.format("AWS CMK Description"); + Tag createdByTag = new Tag().withTagKey("CreatedBy").withTagValue("StorageService"); + CreateKeyRequest req = new CreateKeyRequest().withDescription(desc).withTags(createdByTag); + CreateKeyResult key = awskms.createKey(req); + + assertEquals("AWS KMS Customer Managed Key should be created ", key.getKeyMetadata().getDescription(), desc); + } } public static class WithNetwork { From ff73a5e355ce72097fd2d7f7e0bf3879f213a514 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 5 Jun 2020 21:31:23 +0200 Subject: [PATCH 0781/4969] Clean up the deprecated methods (#2835) * Clean up the deprecated methods * fix the examples project * add japicmp excludes --- core/build.gradle | 44 +- .../containers/AmbassadorContainer.java | 67 --- .../testcontainers/containers/Container.java | 28 -- .../containers/GenericContainer.java | 110 +---- .../containers/traits/VncService.java | 22 - .../containers/wait/HostPortWaitStrategy.java | 31 -- .../containers/wait/HttpWaitStrategy.java | 77 ---- .../wait/LogMessageWaitStrategy.java | 29 -- .../testcontainers/containers/wait/Wait.java | 67 --- .../containers/wait/WaitAllStrategy.java | 41 -- .../containers/wait/WaitStrategy.java | 38 -- .../AuditLoggingDockerClient.java | 4 +- .../AuthDelegatingDockerClientConfig.java | 7 +- .../dockerclient/DockerClientConfigUtils.java | 11 +- .../DockerClientProviderStrategy.java | 1 - .../okhttp/NamedPipeSocketFactory.java | 134 ------ .../okhttp/OkHttpDockerCmdExecFactory.java | 162 ------- .../okhttp/OkHttpInvocationBuilder.java | 414 ------------------ .../transport/okhttp/OkHttpWebTarget.java | 113 ----- .../transport/okhttp/UnixSocketFactory.java | 92 ---- .../utility/ResourceReaper.java | 5 - .../linkedcontainer/RedmineContainer.java | 2 +- .../containers/ClickHouseContainer.java | 2 +- .../containers/PostgreSQLContainer.java | 3 +- .../containers/BrowserWebDriverContainer.java | 16 +- 25 files changed, 58 insertions(+), 1462 deletions(-) delete mode 100644 core/src/main/java/org/testcontainers/containers/AmbassadorContainer.java delete mode 100644 core/src/main/java/org/testcontainers/containers/traits/VncService.java delete mode 100644 core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java delete mode 100644 core/src/main/java/org/testcontainers/containers/wait/HttpWaitStrategy.java delete mode 100644 core/src/main/java/org/testcontainers/containers/wait/LogMessageWaitStrategy.java delete mode 100644 core/src/main/java/org/testcontainers/containers/wait/Wait.java delete mode 100644 core/src/main/java/org/testcontainers/containers/wait/WaitAllStrategy.java delete mode 100644 core/src/main/java/org/testcontainers/containers/wait/WaitStrategy.java rename core/src/main/java/org/testcontainers/dockerclient/{auth => }/AuthDelegatingDockerClientConfig.java (90%) delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java diff --git a/core/build.gradle b/core/build.gradle index efe90a8b68d..5011d24d70c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -89,9 +89,43 @@ task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { "org.testcontainers.shaded.*", ] + // TODO remove once 1.15.0 is released + classExcludes = [ + "org.testcontainers.containers.AmbassadorContainer", + "org.testcontainers.containers.traits.VncService", + "org.testcontainers.containers.wait.HostPortWaitStrategy", + "org.testcontainers.containers.wait.HttpWaitStrategy", + "org.testcontainers.containers.wait.LogMessageWaitStrategy", + "org.testcontainers.containers.wait.Wait", + "org.testcontainers.containers.wait.WaitAllStrategy", + "org.testcontainers.containers.wait.WaitStrategy", + "org.testcontainers.dockerclient.AuditLoggingDockerClient", + "org.testcontainers.dockerclient.auth.AuthDelegatingDockerClientConfig", + "org.testcontainers.containers.GenericContainer\$AbstractWaitStrategy", + "org.testcontainers.dockerclient.transport.okhttp.NamedPipeSocketFactory", + "org.testcontainers.dockerclient.transport.okhttp.OkHttpDockerCmdExecFactory", + "org.testcontainers.dockerclient.transport.okhttp.UnixSocketFactory", + ] + methodExcludes = [ - // METHOD_NEW_DEFAULT - "org.testcontainers.containers.ContainerState#getHost()" + "org.testcontainers.dockerclient.DockerClientConfigUtils#getDetectedDockerHostIp()", + "org.testcontainers.dockerclient.DockerClientConfigUtils#getDockerHostIpAddress(com.github.dockerjava.core.DockerClientConfig)", + + "org.testcontainers.utility.ResourceReaper#start(java.lang.String, com.github.dockerjava.api.DockerClient, boolean)", + + "org.testcontainers.containers.Container#fetchDockerDaemonInfo()", + "org.testcontainers.containers.Container#getDockerDaemonInfo()", + + "org.testcontainers.containers.GenericContainer#fetchDockerDaemonInfo()", + "org.testcontainers.containers.GenericContainer#getDockerDaemonInfo()", + + "org.testcontainers.containers.Container\$ExecResult#Container\$ExecResult(java.lang.String, java.lang.String)", + ] + + fieldExcludes = [ + "org.testcontainers.containers.GenericContainer#containerId", + "org.testcontainers.containers.GenericContainer#containerName", + "org.testcontainers.containers.GenericContainer#dockerDaemonInfo", ] onlyBinaryIncompatibleModified = true @@ -127,10 +161,6 @@ dependencies { compile "net.java.dev.jna:jna-platform:5.5.0" - shaded ('org.scala-sbt.ipcsocket:ipcsocket:1.0.1') { - exclude(group: "net.java.dev.jna") - } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.1') { exclude(group: 'net.java.dev.jna') exclude(group: 'com.google.code.findbug') @@ -140,8 +170,6 @@ dependencies { shaded "org.yaml:snakeyaml:1.25" - shaded 'com.squareup.okhttp3:okhttp:3.14.8' - shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' shaded 'org.zeroturnaround:zt-exec:1.10', { diff --git a/core/src/main/java/org/testcontainers/containers/AmbassadorContainer.java b/core/src/main/java/org/testcontainers/containers/AmbassadorContainer.java deleted file mode 100644 index 0b86821d293..00000000000 --- a/core/src/main/java/org/testcontainers/containers/AmbassadorContainer.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.testcontainers.containers; - -import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.model.Container; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.testcontainers.containers.traits.LinkableContainer; -import org.testcontainers.utility.TestcontainersConfiguration; - -import java.util.List; - -import static java.util.Arrays.asList; - -/** - * An ambassador container is used as a TCP proxy, enabling any TCP port of another linked container to be exposed - * publicly, even if that container does not make the port public itself. The richnorth/ambassador:latest - * container is used (based on HAProxy). - * - * @deprecated use {@link SocatContainer} - */ -@EqualsAndHashCode(callSuper = false) -@Data -@Deprecated -public class AmbassadorContainer> extends GenericContainer { - - private final String otherContainerName; - private final String serviceName; - private final int servicePort; - - public AmbassadorContainer(LinkableContainer otherContainer, String serviceName, int servicePort) { - super(TestcontainersConfiguration.getInstance().getAmbassadorContainerImage()); - - /* - Use the unique 'identifierPrefix' (random compose project name) so that the ambassador can see - the container it's supposed to be proxying. - */ - this.otherContainerName = otherContainer.getContainerName(); - this.serviceName = serviceName; - this.servicePort = servicePort; - - // Link - addLink(otherContainer, serviceName); - - // Expose ambassador's port - addExposedPort(servicePort); - - // Tell the proxy what to connect to within the docker network - addEnv("SERVICE_NAME", serviceName); - addEnv("SERVICE_PORT", String.format("%d", servicePort)); - } - - public boolean isServiceReady() { - try { - List allContainers = dockerClient.listContainersCmd().withShowAll(true).exec(); - - for (Container container : allContainers) { - if (asList(container.getNames()).contains("/" + otherContainerName) && !container.getStatus().contains("Exited")) { - return true; - } - } - - } catch (DockerException e) { - return false; - } - return false; - } -} diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index 631e2653ceb..9c1cb7f8034 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -2,7 +2,6 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Bind; -import com.github.dockerjava.api.model.Info; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NonNull; @@ -13,14 +12,9 @@ import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.containers.wait.strategy.WaitStrategy; -import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.LogUtils; import org.testcontainers.utility.MountableFile; -import org.testcontainers.utility.ThrowingFunction; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; import java.time.Duration; import java.util.List; import java.util.Map; @@ -48,14 +42,6 @@ class ExecResult { int exitCode; String stdout; String stderr; - - /** - * @deprecated should not be instantiated outside of the library, please migrate - */ - @Deprecated - public ExecResult(String stdout, String stderr) { - this(-1, stdout, stderr); - } } /** @@ -413,13 +399,6 @@ default void followOutput(Consumer consumer, OutputFrame.OutputType */ SELF withLogConsumer(Consumer consumer); - /** - * - * @deprecated please use {@code org.testcontainers.DockerClientFactory.instance().client().infoCmd().exec()} - */ - @Deprecated - Info fetchDockerDaemonInfo() throws IOException; - List getPortBindings(); List getExtraHosts(); @@ -447,13 +426,6 @@ default void followOutput(Consumer consumer, OutputFrame.OutputType DockerClient getDockerClient(); - /** - * - * @deprecated please use {@code org.testcontainers.DockerClientFactory.instance().client().infoCmd().exec()} - */ - @Deprecated - Info getDockerDaemonInfo(); - void setExposedPorts(List exposedPorts); void setPortBindings(List portBindings); diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index d906c320bd5..072129de60c 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -44,8 +44,8 @@ import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.traits.LinkableContainer; -import org.testcontainers.containers.wait.Wait; -import org.testcontainers.containers.wait.WaitStrategy; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.images.RemoteDockerImage; @@ -190,30 +190,13 @@ public class GenericContainer> @Setter(AccessLevel.NONE) protected DockerClient dockerClient = DockerClientFactory.lazyClient(); - /* - * Info about the Docker server; lazily fetched. - */ - @Setter(AccessLevel.NONE) - protected Info dockerDaemonInfo = null; - /** * Set during container startup - * // TODO make it private * - * @deprecated use {@link ContainerState#getContainerId()} */ @Setter(AccessLevel.NONE) - @Deprecated - protected String containerId; - - /** - * Set during container startup - * - * @deprecated use {@link GenericContainer#getContainerInfo()} - */ - @Setter(AccessLevel.NONE) - @Deprecated - protected String containerName; + @VisibleForTesting + String containerId; @Setter(AccessLevel.NONE) private InspectContainerResponse containerInfo; @@ -426,7 +409,6 @@ private void tryStart(Instant startedAt) { // Tell subclasses that we're starting containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); - containerName = containerInfo.getName(); containerIsStarting(containerInfo, reused); // Wait until the container has reached the desired running state @@ -1322,18 +1304,6 @@ public SELF withLogConsumer(Consumer consumer) { return self(); } - /** - * {@inheritDoc} - */ - @Override - public synchronized Info fetchDockerDaemonInfo() throws IOException { - - if (this.dockerDaemonInfo == null) { - this.dockerDaemonInfo = this.dockerClient.infoCmd().exec(); - } - return this.dockerDaemonInfo; - } - /** * {@inheritDoc} */ @@ -1403,74 +1373,8 @@ public int hashCode() { return System.identityHashCode(this); } - /** - * Convenience class with access to non-public members of GenericContainer. - * - * @deprecated use {@link org.testcontainers.containers.wait.strategy.AbstractWaitStrategy} - */ - @Deprecated - public static abstract class AbstractWaitStrategy extends org.testcontainers.containers.wait.strategy.AbstractWaitStrategy implements WaitStrategy { - protected GenericContainer container; - - @NonNull - protected Duration startupTimeout = Duration.ofSeconds(60); - - /** - * Wait until the container has started. - * - * @param container the container for which to wait - */ - @Override - public void waitUntilReady(GenericContainer container) { - this.container = container; - waitUntilReady(); - } - - /** - * Wait until {@link #container} has started. - */ - protected abstract void waitUntilReady(); - - /** - * Set the duration of waiting time until container treated as started. - * - * @param startupTimeout timeout - * @return this - * @see WaitStrategy#waitUntilReady(GenericContainer) - */ - public WaitStrategy withStartupTimeout(Duration startupTimeout) { - this.startupTimeout = startupTimeout; - return this; - } - - /** - * @return the container's logger - */ - protected Logger logger() { - return container.logger(); - } - - /** - * @return the port on which to check if the container is ready - * @deprecated see {@link AbstractWaitStrategy#getLivenessCheckPorts()} - */ - @Deprecated - protected Integer getLivenessCheckPort() { - return container.getLivenessCheckPort(); - } - - /** - * @return the ports on which to check if the container is ready - */ - protected Set getLivenessCheckPorts() { - return container.getLivenessCheckPorts(); - } - - /** - * @return the rate limiter to use - */ - protected RateLimiter getRateLimiter() { - return DOCKER_CLIENT_RATE_LIMITER; - } + @Override + public String getContainerName() { + return getContainerInfo().getName(); } } diff --git a/core/src/main/java/org/testcontainers/containers/traits/VncService.java b/core/src/main/java/org/testcontainers/containers/traits/VncService.java deleted file mode 100644 index c0f6458c2c0..00000000000 --- a/core/src/main/java/org/testcontainers/containers/traits/VncService.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.testcontainers.containers.traits; - -/** - * A container which exposes a VNC server. - */ -@Deprecated -public interface VncService { - /** - * @return a URL which can be used to connect to the VNC server from the machine running the tests. Exposed for convenience, e.g. to aid manual debugging - */ - String getVncAddress(); - - /** - * @return the VNC password for this server - */ - String getPassword(); - - /** - * @return the port number on which the VNC server is running - */ - int getPort(); -} diff --git a/core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java deleted file mode 100644 index e208b80345d..00000000000 --- a/core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.testcontainers.containers.wait; - -import lombok.extern.slf4j.Slf4j; -import org.testcontainers.containers.GenericContainer; - -import java.time.Duration; - -/** - * Waits until a socket connection can be established on a port exposed or mapped by the container. - * - * @author richardnorth - * - * @deprecated Use {@link org.testcontainers.containers.wait.strategy.HostPortWaitStrategy} - */ -@Deprecated -@Slf4j -public class HostPortWaitStrategy extends GenericContainer.AbstractWaitStrategy { - - private org.testcontainers.containers.wait.strategy.HostPortWaitStrategy delegateStrategy = new org.testcontainers.containers.wait.strategy.HostPortWaitStrategy(); - - @Override - protected void waitUntilReady() { - delegateStrategy.waitUntilReady(this.waitStrategyTarget); - } - - @Override - public WaitStrategy withStartupTimeout(Duration startupTimeout) { - delegateStrategy.withStartupTimeout(startupTimeout); - return super.withStartupTimeout(startupTimeout); - } -} diff --git a/core/src/main/java/org/testcontainers/containers/wait/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/HttpWaitStrategy.java deleted file mode 100644 index d27133c499d..00000000000 --- a/core/src/main/java/org/testcontainers/containers/wait/HttpWaitStrategy.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.testcontainers.containers.wait; - -import org.testcontainers.containers.GenericContainer; - -import java.util.function.Predicate; - -/** - * Waits until an HTTP(S) endpoint returns a given status code. - * - * @author Pete Cornish {@literal } - * - * @deprecated Use {@link org.testcontainers.containers.wait.strategy.HttpWaitStrategy} - */ -@Deprecated -public class HttpWaitStrategy extends GenericContainer.AbstractWaitStrategy { - - private org.testcontainers.containers.wait.strategy.HttpWaitStrategy delegateStrategy = new org.testcontainers.containers.wait.strategy.HttpWaitStrategy(); - - /** - * Waits for the given status code. - * - * @param statusCode the expected status code - * @return this - */ - public HttpWaitStrategy forStatusCode(int statusCode) { - delegateStrategy.forStatusCode(statusCode); - return this; - } - - /** - * Waits for the given path. - * - * @param path the path to check - * @return this - */ - public HttpWaitStrategy forPath(String path) { - delegateStrategy.forPath(path); - return this; - } - - /** - * Indicates that the status check should use HTTPS. - * - * @return this - */ - public HttpWaitStrategy usingTls() { - delegateStrategy.usingTls(); - return this; - } - - /** - * Authenticate with HTTP Basic Authorization credentials. - * - * @param username the username - * @param password the password - * @return this - */ - public HttpWaitStrategy withBasicCredentials(String username, String password) { - delegateStrategy.withBasicCredentials(username, password); - return this; - } - - /** - * Waits for the response to pass the given predicate - * @param responsePredicate The predicate to test the response against - * @return this - */ - public HttpWaitStrategy forResponsePredicate(Predicate responsePredicate) { - delegateStrategy.forResponsePredicate(responsePredicate); - return this; - } - - @Override - protected void waitUntilReady() { - delegateStrategy.waitUntilReady(this.waitStrategyTarget); - } -} diff --git a/core/src/main/java/org/testcontainers/containers/wait/LogMessageWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/LogMessageWaitStrategy.java deleted file mode 100644 index a21b6b66a59..00000000000 --- a/core/src/main/java/org/testcontainers/containers/wait/LogMessageWaitStrategy.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.testcontainers.containers.wait; - -import org.testcontainers.containers.GenericContainer; - -/** - * Waits until containers logs expected content. - * - * @deprecated Use {@link org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy} - */ -@Deprecated -public class LogMessageWaitStrategy extends GenericContainer.AbstractWaitStrategy { - - private org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy delegateWaitStrategy = new org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy(); - - @Override - protected void waitUntilReady() { - delegateWaitStrategy.waitUntilReady(this.waitStrategyTarget); - } - - public LogMessageWaitStrategy withRegEx(String regEx) { - delegateWaitStrategy.withRegEx(regEx); - return this; - } - - public LogMessageWaitStrategy withTimes(int times) { - delegateWaitStrategy.withTimes(times); - return this; - } -} diff --git a/core/src/main/java/org/testcontainers/containers/wait/Wait.java b/core/src/main/java/org/testcontainers/containers/wait/Wait.java deleted file mode 100644 index 66d055395c5..00000000000 --- a/core/src/main/java/org/testcontainers/containers/wait/Wait.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.testcontainers.containers.wait; - -import java.net.HttpURLConnection; - -/** - * Convenience class with logic for building common {@link WaitStrategy} instances. - * - * @author Pete Cornish {@literal } - * - * @deprecated Use {@link org.testcontainers.containers.wait.strategy.Wait} - */ -@Deprecated -public class Wait { - /** - * Convenience method to return the default WaitStrategy. - * - * @return a WaitStrategy - */ - public static WaitStrategy defaultWaitStrategy() { - return forListeningPort(); - } - - /** - * Convenience method to return a WaitStrategy for an exposed or mapped port. - * - * @return the WaitStrategy - * @see HostPortWaitStrategy - */ - public static HostPortWaitStrategy forListeningPort() { - return new HostPortWaitStrategy(); - } - - /** - * Convenience method to return a WaitStrategy for an HTTP endpoint. - * - * @param path the path to check - * @return the WaitStrategy - * @see HttpWaitStrategy - */ - public static HttpWaitStrategy forHttp(String path) { - return new HttpWaitStrategy() - .forPath(path); - } - - /** - * Convenience method to return a WaitStrategy for an HTTPS endpoint. - * - * @param path the path to check - * @return the WaitStrategy - * @see HttpWaitStrategy - */ - public static HttpWaitStrategy forHttps(String path) { - return forHttp(path) - .usingTls(); - } - - /** - * Convenience method to return a WaitStrategy for log messages. - * - * @param regex the regex pattern to check for - * @param times the number of times the pattern is expected - * @return LogMessageWaitStrategy - */ - public static LogMessageWaitStrategy forLogMessage(String regex, int times) { - return new LogMessageWaitStrategy().withRegEx(regex).withTimes(times); - } -} diff --git a/core/src/main/java/org/testcontainers/containers/wait/WaitAllStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/WaitAllStrategy.java deleted file mode 100644 index 7e3032cd76d..00000000000 --- a/core/src/main/java/org/testcontainers/containers/wait/WaitAllStrategy.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.testcontainers.containers.wait; - -import org.rnorth.ducttape.timeouts.Timeouts; -import org.testcontainers.containers.GenericContainer; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Wait strategy that waits for a number of other strategies to pass in series. - * - * @deprecated Use {@link org.testcontainers.containers.wait.strategy.WaitAllStrategy} - */ -@Deprecated -public class WaitAllStrategy implements WaitStrategy { - - private final List strategies = new ArrayList<>(); - private Duration timeout = Duration.ofSeconds(30); - - @Override - public void waitUntilReady(GenericContainer container) { - Timeouts.doWithTimeout((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> { - for (WaitStrategy strategy : strategies) { - strategy.waitUntilReady(container); - } - }); - } - - public WaitAllStrategy withStrategy(WaitStrategy strategy) { - this.strategies.add(strategy); - return this; - } - - @Override - public WaitStrategy withStartupTimeout(Duration startupTimeout) { - this.timeout = startupTimeout; - return this; - } -} diff --git a/core/src/main/java/org/testcontainers/containers/wait/WaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/WaitStrategy.java deleted file mode 100644 index ee2c14d90ae..00000000000 --- a/core/src/main/java/org/testcontainers/containers/wait/WaitStrategy.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.testcontainers.containers.wait; - -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; - -import java.time.Duration; - -/** - * Approach to determine whether a container is ready. - * - * @author Pete Cornish {@literal } - * - * @deprecated Use {@link org.testcontainers.containers.wait.strategy.WaitStrategy} - */ -@Deprecated -public interface WaitStrategy extends org.testcontainers.containers.wait.strategy.WaitStrategy { - /** - * Wait until the container has started. - * - * @param container the container for which to wait - */ - default void waitUntilReady(GenericContainer container) { - this.waitUntilReady((WaitStrategyTarget)container); - } - - /** - * @param startupTimeout the duration for which to wait - * @return this - */ - WaitStrategy withStartupTimeout(Duration startupTimeout); - - /** - * {@inheritDoc} - */ - default void waitUntilReady(WaitStrategyTarget waitStrategyTarget) { - //default method for backwards compatibility - } -} diff --git a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java index 891709e3a0c..2dc88cad313 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java @@ -16,12 +16,10 @@ * Wrapper for {@link DockerClient} to facilitate 'audit logging' of potentially destruction actions using * {@link org.testcontainers.utility.AuditLogger}. * - * @deprecated should not be used publicly */ @Slf4j @SuppressWarnings("unchecked") -@Deprecated -public class AuditLoggingDockerClient implements DockerClient { +class AuditLoggingDockerClient implements DockerClient { @Delegate(excludes = InterceptedMethods.class) private final DockerClient wrappedClient; diff --git a/core/src/main/java/org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig.java b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java similarity index 90% rename from core/src/main/java/org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig.java rename to core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java index a68605fdfda..c78a13c99ac 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java @@ -1,4 +1,4 @@ -package org.testcontainers.dockerclient.auth; +package org.testcontainers.dockerclient; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.core.DockerClientConfig; @@ -15,11 +15,10 @@ * to try and obtain auth credentials, but after that {@link RegistryAuthLocator} will be * used to try and improve the auth resolution (e.g. using credential helpers). * - * @deprecated should not be used publicly, to be moved to docker-java + * TODO move to docker-java */ @Slf4j -@Deprecated -public class AuthDelegatingDockerClientConfig implements DockerClientConfig { +class AuthDelegatingDockerClientConfig implements DockerClientConfig { @Delegate(excludes = DelegateExclusions.class) private DockerClientConfig delegate; diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java index 1060d663d65..b494eb087f6 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java @@ -1,6 +1,5 @@ package org.testcontainers.dockerclient; -import com.github.dockerjava.core.DockerClientConfig; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; @@ -18,10 +17,6 @@ public class DockerClientConfigUtils { // See https://github.com/docker/docker/blob/a9fa38b1edf30b23cae3eade0be48b3d4b1de14b/daemon/initlayer/setup_unix.go#L25 public static final boolean IN_A_CONTAINER = new File("/.dockerenv").exists(); - @Deprecated - @Getter(lazy = true) - private static final Optional detectedDockerHostIp = IN_A_CONTAINER ? getDefaultGateway() : Optional.empty(); - @Getter(lazy = true) private static final Optional defaultGateway = Optional .ofNullable(DockerClientFactory.instance().runInsideDocker( @@ -45,13 +40,9 @@ public class DockerClientConfigUtils { .filter(StringUtils::isNotBlank); /** - * Use {@link DockerClientFactory#dockerHostIpAddress()} + * @deprecated use {@link DockerClientProviderStrategy#getDockerHostIpAddress()} */ @Deprecated - public static String getDockerHostIpAddress(DockerClientConfig config) { - return getDockerHostIpAddress(config.getDockerHost()); - } - public static String getDockerHostIpAddress(URI dockerHost) { switch (dockerHost.getScheme()) { case "http": diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index c305d56389c..f0af6d51ae2 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -16,7 +16,6 @@ import org.rnorth.ducttape.unreliables.Unreliables; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testcontainers.dockerclient.auth.AuthDelegatingDockerClientConfig; import org.testcontainers.utility.TestcontainersConfiguration; import java.net.URI; diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java deleted file mode 100644 index d26e2977318..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/NamedPipeSocketFactory.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.testcontainers.dockerclient.transport.okhttp; - -import com.sun.jna.platform.win32.Kernel32; -import lombok.EqualsAndHashCode; -import lombok.SneakyThrows; -import lombok.Value; -import org.rnorth.ducttape.unreliables.Unreliables; - -import javax.net.SocketFactory; -import java.io.*; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.concurrent.TimeUnit; - -/** - * @deprecated use com.github.docker-java:docker-java-transport-okhttp - */ -@Deprecated -@Value -@EqualsAndHashCode(callSuper = false) -public class NamedPipeSocketFactory extends SocketFactory { - - String socketFileName; - - @Override - @SneakyThrows - public Socket createSocket() { - return new Socket() { - - RandomAccessFile file; - InputStream is; - OutputStream os; - - @Override - public void close() throws IOException { - if (file != null) { - file.close(); - file = null; - } - } - - @Override - public void connect(SocketAddress endpoint) { - connect(endpoint, 0); - } - - @Override - public void connect(SocketAddress endpoint, int timeout) { - file = Unreliables.retryUntilSuccess(Math.max(timeout, 10_000), TimeUnit.MILLISECONDS, () -> { - try { - return new RandomAccessFile(socketFileName, "rw"); - } catch (FileNotFoundException e) { - Kernel32.INSTANCE.WaitNamedPipe(socketFileName, 100); - throw e; - } - }); - - is = new InputStream() { - @Override - public int read(byte[] bytes, int off, int len) throws IOException { - if (OkHttpInvocationBuilder.CLOSING.get()) { - return 0; - } - return file.read(bytes, off, len); - } - - @Override - public int read() throws IOException { - if (OkHttpInvocationBuilder.CLOSING.get()) { - return 0; - } - return file.read(); - } - - @Override - public int read(byte[] bytes) throws IOException { - if (OkHttpInvocationBuilder.CLOSING.get()) { - return 0; - } - return file.read(bytes); - } - }; - - os = new OutputStream() { - @Override - public void write(byte[] bytes, int off, int len) throws IOException { - file.write(bytes, off, len); - } - - @Override - public void write(int value) throws IOException { - file.write(value); - } - - @Override - public void write(byte[] bytes) throws IOException { - file.write(bytes); - } - }; - } - - @Override - public InputStream getInputStream() { - return is; - } - - @Override - public OutputStream getOutputStream() { - return os; - } - }; - } - - @Override - public Socket createSocket(String s, int i) { - throw new UnsupportedOperationException(); - } - - @Override - public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) { - throw new UnsupportedOperationException(); - } - - @Override - public Socket createSocket(InetAddress inetAddress, int i) { - throw new UnsupportedOperationException(); - } - - @Override - public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) { - throw new UnsupportedOperationException(); - } -} diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java deleted file mode 100644 index 4da568834d5..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpDockerCmdExecFactory.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.testcontainers.dockerclient.transport.okhttp; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dockerjava.api.command.PingCmd; -import com.github.dockerjava.core.AbstractDockerCmdExecFactory; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.core.SSLConfig; -import com.github.dockerjava.core.WebTarget; -import com.github.dockerjava.core.exec.PingCmdExec; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.MultimapBuilder; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import okhttp3.ConnectionPool; -import okhttp3.Dns; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import org.apache.commons.io.IOUtils; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.X509TrustManager; -import java.io.IOException; -import java.net.InetAddress; -import java.net.URI; -import java.security.cert.X509Certificate; -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -/** - * @deprecated use com.github.docker-java:docker-java-transport-okhttp - */ -@Deprecated -@Slf4j -public class OkHttpDockerCmdExecFactory extends AbstractDockerCmdExecFactory { - - private static final String SOCKET_SUFFIX = ".socket"; - - private ObjectMapper objectMapper; - - private OkHttpClient okHttpClient; - - private HttpUrl baseUrl; - - @Override - @SneakyThrows - public void init(DockerClientConfig dockerClientConfig) { - super.init(dockerClientConfig); - - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() - .readTimeout(0, TimeUnit.SECONDS) - .retryOnConnectionFailure(true); - - URI dockerHost = dockerClientConfig.getDockerHost(); - switch (dockerHost.getScheme()) { - case "unix": - case "npipe": - String socketPath = dockerHost.getPath(); - - if ("unix".equals(dockerHost.getScheme())) { - clientBuilder - .socketFactory(new UnixSocketFactory(socketPath)); - } else { - clientBuilder - .socketFactory(new NamedPipeSocketFactory(socketPath)); - } - - clientBuilder - // Disable pooling - .connectionPool(new ConnectionPool(0, 1, TimeUnit.SECONDS)) - .dns(hostname -> { - if (hostname.endsWith(SOCKET_SUFFIX)) { - return Collections.singletonList(InetAddress.getByAddress(hostname, new byte[]{0, 0, 0, 0})); - } else { - return Dns.SYSTEM.lookup(hostname); - } - }); - default: - } - - SSLConfig sslConfig = dockerClientConfig.getSSLConfig(); - if (sslConfig != null) { - SSLContext sslContext = sslConfig.getSSLContext(); - if (sslContext != null) { - clientBuilder - .sslSocketFactory(sslContext.getSocketFactory(), new TrustAllX509TrustManager()); - } - } - - okHttpClient = clientBuilder.build(); - - HttpUrl.Builder baseUrlBuilder; - - switch (dockerHost.getScheme()) { - case "unix": - case "npipe": - baseUrlBuilder = new HttpUrl.Builder() - .scheme("http") - .host("docker" + SOCKET_SUFFIX); - break; - case "tcp": - baseUrlBuilder = new HttpUrl.Builder() - .scheme(sslConfig != null && sslConfig.getSSLContext() != null ? "https" : "http") - .host(dockerHost.getHost()) - .port(dockerHost.getPort()); - break; - default: - baseUrlBuilder = HttpUrl.get(dockerHost.toString()).newBuilder(); - } - baseUrl = baseUrlBuilder.build(); - - objectMapper = dockerClientConfig.getObjectMapper(); - } - - @Override - protected OkHttpWebTarget getBaseResource() { - return new OkHttpWebTarget( - objectMapper, - okHttpClient, - baseUrl, - ImmutableList.of(), - MultimapBuilder.hashKeys().hashSetValues().build() - ); - } - - @Override - public PingCmd.Exec createPingCmdExec() { - return new PingCmdExec(getBaseResource(), getDockerClientConfig()) { - - @Override - protected Void execute(PingCmd command) { - WebTarget webResource = getBaseResource().path("/_ping"); - - // TODO contribute to docker-java, make it close the stream - IOUtils.closeQuietly(webResource.request().get()); - - return null; - } - }; - } - - @Override - public void close() throws IOException { - - } - - private static class TrustAllX509TrustManager implements X509TrustManager { - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { - - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { - - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - } -} diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java deleted file mode 100644 index cada10328ec..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpInvocationBuilder.java +++ /dev/null @@ -1,414 +0,0 @@ -package org.testcontainers.dockerclient.transport.okhttp; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dockerjava.api.async.ResultCallback; -import com.github.dockerjava.api.exception.BadRequestException; -import com.github.dockerjava.api.exception.ConflictException; -import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.exception.InternalServerErrorException; -import com.github.dockerjava.api.exception.NotAcceptableException; -import com.github.dockerjava.api.exception.NotFoundException; -import com.github.dockerjava.api.exception.NotModifiedException; -import com.github.dockerjava.api.exception.UnauthorizedException; -import com.github.dockerjava.api.model.Frame; -import com.github.dockerjava.api.model.StreamType; -import com.github.dockerjava.core.InvocationBuilder; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.experimental.FieldDefaults; -import lombok.extern.slf4j.Slf4j; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.internal.connection.RealConnection; -import okio.*; -import org.jetbrains.annotations.Nullable; -import org.testcontainers.DockerClientFactory; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Objects; -import java.util.function.Consumer; - -@Slf4j -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -class OkHttpInvocationBuilder implements InvocationBuilder { - - static final ThreadLocal CLOSING = ThreadLocal.withInitial(() -> false); - - ObjectMapper objectMapper; - - OkHttpClient okHttpClient; - - Request.Builder requestBuilder; - - public OkHttpInvocationBuilder(ObjectMapper objectMapper, OkHttpClient okHttpClient, HttpUrl httpUrl) { - this.objectMapper = objectMapper; - this.okHttpClient = okHttpClient; - - requestBuilder = new Request.Builder() - .url(httpUrl); - } - - @Override - public OkHttpInvocationBuilder accept(com.github.dockerjava.core.MediaType mediaType) { - return header("accept", mediaType.getMediaType()); - } - - @Override - public OkHttpInvocationBuilder header(String name, String value) { - requestBuilder.header(name, value); - return this; - } - - @Override - @SneakyThrows - public void delete() { - Request request = requestBuilder - .delete() - .build(); - - execute(request).close(); - } - - @Override - @SneakyThrows - public void get(ResultCallback resultCallback) { - Request request = requestBuilder - .get() - .build(); - - executeAndStream( - request, - resultCallback, - new FramedSink(resultCallback) - ); - } - - @Override - @SneakyThrows(IOException.class) - public T get(TypeReference typeReference) { - try (InputStream inputStream = get()) { - return objectMapper.readValue(inputStream, typeReference); - } - } - - @Override - public void get(TypeReference typeReference, ResultCallback resultCallback) { - Request request = requestBuilder - .get() - .build(); - - executeAndStream( - request, - resultCallback, - new JsonSink<>(objectMapper, typeReference, resultCallback) - ); - } - - @Override - @SneakyThrows - public InputStream post(Object entity) { - Request request = requestBuilder - .post(RequestBody.create(MediaType.parse("application/json"), objectMapper.writeValueAsBytes(entity))) - .build(); - - return execute(request).body().byteStream(); - } - - @Override - @SneakyThrows - public T post(Object entity, TypeReference typeReference) { - Request request = requestBuilder - .post(RequestBody.create(MediaType.parse("application/json"), objectMapper.writeValueAsBytes(entity))) - .build(); - - try (Response response = execute(request)) { - String inputStream = response.body().string(); - return objectMapper.readValue(inputStream, typeReference); - } - } - - @Override - @SneakyThrows(JsonProcessingException.class) - public void post(Object entity, TypeReference typeReference, ResultCallback resultCallback) { - post(typeReference, resultCallback, new ByteArrayInputStream(objectMapper.writeValueAsBytes(entity))); - } - - @Override - @SneakyThrows(IOException.class) - public T post(TypeReference typeReference, InputStream body) { - try (InputStream inputStream = post(body)) { - return objectMapper.readValue(inputStream, typeReference); - } - } - - @Override - @SneakyThrows - public void post(Object entity, InputStream stdin, ResultCallback resultCallback) { - Request request = requestBuilder - .post(RequestBody.create(MediaType.parse("application/json"), objectMapper.writeValueAsBytes(entity))) - .build(); - - OkHttpClient okHttpClient = this.okHttpClient; - - if (stdin != null) { - // FIXME there must be a better way of handling it - okHttpClient = okHttpClient.newBuilder() - .addNetworkInterceptor(chain -> { - Response response = chain.proceed(chain.request()); - if (response.isSuccessful()) { - Thread thread = new Thread() { - @Override - @SneakyThrows - public void run() { - Field sinkField = RealConnection.class.getDeclaredField("sink"); - sinkField.setAccessible(true); - - try ( - BufferedSink sink = (BufferedSink) sinkField.get(chain.connection()); - Source source = Okio.source(stdin); - ) { - sink.writeAll(source); - } - } - }; - thread.start(); - } - return response; - }) - .build(); - } - - executeAndStream( - okHttpClient, - request, - resultCallback, - new FramedSink(resultCallback) - ); - } - - @Override - public void post(TypeReference typeReference, ResultCallback resultCallback, InputStream body) { - Request request = requestBuilder - .post(toRequestBody(body, null)) - .build(); - - executeAndStream( - request, - resultCallback, - new JsonSink<>(objectMapper, typeReference, resultCallback) - ); - } - - @Override - @SneakyThrows - public void postStream(InputStream body) { - Request request = requestBuilder - .post(toRequestBody(body, null)) - .build(); - - execute(request).close(); - } - - @Override - @SneakyThrows - public InputStream get() { - Request request = requestBuilder - .get() - .build(); - - return execute(request).body().byteStream(); - } - - @Override - @SneakyThrows - public void put(InputStream body, com.github.dockerjava.core.MediaType mediaType) { - Request request = requestBuilder - .put(toRequestBody(body, mediaType.toString())) - .build(); - - execute(request).close(); - } - - protected RequestBody toRequestBody(InputStream body, @Nullable String mediaType) { - return new RequestBody() { - @Nullable - @Override - public MediaType contentType() { - if (mediaType == null) { - return null; - } - return MediaType.parse(mediaType); - } - - @Override - public void writeTo(BufferedSink sink) throws IOException { - try (Source source = Okio.source(body)) { - sink.writeAll(source); - } - } - }; - } - - protected Response execute(Request request) { - return execute(okHttpClient, request); - } - - @SneakyThrows(IOException.class) - protected Response execute(OkHttpClient okHttpClient, Request request) { - Response response = okHttpClient.newCall(request).execute(); - if (!response.isSuccessful()) { - String body = response.body().string(); - switch (response.code()) { - case 304: - throw new NotModifiedException(body); - case 400: - throw new BadRequestException(body); - case 401: - throw new UnauthorizedException(body); - case 404: - throw new NotFoundException(body); - case 406: - throw new NotAcceptableException(body); - case 409: - throw new ConflictException(body); - case 500: - throw new InternalServerErrorException(body); - default: - throw new DockerException(body, response.code()); - } - } else { - return response; - } - } - - protected void executeAndStream(Request request, ResultCallback callback, Consumer sourceConsumer) { - executeAndStream(okHttpClient, request, callback, sourceConsumer); - } - - protected void executeAndStream(OkHttpClient okHttpClient, Request request, ResultCallback callback, Consumer sourceConsumer) { - Thread thread = new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { - try ( - Response response = execute(okHttpClient, request.newBuilder().tag("streaming").build()); - BufferedSource source = response.body().source(); - ) { - callback.onStart(() -> { - boolean previous = CLOSING.get(); - CLOSING.set(true); - try { - response.close(); - } finally { - CLOSING.set(previous); - } - }); - - sourceConsumer.accept(source); - callback.onComplete(); - } catch (Exception e) { - callback.onError(e); - } - }, "tc-okhttp-stream-" + Objects.hashCode(request)); - thread.setDaemon(true); - - thread.start(); - } - - @RequiredArgsConstructor - @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) - private static class JsonSink implements Consumer { - - ObjectMapper objectMapper; - - TypeReference typeReference; - - ResultCallback resultCallback; - - @Override - public void accept(BufferedSource source) { - try { - while (true) { - String line = source.readUtf8Line(); - if (line == null) { - break; - } - - resultCallback.onNext(objectMapper.readValue(line, typeReference)); - } - } catch (Exception e) { - resultCallback.onError(e); - } - } - } - - @RequiredArgsConstructor - @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) - private static class FramedSink implements Consumer { - - private static final int HEADER_SIZE = 8; - - ResultCallback resultCallback; - - @Override - public void accept(BufferedSource source) { - try { - while (!source.exhausted()) { - // See https://docs.docker.com/engine/api/v1.37/#operation/ContainerAttach - // [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT} - - if (!source.request(HEADER_SIZE)) { - return; - } - byte[] bytes = source.readByteArray(HEADER_SIZE); - - StreamType streamType = streamType(bytes[0]); - - if (streamType == StreamType.RAW) { - resultCallback.onNext(new Frame(StreamType.RAW, bytes)); - byte[] buffer = new byte[1024]; - while (!source.exhausted()) { - int readBytes = source.read(buffer); - if (readBytes != -1) { - resultCallback.onNext(new Frame(StreamType.RAW, Arrays.copyOf(buffer, readBytes))); - } - } - return; - } - - int payloadSize = ByteBuffer.wrap(bytes, 4, 4).getInt(); - if (!source.request(payloadSize)) { - return; - } - byte[] payload = source.readByteArray(payloadSize); - - resultCallback.onNext(new Frame(streamType, payload)); - } - } catch (Exception e) { - resultCallback.onError(e); - } - } - - private static StreamType streamType(byte streamType) { - switch (streamType) { - case 0: - return StreamType.STDIN; - case 1: - return StreamType.STDOUT; - case 2: - return StreamType.STDERR; - default: - return StreamType.RAW; - } - } - } -} diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java deleted file mode 100644 index 9c360522d20..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/OkHttpWebTarget.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.testcontainers.dockerclient.transport.okhttp; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dockerjava.core.InvocationBuilder; -import com.github.dockerjava.core.WebTarget; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.SetMultimap; -import lombok.SneakyThrows; -import lombok.Value; -import lombok.experimental.Wither; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import org.apache.commons.lang.StringUtils; - -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -@Wither -@Value -class OkHttpWebTarget implements WebTarget { - - ObjectMapper objectMapper; - - OkHttpClient okHttpClient; - - HttpUrl baseUrl; - - ImmutableList path; - - SetMultimap queryParams; - - @Override - @SneakyThrows - public InvocationBuilder request() { - String resource = StringUtils.join(path, "/"); - - if (!resource.startsWith("/")) { - resource = "/" + resource; - } - - HttpUrl.Builder baseUrlBuilder = baseUrl.newBuilder() - .encodedPath(resource); - - for (Map.Entry> queryParamEntry : queryParams.asMap().entrySet()) { - String key = queryParamEntry.getKey(); - for (String paramValue : queryParamEntry.getValue()) { - baseUrlBuilder.addQueryParameter(key, paramValue); - } - } - - return new OkHttpInvocationBuilder( - objectMapper, - okHttpClient, - baseUrlBuilder.build() - ); - } - - @Override - public OkHttpWebTarget path(String... components) { - return this.withPath( - ImmutableList.builder() - .addAll(path) - .add(components) - .build() - ); - } - - @Override - public OkHttpWebTarget resolveTemplate(String name, Object value) { - ImmutableList.Builder newPath = ImmutableList.builder(); - for (String component : path) { - component = component.replaceAll("\\{" + name + "\\}", value.toString()); - newPath.add(component); - } - return this.withPath(newPath.build()); - } - - @Override - public OkHttpWebTarget queryParam(String name, Object value) { - if (value == null) { - return this; - } - - SetMultimap newQueryParams = HashMultimap.create(queryParams); - newQueryParams.put(name, value.toString()); - - return this.withQueryParams(newQueryParams); - } - - @Override - public OkHttpWebTarget queryParamsSet(String name, Set values) { - SetMultimap newQueryParams = HashMultimap.create(queryParams); - newQueryParams.replaceValues(name, values.stream().filter(Objects::nonNull).map(Object::toString).collect(Collectors.toSet())); - - return this.withQueryParams(newQueryParams); - } - - @Override - @SneakyThrows(JsonProcessingException.class) - public OkHttpWebTarget queryParamsJsonMap(String name, Map values) { - if (values == null || values.isEmpty()) { - return this; - } - - // when param value is JSON string - return queryParam(name, objectMapper.writeValueAsString(values)); - } -} diff --git a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java b/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java deleted file mode 100644 index d1e55f3e647..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/transport/okhttp/UnixSocketFactory.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.testcontainers.dockerclient.transport.okhttp; - -import lombok.EqualsAndHashCode; -import lombok.SneakyThrows; -import lombok.Value; -import org.scalasbt.ipcsocket.UnixDomainSocket; - -import javax.net.SocketFactory; -import java.io.FilterInputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketAddress; - -/** - * @deprecated use com.github.docker-java:docker-java-transport-okhttp - */ -@Deprecated -@Value -@EqualsAndHashCode(callSuper = false) -public class UnixSocketFactory extends SocketFactory { - - String socketPath; - - @Override - @SneakyThrows - public Socket createSocket() { - return new UnixDomainSocket(socketPath) { - @Override - public void connect(SocketAddress endpoint, int timeout) throws IOException { - // Do nothing since it's not "connectable" - } - - @Override - public InputStream getInputStream() { - return new FilterInputStream(super.getInputStream()) { - @Override - public void close() throws IOException { - shutdownInput(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - if (OkHttpInvocationBuilder.CLOSING.get()) { - return 0; - } - return super.read(b, off, len); - } - }; - } - - @Override - public OutputStream getOutputStream() { - return new FilterOutputStream(super.getOutputStream()) { - - @Override - public void write(byte[] b, int off, int len) throws IOException { - out.write(b, off, len); - } - - @Override - public void close() throws IOException { - shutdownOutput(); - } - }; - } - }; - } - - @Override - public Socket createSocket(String s, int i) { - throw new UnsupportedOperationException(); - } - - @Override - public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) { - throw new UnsupportedOperationException(); - } - - @Override - public Socket createSocket(InetAddress inetAddress, int i) { - throw new UnsupportedOperationException(); - } - - @Override - public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) { - throw new UnsupportedOperationException(); - } -} diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 2f668d80426..4d44cbc3842 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -70,11 +70,6 @@ private ResourceReaper() { dockerClient = DockerClientFactory.instance().client(); } - @Deprecated - public static String start(String hostIpAddress, DockerClient client, boolean withDummyMount) { - return start(hostIpAddress, client); - } - @SneakyThrows(InterruptedException.class) public static String start(String hostIpAddress, DockerClient client) { String ryukImage = TestcontainersConfiguration.getInstance().getRyukImage(); diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java index a4e8cceb558..113d0a76ec0 100644 --- a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java @@ -2,7 +2,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.traits.LinkableContainer; -import org.testcontainers.containers.wait.Wait; +import org.testcontainers.containers.wait.strategy.Wait; /** * A Redmine container. diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 10c0e1835c2..dd48f32bece 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -1,6 +1,6 @@ package org.testcontainers.containers; -import org.testcontainers.containers.wait.HttpWaitStrategy; +import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import java.time.Duration; diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 6ba7390878e..1c814044023 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -1,13 +1,12 @@ package org.testcontainers.containers; import org.jetbrains.annotations.NotNull; -import org.testcontainers.containers.wait.LogMessageWaitStrategy; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import java.time.Duration; import java.util.HashSet; import java.util.Set; -import static java.lang.String.format; import static java.time.temporal.ChronoUnit.SECONDS; /** diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 397f6c4a2cf..16127171c59 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -19,11 +19,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.containers.traits.LinkableContainer; -import org.testcontainers.containers.traits.VncService; -import org.testcontainers.containers.wait.HostPortWaitStrategy; -import org.testcontainers.containers.wait.LogMessageWaitStrategy; -import org.testcontainers.containers.wait.WaitAllStrategy; -import org.testcontainers.containers.wait.WaitStrategy; +import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.containers.wait.strategy.WaitAllStrategy; +import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.lifecycle.TestDescription; import org.testcontainers.lifecycle.TestLifecycleAware; @@ -44,7 +43,7 @@ *

* The container should expose Selenium remote control protocol and VNC. */ -public class BrowserWebDriverContainer> extends GenericContainer implements VncService, LinkableContainer, TestLifecycleAware { +public class BrowserWebDriverContainer> extends GenericContainer implements LinkableContainer, TestLifecycleAware { private static final String CHROME_IMAGE = "selenium/standalone-chrome-debug:%s"; private static final String FIREFOX_IMAGE = "selenium/standalone-firefox-debug:%s"; @@ -214,17 +213,16 @@ public URL getSeleniumAddress() { } } - @Override public String getVncAddress() { return "vnc://vnc:secret@" + getHost() + ":" + getMappedPort(VNC_PORT); } - @Override + @Deprecated public String getPassword() { return DEFAULT_PASSWORD; } - @Override + @Deprecated public int getPort() { return VNC_PORT; } From ddae79c2c0ae65d3cf2e898c5aeea9fcf3a55ecd Mon Sep 17 00:00:00 2001 From: Kyle Aure Date: Fri, 5 Jun 2020 16:22:34 -0500 Subject: [PATCH 0782/4969] Add acceptLicense method to MSSQLServerContainer (#2085) Co-authored-by: Richard North --- docs/modules/databases/mssqlserver.md | 5 +++-- .../containers/MSSQLServerContainer.java | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/modules/databases/mssqlserver.md b/docs/modules/databases/mssqlserver.md index 9e0bec25dad..29c5435be32 100644 --- a/docs/modules/databases/mssqlserver.md +++ b/docs/modules/databases/mssqlserver.md @@ -10,7 +10,8 @@ Running MS SQL Server as a stand-in for in a test: public class SomeTest { @Rule - public MSSQLServerContainer mssqlserver = new MSSQLServerContainer(); + public MSSQLServerContainer mssqlserver = new MSSQLServerContainer() + .acceptLicense(); @Test public void someTestMethod() { @@ -20,7 +21,7 @@ public class SomeTest { ``` !!! warning "EULA Acceptance" - Due to licencing restrictions you are required to accept an EULA for this container image. To indicate that you accept the MS SQL Server image EULA, Please place a file at the root of the classpath named `container-license-acceptance.txt`, e.g. at `src/test/resources/container-license-acceptance.txt`. This file should contain the line: `mcr.microsoft.com/mssql/server:2017-CU12` (or, if you are overriding the docker image name/tag, update accordingly). + Due to licencing restrictions you are required to accept an EULA for this container image. To indicate that you accept the MS SQL Server image EULA, call the `acceptLicense()` method, or place a file at the root of the classpath named `container-license-acceptance.txt`, e.g. at `src/test/resources/container-license-acceptance.txt`. This file should contain the line: `mcr.microsoft.com/mssql/server:2017-CU12` (or, if you are overriding the docker image name/tag, update accordingly). Please see the [`microsoft-mssql-server` image documentation](https://hub.docker.com/_/microsoft-mssql-server#environment-variables) for a link to the EULA document. diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index b500e6fddf0..7550f820d51 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -50,11 +50,24 @@ protected Integer getLivenessCheckPort() { @Override protected void configure() { - LicenseAcceptance.assertLicenseAccepted(this.getDockerImageName()); - addEnv("ACCEPT_EULA", "Y"); + // If license was not accepted programatically, check if it was accepted via resource file + if (!getEnvMap().containsKey("ACCEPT_EULA")) { + LicenseAcceptance.assertLicenseAccepted(this.getDockerImageName()); + acceptLicense(); + } + addEnv("SA_PASSWORD", password); } + /** + * Accepts the license for the SQLServer container by setting the ACCEPT_EULA=Y + * variable as described at https://hub.docker.com/_/microsoft-mssql-server + */ + public SELF acceptLicense() { + addEnv("ACCEPT_EULA", "Y"); + return self(); + } + @Override public String getDriverClassName() { return "com.microsoft.sqlserver.jdbc.SQLServerDriver"; @@ -116,6 +129,5 @@ private void checkPasswordStrength(String password) { "or percent (%)." ); } - } } From 0035c311b8cd3dc342a092992efdf39d158264b6 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 6 Jun 2020 09:35:01 +0200 Subject: [PATCH 0783/4969] Avoid connection leaks in `LogUtils` (#2834) --- .../wait/strategy/LogMessageWaitStrategy.java | 37 ++++++++++++++----- .../org/testcontainers/utility/LogUtils.java | 26 ++++++++----- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java index bd164096300..9f7a0078f00 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java @@ -1,15 +1,21 @@ package org.testcontainers.containers.wait.strategy; +import com.github.dockerjava.api.command.LogContainerCmd; +import lombok.SneakyThrows; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.output.FrameConsumerResultCallback; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.WaitingConsumer; -import org.testcontainers.utility.LogUtils; +import java.io.IOException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Predicate; +import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; +import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; + public class LogMessageWaitStrategy extends AbstractWaitStrategy { private String regEx; @@ -17,18 +23,31 @@ public class LogMessageWaitStrategy extends AbstractWaitStrategy { private int times = 1; @Override + @SneakyThrows(IOException.class) protected void waitUntilReady() { WaitingConsumer waitingConsumer = new WaitingConsumer(); - LogUtils.followOutput(DockerClientFactory.instance().client(), waitStrategyTarget.getContainerId(), waitingConsumer); - Predicate waitPredicate = outputFrame -> - // (?s) enables line terminator matching (equivalent to Pattern.DOTALL) - outputFrame.getUtf8String().matches("(?s)" + regEx); + LogContainerCmd cmd = DockerClientFactory.instance().client().logContainerCmd(waitStrategyTarget.getContainerId()) + .withFollowStream(true) + .withSince(0) + .withStdOut(true) + .withStdErr(true); + + try (FrameConsumerResultCallback callback = new FrameConsumerResultCallback()) { + callback.addConsumer(STDOUT, waitingConsumer); + callback.addConsumer(STDERR, waitingConsumer); + + cmd.exec(callback); + + Predicate waitPredicate = outputFrame -> + // (?s) enables line terminator matching (equivalent to Pattern.DOTALL) + outputFrame.getUtf8String().matches("(?s)" + regEx); - try { - waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, times); - } catch (TimeoutException e) { - throw new ContainerLaunchException("Timed out waiting for log output matching '" + regEx + "'"); + try { + waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, times); + } catch (TimeoutException e) { + throw new ContainerLaunchException("Timed out waiting for log output matching '" + regEx + "'"); + } } } diff --git a/core/src/main/java/org/testcontainers/utility/LogUtils.java b/core/src/main/java/org/testcontainers/utility/LogUtils.java index b51325cdda7..ce27387490f 100644 --- a/core/src/main/java/org/testcontainers/utility/LogUtils.java +++ b/core/src/main/java/org/testcontainers/utility/LogUtils.java @@ -2,12 +2,15 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.LogContainerCmd; +import lombok.SneakyThrows; import lombok.experimental.UtilityClass; import org.testcontainers.containers.output.FrameConsumerResultCallback; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.ToStringConsumer; import org.testcontainers.containers.output.WaitingConsumer; +import java.io.Closeable; +import java.io.IOException; import java.util.function.Consumer; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; @@ -59,6 +62,7 @@ public void followOutput(DockerClient dockerClient, * @param types types of {@link OutputFrame} to receive * @return all previous output frames (stdout/stderr being separated by newline characters) */ + @SneakyThrows(IOException.class) public String getOutput(DockerClient dockerClient, String containerId, OutputFrame.OutputType... types) { @@ -73,17 +77,19 @@ public String getOutput(DockerClient dockerClient, final ToStringConsumer consumer = new ToStringConsumer(); final WaitingConsumer wait = new WaitingConsumer(); - attachConsumer(dockerClient, containerId, consumer.andThen(wait), false, types); - - wait.waitUntilEnd(); - return consumer.toUtf8String(); + try (Closeable closeable = attachConsumer(dockerClient, containerId, consumer.andThen(wait), false, types)) { + wait.waitUntilEnd(); + return consumer.toUtf8String(); + } } - private static void attachConsumer(DockerClient dockerClient, - String containerId, - Consumer consumer, - boolean followStream, - OutputFrame.OutputType... types) { + private static Closeable attachConsumer( + DockerClient dockerClient, + String containerId, + Consumer consumer, + boolean followStream, + OutputFrame.OutputType... types + ) { final LogContainerCmd cmd = dockerClient.logContainerCmd(containerId) .withFollowStream(followStream) @@ -96,6 +102,6 @@ private static void attachConsumer(DockerClient dockerClient, if (type == STDERR) cmd.withStdErr(true); } - cmd.exec(callback); + return cmd.exec(callback); } } From 54b3a1869468866a2f2e0b0a003f5a0abcc3f2b4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 08:46:11 +0100 Subject: [PATCH 0784/4969] Bump mongo-java-driver from 3.12.4 to 3.12.5 in /core (#2844) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.4 to 3.12.5. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.4...r3.12.5) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 5011d24d70c..e728f1cd48b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -179,7 +179,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.3.0' testCompile 'com.rabbitmq:amqp-client:5.9.0' - testCompile 'org.mongodb:mongo-java-driver:3.12.4' + testCompile 'org.mongodb:mongo-java-driver:3.12.5' testCompile ('org.mockito:mockito-core:3.3.3') { exclude(module: 'hamcrest-core') From a4d6963712edd0bdba21e2c7be06c622c80ec943 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 08:48:27 +0100 Subject: [PATCH 0785/4969] Bump elasticsearch-rest-client from 7.6.2 to 7.7.1 in /modules/elasticsearch (#2841) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.6.2 to 7.7.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.6.2...v7.7.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 6deaf802112..04e038864ce 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.6.2" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.7.1" testCompile "org.elasticsearch.client:transport:6.7.1" } From 6d97aa2b5e3e402de7464968bb348e5f9b1049d3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 08:49:28 +0100 Subject: [PATCH 0786/4969] Bump postgresql from 42.2.12 to 42.2.13 in /examples (#2842) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.12 to 42.2.13. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.12...REL42.2.13) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 96dd03c602b..79b66e15c57 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:3.14.8' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.12' + testImplementation 'org.postgresql:postgresql:42.2.13' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From adc3729b0d2a949df8c1f2aea1a5bfa0f64580d4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 08:50:02 +0100 Subject: [PATCH 0787/4969] Bump postgresql from 42.2.12 to 42.2.13 in /modules/spock (#2840) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.12 to 42.2.13. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.12...REL42.2.13) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index fea1c8baa2d..7e1b05b7719 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testRuntime 'org.postgresql:postgresql:42.2.12' + testRuntime 'org.postgresql:postgresql:42.2.13' testRuntime 'mysql:mysql-connector-java:8.0.20' } From 7c1d2f1f4d1b7a005f48404b5418419e3ad94ca8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 11:48:34 +0100 Subject: [PATCH 0788/4969] Bump postgresql from 42.2.12 to 42.2.13 in /modules/junit-jupiter (#2845) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.12 to 42.2.13. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.12...REL42.2.13) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 485e02f6089..301c7eaaecc 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'org.assertj:assertj-core:3.16.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' - testRuntime 'org.postgresql:postgresql:42.2.12' + testRuntime 'org.postgresql:postgresql:42.2.13' testRuntime 'mysql:mysql-connector-java:8.0.20' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' } From db6e555391a6c6d3d69ec3f458caf37923950672 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 11:50:09 +0100 Subject: [PATCH 0789/4969] Bump aws-java-sdk-sqs from 1.11.792 to 1.11.797 in /modules/localstack (#2847) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.792 to 1.11.797. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.792...1.11.797) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index f35d38c3530..ed37cadfb65 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.792' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.792' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.792' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.792' testCompile 'software.amazon.awssdk:s3:2.13.23' } From ec1c516d4ed77d2adf39f125c77d58acbe07b6aa Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 11:50:23 +0100 Subject: [PATCH 0790/4969] Bump s3 from 2.13.23 to 2.13.31 in /modules/localstack (#2848) Bumps s3 from 2.13.23 to 2.13.31. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ed37cadfb65..4a643d5b7f5 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.792' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.792' - testCompile 'software.amazon.awssdk:s3:2.13.23' + testCompile 'software.amazon.awssdk:s3:2.13.31' } From 99cf50d09cfe6d5817f4d8b1b06e2899214ffe8a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 11:51:18 +0100 Subject: [PATCH 0791/4969] Bump postgresql from 42.2.12 to 42.2.13 in /modules/postgresql (#2846) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.12 to 42.2.13. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.12...REL42.2.13) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 1d808b1555d..2fe381f5fb4 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':jdbc-test') testCompile project(':test-support') - testCompile 'org.postgresql:postgresql:42.2.12' + testCompile 'org.postgresql:postgresql:42.2.13' testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' From f90ad90db67e432cdabe3e9e347a7931ace0f29e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 12:00:42 +0100 Subject: [PATCH 0792/4969] Bump aws-java-sdk-logs from 1.11.792 to 1.11.797 in /modules/localstack (#2849) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 4a643d5b7f5..ed4b2073a41 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,9 +3,11 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.792' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.792' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.797' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.792' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' testCompile 'software.amazon.awssdk:s3:2.13.31' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' } From 7ba06573feb6561c6fc857cd5b53ff1449808da9 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 6 Jun 2020 21:00:02 +0200 Subject: [PATCH 0793/4969] Use testcontainers/* Docker Hub images (#2850) --- .../utility/TestcontainersConfiguration.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 44691cfb6fb..7b76039da52 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -58,6 +58,7 @@ static AtomicReference getInstanceField() { this.properties.putAll(environmentProperties); } + @Deprecated public String getAmbassadorContainerImage() { return (String) properties.getOrDefault("ambassador.container.image", "richnorth/ambassador:latest"); } @@ -67,7 +68,7 @@ public String getSocatContainerImage() { } public String getVncRecordedContainerImage() { - return (String) properties.getOrDefault("vncrecorder.container.image", "testcontainersofficial/vnc-recorder:1.1.0"); + return (String) properties.getOrDefault("vncrecorder.container.image", "testcontainers/vnc-recorder:1.1.0"); } public String getDockerComposeContainerImage() { @@ -83,11 +84,11 @@ public boolean isRyukPrivileged() { } public String getRyukImage() { - return (String) properties.getOrDefault("ryuk.container.image", "testcontainersofficial/ryuk:0.3.0"); + return (String) properties.getOrDefault("ryuk.container.image", "testcontainers/ryuk:0.3.0"); } public String getSSHdImage() { - return (String) properties.getOrDefault("sshd.container.image", "testcontainersofficial/sshd:1.0.0"); + return (String) properties.getOrDefault("sshd.container.image", "testcontainers/sshd:1.0.0"); } public Integer getRyukTimeout() { From f353266fe3ec18514f8933a1f9469162ef3c3ad0 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 10 Jun 2020 14:21:21 +0200 Subject: [PATCH 0794/4969] Hard deprecate `ProxiedUnixSocketClientProviderStrategy` (#2851) --- core/build.gradle | 4 --- .../DockerMachineClientProviderStrategy.java | 2 +- ...oxiedUnixSocketClientProviderStrategy.java | 32 ++++--------------- ....dockerclient.DockerClientProviderStrategy | 1 - 4 files changed, 8 insertions(+), 31 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index e728f1cd48b..d0d76392e48 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -155,10 +155,6 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - compile ('org.rnorth:tcp-unix-socket-proxy:1.0.2') { - exclude(group: "log4j", module: "log4j") - } - compile "net.java.dev.jna:jna-platform:5.5.0" shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.1') { diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java index f1503477500..fac092044c7 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java @@ -31,7 +31,7 @@ protected boolean isPersistable() { @Override protected int getPriority() { - return ProxiedUnixSocketClientProviderStrategy.PRIORITY - 10; + return EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 100; } @Override diff --git a/core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java index 84671e32efd..b1a21da724c 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java @@ -1,20 +1,16 @@ package org.testcontainers.dockerclient; -import lombok.extern.slf4j.Slf4j; -import org.rnorth.tcpunixsocketproxy.TcpToUnixSocketProxy; - -import java.io.File; - -@Slf4j +/** + * @deprecated no longer needed since `docker-java` supports all transport modes now + */ +@Deprecated public class ProxiedUnixSocketClientProviderStrategy extends UnixSocketClientProviderStrategy { public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 100; - private final File socketFile = new File(DOCKER_SOCK_PATH); - @Override protected boolean isApplicable() { - return socketFile.exists(); + return false; } @Override @@ -24,26 +20,12 @@ protected int getPriority() { @Override public void test() throws InvalidConfigurationException { - TcpToUnixSocketProxy proxy = new TcpToUnixSocketProxy(socketFile); - - try { - int proxyPort = proxy.start().getPort(); - - config = tryConfiguration("tcp://localhost:" + proxyPort); - - log.debug("Accessing unix domain socket via TCP proxy (" + DOCKER_SOCK_PATH + " via localhost:" + proxyPort + ")"); - } catch (Exception e) { - - proxy.stop(); - - throw new InvalidConfigurationException("ping failed", e); - } - + throw new InvalidConfigurationException("Deprecated"); } @Override public String getDescription() { - return "local Unix socket (via TCP proxy)"; + return "[Deprecated] local Unix socket (via TCP proxy)"; } } diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy index 25bbb30d725..cde7fc827e4 100644 --- a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy +++ b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy @@ -1,6 +1,5 @@ org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy org.testcontainers.dockerclient.UnixSocketClientProviderStrategy -org.testcontainers.dockerclient.ProxiedUnixSocketClientProviderStrategy org.testcontainers.dockerclient.DockerMachineClientProviderStrategy org.testcontainers.dockerclient.WindowsClientProviderStrategy org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy From 556659751849dfb06313f46a6560d5a194efd035 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 11 Jun 2020 14:40:24 +0200 Subject: [PATCH 0795/4969] Update Windows docs for WSL2 (#2816) --- docs/supported_docker_environment/windows.md | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/supported_docker_environment/windows.md b/docs/supported_docker_environment/windows.md index 6365456b095..6afab5972f2 100644 --- a/docs/supported_docker_environment/windows.md +++ b/docs/supported_docker_environment/windows.md @@ -4,18 +4,12 @@ * [Docker for Windows](https://docs.docker.com/docker-for-windows/) needs to be installed * Docker version 17.06 is confirmed to work on Windows 10 with Hyper-V. * Testcontainers supports communication with Docker on Docker for Windows using named pipes. + * WSL2 backend is supported starting with Windows 10 2004. (**Beta**) ## Limitations The following features are not available or do not work correctly so make sure you do not use them or use them with caution. The list may not be complete. -### Testing - -Testcontainers is not regularly tested on Windows, so please consider it to be at an beta level of readiness. - -If you wish to use Testcontainers on Windows, please confirm that it works correctly for you before investing significant -effort. - ### MySQL containers * MySQL server prevents custom configuration file (ini-script) from being loaded due to security measures ([link to feature description](../modules/databases/index.md#using-an-init-script-from-a-file)) @@ -23,7 +17,18 @@ effort. * WCOW is currently not supported, since Testcontainers uses auxiliary Linux containers for certain tasks and Docker for Windows does not support hybrid engine mode at the time of writing. -## Windows Subsystem for Linux +## WSL2 backend + +Using Docker for Windows with WSL2 backend should work out of the box. + +However, there is an [existing issue](https://github.com/microsoft/WSL/issues/4694) in WSL/WSL2 that effects certain older Docker images. +The currently proposed workaround is to enable vsyscall emulation in the WSL2 kernel: +``` +[wsl2] +kernelCommandLine = vsyscall=emulate +``` + +## Windows Subsystem for Linux (WSL) Testcontainers supports communicating with Docker for Windows within the Windows Subsystem for Linux *([**WSL**](https://docs.microsoft.com/en-us/windows/wsl/about))*. The following additional configurations steps are required: From 780b8e33811f046e64c7cdf6a25b49fb0fe79ce8 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 15 Jun 2020 21:28:37 +0200 Subject: [PATCH 0796/4969] Upgrade to docker-java 3.2.2, add Apache HttpClient5 option (#2803) --- .github/workflows/ci.yml | 18 ++++++++++ core/build.gradle | 7 +++- .../DelegatingDockerClient.java | 12 +++++++ .../testcontainers/DockerClientFactory.java | 7 +++- .../containers/ContainerState.java | 2 +- .../DockerClientProviderStrategy.java | 36 ++++++++++++++++--- .../utility/TestcontainersConfiguration.java | 5 --- examples/build.gradle | 4 +++ 8 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/DelegatingDockerClient.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ea2319193d..e2ca5d35daa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,3 +66,21 @@ jobs: wget -q https://get.cimate.io/release/linux/cimate chmod +x cimate ./cimate "**/TEST-*.xml" + httpclient5_test: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: Build with Gradle + run: | + echo "transport.type=httpclient5" > $HOME/.testcontainers.properties + cat $HOME/.testcontainers.properties + ./gradlew --no-daemon --scan testcontainers:test --tests '*EventStreamTest' + - name: aggregate test reports with ciMate + if: always() + env: + CIMATE_PROJECT_ID: 2348n4vl + CIMATE_CI_KEY: "CI / Apache HttpClient5" + run: | + wget -q https://get.cimate.io/release/linux/cimate + chmod +x cimate + ./cimate "**/TEST-*.xml" diff --git a/core/build.gradle b/core/build.gradle index d0d76392e48..c273cede20f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -157,13 +157,18 @@ dependencies { compile "net.java.dev.jna:jna-platform:5.5.0" - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.1') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.2') { exclude(group: 'net.java.dev.jna') exclude(group: 'com.google.code.findbug') exclude(group: 'org.slf4j') exclude(group: 'org.apache.commons', module: 'commons-compress') } + shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.2') { + exclude(group: 'net.java.dev.jna') + exclude(group: 'org.slf4j') + } + shaded "org.yaml:snakeyaml:1.25" shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' diff --git a/core/src/main/java/org/testcontainers/DelegatingDockerClient.java b/core/src/main/java/org/testcontainers/DelegatingDockerClient.java new file mode 100644 index 00000000000..ca25650bb02 --- /dev/null +++ b/core/src/main/java/org/testcontainers/DelegatingDockerClient.java @@ -0,0 +1,12 @@ +package org.testcontainers; + +import com.github.dockerjava.api.DockerClient; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; + +@RequiredArgsConstructor +class DelegatingDockerClient implements DockerClient { + + @Delegate + private final DockerClient dockerClient; +} diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 4e16a7edf9d..48900631456 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -148,7 +148,12 @@ public DockerClient client() { String hostIpAddress = strategy.getDockerHostIpAddress(); log.info("Docker host IP address is {}", hostIpAddress); - final DockerClient client = strategy.getClient(); + final DockerClient client = new DelegatingDockerClient(strategy.getClient()) { + @Override + public void close() { + throw new IllegalStateException("You should never close the global DockerClient!"); + } + }; Info dockerInfo = client.infoCmd().exec(); Version version = client.versionCmd().exec(); diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 1565b4e7e3e..1b1a99d3b89 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -310,8 +310,8 @@ default T copyFileFromContainer(String containerPath, ThrowingFunction" + ); strategy.checkOSType(); if (strategy.isPersistable()) { @@ -171,9 +180,28 @@ public DockerClient getClient() { } protected DockerClient getClientForConfig(DockerClientConfig config) { - return DockerClientImpl - .getInstance(new AuthDelegatingDockerClientConfig(config)) - .withDockerCmdExecFactory(new OkHttpDockerCmdExecFactory()); + config = new AuthDelegatingDockerClientConfig(config); + final DockerHttpClient dockerHttpClient; + + String transportType = TestcontainersConfiguration.getInstance().getTransportType(); + switch (transportType) { + case "okhttp": + dockerHttpClient = new OkDockerHttpClient.Builder() + .dockerHost(config.getDockerHost()) + .sslConfig(config.getSSLConfig()) + .build(); + break; + case "httpclient5": + dockerHttpClient = new ZerodepDockerHttpClient.Builder() + .dockerHost(config.getDockerHost()) + .sslConfig(config.getSSLConfig()) + .build(); + break; + default: + throw new IllegalArgumentException("Unknown transport type '" + transportType + "'"); + } + + return DockerClientImpl.getInstance(config, dockerHttpClient); } protected void ping(DockerClient client, int timeoutInSeconds) { diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 7b76039da52..aa829573447 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -120,11 +120,6 @@ public String getDockerClientStrategyClassName() { return (String) environmentProperties.get("docker.client.strategy"); } - /** - * - * @deprecated we no longer have different transport types - */ - @Deprecated public String getTransportType() { return properties.getProperty("transport.type", "okhttp"); } diff --git a/examples/build.gradle b/examples/build.gradle index 25b7c1fcf29..83e196dac00 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -3,4 +3,8 @@ apply from: "$rootDir/../gradle/ci-support.gradle" subprojects { apply plugin:"java" + + repositories { + jcenter() + } } From 816b8c309ba526b4f34a9970f9f5e9918ad47d06 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 16 Jun 2020 21:56:42 +0200 Subject: [PATCH 0797/4969] Fix log-related leaks (#2883) * Fix log-related leaks * Update core/src/main/java/org/testcontainers/utility/ResourceReaper.java Co-authored-by: Richard North * Update core/src/main/java/org/testcontainers/utility/ResourceReaper.java Co-authored-by: Richard North Co-authored-by: Richard North --- .../containers/ExecInContainerPattern.java | 9 +++++---- .../testcontainers/utility/ResourceReaper.java | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java index 359065d732b..9cd68d48ffb 100644 --- a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java +++ b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java @@ -73,11 +73,12 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn final ToStringConsumer stdoutConsumer = new ToStringConsumer(); final ToStringConsumer stderrConsumer = new ToStringConsumer(); - FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); - callback.addConsumer(OutputFrame.OutputType.STDOUT, stdoutConsumer); - callback.addConsumer(OutputFrame.OutputType.STDERR, stderrConsumer); + try (FrameConsumerResultCallback callback = new FrameConsumerResultCallback()) { + callback.addConsumer(OutputFrame.OutputType.STDOUT, stdoutConsumer); + callback.addConsumer(OutputFrame.OutputType.STDERR, stderrConsumer); - dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(callback).awaitCompletion(); + dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(callback).awaitCompletion(); + } Integer exitCode = dockerClient.inspectExecCmd(execCreateCmdResponse.getId()).exec().getExitCode(); final Container.ExecResult result = new Container.ExecResult( diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 4d44cbc3842..5d89ab886e7 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -93,7 +93,7 @@ public static String start(String hostIpAddress, DockerClient client) { StringBuilder ryukLog = new StringBuilder(); - client.logContainerCmd(ryukContainerId) + ResultCallback.Adapter logCallback = client.logContainerCmd(ryukContainerId) .withSince(0) .withFollowStream(true) .withStdOut(true) @@ -164,11 +164,17 @@ public void onNext(Frame frame) { ); kiraThread.setDaemon(true); kiraThread.start(); - - // We need to wait before we can start any containers to make sure that we delete them - if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { - log.error("Timeout out waiting for Ryuk. Ryuk's log:\n{}", ryukLog); - throw new IllegalStateException(String.format("Can not connect to Ryuk at %s:%s", hostIpAddress, ryukPort)); + try { + // We need to wait before we can start any containers to make sure that we delete them + if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { + log.error("Timed out waiting for Ryuk container to start. Ryuk's logs:\n{}", ryukLog); + throw new IllegalStateException(String.format("Could not connect to Ryuk at %s:%s", hostIpAddress, ryukPort)); + } + } finally { + try { + logCallback.close(); + } catch (IOException ignored) { + } } return ryukContainerId; From bfd2f2672360c7b7876ceec86b03dfa4c8ed20df Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 17 Jun 2020 15:08:55 +0200 Subject: [PATCH 0798/4969] Update to docker-java 3.2.3 (#2885) --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index c273cede20f..deabf16e90d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -157,14 +157,14 @@ dependencies { compile "net.java.dev.jna:jna-platform:5.5.0" - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.2') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.3') { exclude(group: 'net.java.dev.jna') exclude(group: 'com.google.code.findbug') exclude(group: 'org.slf4j') exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.2') { + shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.3') { exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } From c88fcc1c6359ba22c811a21c9f3b17bb3c614513 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:37:10 +0100 Subject: [PATCH 0799/4969] Bump aws-java-sdk-s3 from 1.11.797 to 1.11.802 in /modules/localstack (#2870) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.797 to 1.11.802. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.797...1.11.802) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ed4b2073a41..4c04a049591 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.797' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.802' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' From dac46206afca670c34f67cd2d1d478b4f32cd26b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:37:28 +0100 Subject: [PATCH 0800/4969] Bump postgresql from 42.2.13 to 42.2.14 in /modules/postgresql (#2867) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.13 to 42.2.14. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.13...REL42.2.14) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 2fe381f5fb4..7e6adea9cf1 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':jdbc-test') testCompile project(':test-support') - testCompile 'org.postgresql:postgresql:42.2.13' + testCompile 'org.postgresql:postgresql:42.2.14' testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' From a74afbfc3458cdaf5b9db194710168c2671485de Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:37:48 +0100 Subject: [PATCH 0801/4969] Bump tomcat-jdbc from 9.0.35 to 9.0.36 in /modules/jdbc (#2865) Bumps tomcat-jdbc from 9.0.35 to 9.0.36. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 1cfdeab73b2..3b6aea15c59 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.35' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.36' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' } From 5a793a6c24460c7837dde0ffce50abbcd46a6fc7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:37:59 +0100 Subject: [PATCH 0802/4969] Bump org.springframework.boot from 2.3.0.RELEASE to 2.3.1.RELEASE in /examples (#2871) Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.3.0.RELEASE to 2.3.1.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.0.RELEASE...v2.3.1.RELEASE) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 49e015f1af3..dc59ca877ab 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.0.RELEASE' + id 'org.springframework.boot' version '2.3.1.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index ad8d8252fb6..060a7f48357 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.0.RELEASE' + id 'org.springframework.boot' version '2.3.1.RELEASE' } apply plugin: 'io.spring.dependency-management' From 9e361ba447af11a158cbfdb7a3b687292ff6752c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:38:13 +0100 Subject: [PATCH 0803/4969] Bump s3 from 2.13.31 to 2.13.36 in /modules/localstack (#2872) Bumps s3 from 2.13.31 to 2.13.36. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 4c04a049591..8a2a372a0f1 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,7 +7,7 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' - testCompile 'software.amazon.awssdk:s3:2.13.31' + testCompile 'software.amazon.awssdk:s3:2.13.36' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' } From 66a2cb07068d70ab5874b5267565177956524f1e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:38:23 +0100 Subject: [PATCH 0804/4969] Bump postgresql from 42.2.13 to 42.2.14 in /modules/junit-jupiter (#2869) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.13 to 42.2.14. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.13...REL42.2.14) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 301c7eaaecc..ffc060d8b01 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'org.assertj:assertj-core:3.16.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' - testRuntime 'org.postgresql:postgresql:42.2.13' + testRuntime 'org.postgresql:postgresql:42.2.14' testRuntime 'mysql:mysql-connector-java:8.0.20' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' } From 4207844d1f9b2dbfb55c0df533ce1a799cc006d5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:38:36 +0100 Subject: [PATCH 0805/4969] Bump tomcat-jdbc from 9.0.35 to 9.0.36 in /modules/jdbc-test (#2866) Bumps tomcat-jdbc from 9.0.35 to 9.0.36. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 23564279332..e901869f04e 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -15,7 +15,7 @@ dependencies { } compile 'commons-dbutils:commons-dbutils:1.7' - compile 'org.apache.tomcat:tomcat-jdbc:9.0.35' + compile 'org.apache.tomcat:tomcat-jdbc:9.0.36' compile 'org.vibur:vibur-dbcp:25.0' compile 'mysql:mysql-connector-java:8.0.20' } From 4219f078222545bcab005d4f6f3a76dda5847c18 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:38:45 +0100 Subject: [PATCH 0806/4969] Bump postgresql from 42.2.13 to 42.2.14 in /modules/spock (#2873) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.13 to 42.2.14. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.13...REL42.2.14) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 7e1b05b7719..ee4ac56053f 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testRuntime 'org.postgresql:postgresql:42.2.13' + testRuntime 'org.postgresql:postgresql:42.2.14' testRuntime 'mysql:mysql-connector-java:8.0.20' } From c7ebdd7ae0f5fdae9b2bc10874c5d6f8c9cfff2b Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 18 Jun 2020 19:14:08 +0100 Subject: [PATCH 0807/4969] Use PyPI published version of mkdocs-codeinclude-plugin --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dd80510a4b4..227c646dd6b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ mkdocs==1.0.4 --e git+https://github.com/rnorth/mkdocs-codeinclude-plugin#egg=mkdocs_codeinclude_plugin +mkdocs-codeinclude-plugin==0.0.1 mkdocs-material==4.6.0 mkdocs-markdownextradata-plugin==0.1.1 markdown>=3.1,<3.2 From b9ee64c9acecb5bc6c0637f9cc669c08562ad1e5 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 18 Jun 2020 19:21:39 +0100 Subject: [PATCH 0808/4969] Use PyPI published version of mkdocs-codeinclude-plugin --- Pipfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipfile b/Pipfile index 145ddf858a2..2236de86daf 100644 --- a/Pipfile +++ b/Pipfile @@ -7,7 +7,7 @@ verify_ssl = true [packages] mkdocs = "*" -mkdocs-codeinclude-plugin = {editable = true,git = "https://github.com/rnorth/mkdocs-codeinclude-plugin"} +mkdocs-codeinclude-plugin = "*" mkdocs-material = "*" mkdocs-markdownextradata-plugin = "*" From 8767b8619356bd31e33a9893c361c070bd3ded10 Mon Sep 17 00:00:00 2001 From: Alex Yaroslavsky Date: Fri, 19 Jun 2020 12:33:33 +0300 Subject: [PATCH 0809/4969] Fix compilation error related to unicode in source code (#2464) Co-authored-by: Richard North --- core/src/main/java/org/testcontainers/DockerClientFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 48900631456..50c0f3d021c 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -239,7 +239,7 @@ private void checkDiskSpace(DockerClient dockerClient, String id) { private void check(String message, boolean isSuccessful) { if (isSuccessful) { - log.info("\u2714︎ {}", message); + log.info("\u2714\ufe0e {}", message); } else { log.error("\u274c {}", message); throw new IllegalStateException("Check failed: " + message); From d345b9163898f556ea63d9c0db25487a74e8cf5a Mon Sep 17 00:00:00 2001 From: sullis Date: Sat, 20 Jun 2020 13:03:23 -0700 Subject: [PATCH 0810/4969] upgrade to Dependabot 2 (#2898) https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/ https://help.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates --- .dependabot/config.yml | 160 ----------------------------------------- .github/dependabot.yml | 136 +++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 160 deletions(-) delete mode 100644 .dependabot/config.yml create mode 100644 .github/dependabot.yml diff --git a/.dependabot/config.yml b/.dependabot/config.yml deleted file mode 100644 index bf80d72ab92..00000000000 --- a/.dependabot/config.yml +++ /dev/null @@ -1,160 +0,0 @@ -# See https://github.com/dependabot/feedback/issues/70 for current (beta) configurability -version: 1 -update_configs: - - package_manager: "java:gradle" - directory: "/core" - update_schedule: "weekly" - -# Explicit entry for each module - - package_manager: "java:gradle" - directory: "/modules/cassandra" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/clickhouse" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/couchbase" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/database-commons" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/dynalite" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/elasticsearch" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/influxdb" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/jdbc" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/jdbc-test" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/junit-jupiter" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/kafka" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/localstack" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/mariadb" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/mockserver" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/mssqlserver" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/mysql" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/neo4j" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/nginx" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/oracle-xe" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/postgresql" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/pulsar" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/selenium" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/spock" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - - package_manager: "java:gradle" - directory: "/modules/vault" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } - -# Examples - - package_manager: "java:gradle" - directory: "/examples" - update_schedule: "weekly" - automerged_updates: - - match: { dependency_type: "development", update_type: "semver:minor" } - - match: { dependency_type: "production", update_type: "semver:minor" } diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..8abda8d8c5a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,136 @@ +version: 2 +updates: + - package-ecosystem: "gradle" + directory: "/core" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + +# Explicit entry for each module + - package-ecosystem: "gradle" + directory: "/modules/cassandra" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/clickhouse" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/couchbase" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/database-commons" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/dynalite" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/elasticsearch" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/influxdb" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/jdbc" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/jdbc-test" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/junit-jupiter" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/kafka" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/localstack" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/mariadb" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/mockserver" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/mssqlserver" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/mysql" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/neo4j" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/nginx" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/oracle-xe" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/postgresql" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/pulsar" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/selenium" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/spock" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/vault" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + +# Examples + - package-ecosystem: "gradle" + directory: "/examples" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 From 0bc4a4db37c1aad0dc97229d0b5e409904a52510 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 21:04:27 +0100 Subject: [PATCH 0811/4969] Bump elasticsearch-rest-client from 7.7.1 to 7.8.0 in /modules/elasticsearch (#2889) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.7.1 to 7.8.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.7.1...v7.8.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 04e038864ce..591760d7b0e 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.7.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.8.0" testCompile "org.elasticsearch.client:transport:6.7.1" } From d1f319491ed34c80b43d8bbba7575cc8fd570b31 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 21:05:13 +0100 Subject: [PATCH 0812/4969] Bump cucumber-junit from 5.7.0 to 6.1.1 in /examples (#2891) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 5.7.0 to 6.1.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v5.7.0...v6.1.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 011b2bddecd..dfd80dc16c2 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' testImplementation 'io.cucumber:cucumber-java:5.7.0' - testImplementation 'io.cucumber:cucumber-junit:5.7.0' + testImplementation 'io.cucumber:cucumber-junit:6.1.1' testImplementation 'org.testcontainers:selenium' } From d4c2230d1de7c765a12087aecdd1f3da197f05a9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 21:05:28 +0100 Subject: [PATCH 0813/4969] Bump pulsar-client from 2.5.2 to 2.6.0 in /modules/pulsar (#2893) Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.5.2 to 2.6.0. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.5.2...v2.6.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 4082197b8ea..371aa0c11d0 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.5.2' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.1' } From 0e6e14725418a99a38c87b05f3e13d87d428bda3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 21:05:47 +0100 Subject: [PATCH 0814/4969] Bump postgresql from 42.2.13 to 42.2.14 in /examples (#2892) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.13 to 42.2.14. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.13...REL42.2.14) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 79b66e15c57..52d2d58b6e7 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:3.14.8' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.13' + testImplementation 'org.postgresql:postgresql:42.2.14' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From 1955de455c36008048b3756b5a9623fd0382b13f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 21:06:02 +0100 Subject: [PATCH 0815/4969] Bump aws-java-sdk-s3 from 1.11.802 to 1.11.807 in /modules/localstack (#2894) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.802 to 1.11.807. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.802...1.11.807) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8a2a372a0f1..12f7dbe7e63 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.802' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.797' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.807' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' testCompile 'software.amazon.awssdk:s3:2.13.36' From 7278c496f4a6ad2cfdf79c187efae36fa35324f0 Mon Sep 17 00:00:00 2001 From: Simon Schneider <10846939+raynigon@users.noreply.github.com> Date: Sat, 20 Jun 2020 22:07:37 +0200 Subject: [PATCH 0816/4969] Use codeinclude for Elasticsearch Module (#2828) Co-authored-by: Simon Schneider --- docs/modules/elasticsearch.md | 39 +++-------- .../ElasticsearchContainerTest.java | 69 +++++++++++++++---- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index c7efa872df6..9959d0b7926 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -9,31 +9,11 @@ Note that it's based on the [official Docker image](https://www.elastic.co/guide You can start an elasticsearch container instance from any Java application by using: -```java -// Create the elasticsearch container. -ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:6.4.1"); + +[HttpClient](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:httpClientContainer +[TransportClient](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:transportClientContainer + -// Start the container. This step might take some time... -container.start(); - -// Do whatever you want with the rest client ... -final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); -credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "changeme")); -RestClient restClient = RestClient.builder(HttpHost.create(container.getHttpHostAddress())) - .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)) - .build(); -Response response = restClient.performRequest(new Request("GET", "/")); - -// ... or the transport client -TransportAddress transportAddress = new TransportAddress(container.getTcpHost()); -Settings settings = Settings.builder().put("cluster.name", "docker-cluster").build(); -TransportClient transportClient = new PreBuiltTransportClient(settings) - .addTransportAddress(transportAddress); -ClusterHealthResponse healths = transportClient.admin().cluster().prepareHealth().get(); - -// Stop the container. -container.stop(); -``` Note that if you are still using the [TransportClient](https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.3/transport-client.html) (not recommended as it is deprecated), the default cluster name is set to `docker-cluster` so you need to change `cluster.name` setting @@ -41,13 +21,12 @@ or set `client.transport.ignore_cluster_name` to `true`. ## Choose your Elasticsearch license -If you prefer to start a Docker image with the pure OSS version (which means with no security or -other advanced features), you can use this instead: +If you prefer to start a Docker image with the pure OSS version (which means with no security in older versions or +other new and advanced features), you can use this instead: -```java -// Create the elasticsearch container. -ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.1"); -``` + +[Elasticsearch OSS](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:oosContainer + ## Adding this module to your project dependencies diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 7aaf49d3af7..5da759872c9 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -1,5 +1,12 @@ package org.testcontainers.elasticsearch; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.testcontainers.elasticsearch.ElasticsearchContainer.ELASTICSEARCH_DEFAULT_VERSION; + +import java.io.IOException; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; @@ -7,6 +14,7 @@ import org.apache.http.client.CredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.util.EntityUtils; +import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; @@ -19,16 +27,13 @@ import org.junit.After; import org.junit.Test; -import java.io.IOException; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; -import static org.testcontainers.elasticsearch.ElasticsearchContainer.ELASTICSEARCH_DEFAULT_VERSION; - public class ElasticsearchContainerTest { + /** + * Elasticsearch version which should be used for the Tests + */ + private static final String ELASTICSEARCH_VERSION = Version.CURRENT.toString(); + /** * Elasticsearch default username, when secured with a license > basic */ @@ -51,10 +56,14 @@ public void stopRestClient() throws IOException { @Test public void elasticsearchDefaultTest() throws IOException { + // Create the elasticsearch container. try (ElasticsearchContainer container = new ElasticsearchContainer() .withEnv("foo", "bar") // dummy env for compiler checking correct generics usage ) { + // Start the container. This step might take some time... container.start(); + + // Do whatever you want with the rest client ... Response response = getClient(container).performRequest(new Request("GET", "/")); assertThat(response.getStatusLine().getStatusCode(), is(200)); assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_DEFAULT_VERSION)); @@ -69,19 +78,22 @@ public void elasticsearchDefaultTest() throws IOException { @Test public void elasticsearchVersion() throws IOException { - try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:5.6.12")) { + try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); assertThat(response.getStatusLine().getStatusCode(), is(200)); String responseAsString = EntityUtils.toString(response.getEntity()); - assertThat(responseAsString, containsString("5.6.12")); + assertThat(responseAsString, containsString(ELASTICSEARCH_VERSION)); } } @Test public void elasticsearchOssImage() throws IOException { - try (ElasticsearchContainer container = - new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:" + ELASTICSEARCH_DEFAULT_VERSION)) { + try ( + // oosContainer { + ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:" + ELASTICSEARCH_VERSION) + // } + ) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); assertThat(response.getStatusLine().getStatusCode(), is(200)); @@ -92,11 +104,41 @@ public void elasticsearchOssImage() throws IOException { } } + @Test + public void restClientClusterHealth() throws IOException { + // httpClientContainer { + // Create the elasticsearch container. + try (ElasticsearchContainer container = new ElasticsearchContainer()) { + // Start the container. This step might take some time... + container.start(); + + // Do whatever you want with the rest client ... + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)); + + client = RestClient.builder(HttpHost.create(container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)) + .build(); + + Response response = client.performRequest(new Request("GET", "/_cluster/health")); + // }} + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + // httpClientContainer {{ + } + // } + } + @Test public void transportClientClusterHealth() { + // transportClientContainer { + // Create the elasticsearch container. try (ElasticsearchContainer container = new ElasticsearchContainer()) { + // Start the container. This step might take some time... container.start(); + // Do whatever you want with the transport client TransportAddress transportAddress = new TransportAddress(container.getTcpHost()); String expectedClusterName = "docker-cluster"; Settings settings = Settings.builder().put("cluster.name", expectedClusterName).build(); @@ -104,9 +146,12 @@ public void transportClientClusterHealth() { .addTransportAddress(transportAddress)) { ClusterHealthResponse healths = transportClient.admin().cluster().prepareHealth().get(); String clusterName = healths.getClusterName(); + // }}} assertThat(clusterName, is(expectedClusterName)); + // transportClientContainer {{{ } } + // } } private RestClient getClient(ElasticsearchContainer container) { From 0053dfe559a90c4d8abb2a296d046d513abf0a08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 21:12:21 +0100 Subject: [PATCH 0817/4969] Bump aws-java-sdk-dynamodb from 1.11.479 to 1.11.807 in /modules/dynalite (#2905) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.479 to 1.11.807. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.479...1.11.807) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 32d522aa964..7101f40552f 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.479' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.479' } From 924d36f9773fefc3321f6d3e23d97fea8852ff8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 21:13:44 +0100 Subject: [PATCH 0818/4969] Bump me.champeau.gradle.japicmp from 0.2.8 to 0.2.9 in /core (#2900) Bumps me.champeau.gradle.japicmp from 0.2.8 to 0.2.9. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index deabf16e90d..69788d1f0de 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -10,7 +10,7 @@ buildscript { } plugins { - id 'me.champeau.gradle.japicmp' version '0.2.8' + id 'me.champeau.gradle.japicmp' version '0.2.9' } apply plugin: 'com.github.johnrengelman.shadow' From e61bff8675847eec9db1d626ece77b588c70ad80 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2020 09:50:05 +0100 Subject: [PATCH 0819/4969] Bump aws-java-sdk-sqs from 1.11.797 to 1.11.807 in /modules/localstack (#2896) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 12f7dbe7e63..d90e8e1611a 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,9 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.807' + testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.13.36' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.797' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.797' } From f358ebfcfa36c84ef50707767d4beaa644e7a070 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2020 09:51:51 +0100 Subject: [PATCH 0820/4969] Bump selenium-remote-driver from 3.14.0 to 3.141.59 in /examples (#2913) Bumps [selenium-remote-driver](https://github.com/SeleniumHQ/selenium) from 3.14.0 to 3.141.59. - [Release notes](https://github.com/SeleniumHQ/selenium/releases) - [Commits](https://github.com/SeleniumHQ/selenium/compare/selenium-3.14.0...selenium-3.141.59) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index dfd80dc16c2..2131c5766e8 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.14.0' + implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' testImplementation 'io.cucumber:cucumber-java:5.7.0' From 0cfa031297e38fd818af8add256dc08f7bd0928d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2020 09:52:05 +0100 Subject: [PATCH 0821/4969] Bump selenium-chrome-driver from 3.14.0 to 3.141.59 in /examples (#2914) Bumps [selenium-chrome-driver](https://github.com/SeleniumHQ/selenium) from 3.14.0 to 3.141.59. - [Release notes](https://github.com/SeleniumHQ/selenium/releases) - [Commits](https://github.com/SeleniumHQ/selenium/compare/selenium-3.14.0...selenium-3.141.59) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 2131c5766e8..e4c44c0e063 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' - implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.14.0' + implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:5.7.0' testImplementation 'io.cucumber:cucumber-junit:6.1.1' testImplementation 'org.testcontainers:selenium' From 043d9ea2e2add78a767c241cbb04f6494071dee5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2020 09:52:25 +0100 Subject: [PATCH 0822/4969] Bump okhttp from 3.14.8 to 4.7.2 in /examples (#2915) Bumps [okhttp](https://github.com/square/okhttp) from 3.14.8 to 4.7.2. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-3.14.8...parent-4.7.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 52d2d58b6e7..f56b8bc46d8 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:3.14.8' + implementation 'com.squareup.okhttp3:okhttp:4.7.2' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.14' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 98f5e9bb88de667b5b7ad5d548d0f4901776821e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2020 19:43:37 +0100 Subject: [PATCH 0823/4969] Bump s3 from 2.13.36 to 2.13.41 in /modules/localstack (#2907) Bumps s3 from 2.13.36 to 2.13.41. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d90e8e1611a..a04c04a4751 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.13.36' + testCompile 'software.amazon.awssdk:s3:2.13.41' } From 859f29d205f88404d7ec290cdaf6e4fb7b8b6ca2 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 23 Jun 2020 15:11:09 +0100 Subject: [PATCH 0824/4969] Upgrade docker-java to 3.2.4 (#2924) Primarily to incorporate https://github.com/docker-java/docker-java/pull/1420 and improve build stability issues seen recently. --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 69788d1f0de..0e0a41f4914 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -157,14 +157,14 @@ dependencies { compile "net.java.dev.jna:jna-platform:5.5.0" - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.3') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.4') { exclude(group: 'net.java.dev.jna') exclude(group: 'com.google.code.findbug') exclude(group: 'org.slf4j') exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.3') { + shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.4') { exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } From fc03c217b9ebfbc7e6db82bcdd3b54a159580cd9 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 23 Jun 2020 17:59:12 +0100 Subject: [PATCH 0825/4969] Pin registry image used for testing (#2926) As a workaround for https://github.com/docker/distribution-library-image/issues/107 --- .../org/testcontainers/utility/AuthenticatedImagePullTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 31f098bab16..3986255f248 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -45,7 +45,7 @@ public class AuthenticatedImagePullTest { @ClassRule public static GenericContainer authenticatedRegistry = new GenericContainer<>(new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { - builder.from("registry:2") + builder.from("registry:2.7.0") .run("htpasswd -Bbn testuser notasecret > /htpasswd") .env("REGISTRY_AUTH", "htpasswd") .env("REGISTRY_AUTH_HTPASSWD_PATH", "/htpasswd") From 3f64d0c9eac4b500730074fb40a20b9a689c6b65 Mon Sep 17 00:00:00 2001 From: Simon Schneider <10846939+raynigon@users.noreply.github.com> Date: Tue, 23 Jun 2020 19:53:54 +0200 Subject: [PATCH 0826/4969] Convert Docs for the Spock Testframework (#2928) Convert inline example code to use codeinclude macro for the Spock Testframework documentation See #1158 for more details. --- docs/test_framework_integration/spock.md | 34 ++----------------- .../spock/PostgresContainerIT.groovy | 2 ++ 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/docs/test_framework_integration/spock.md b/docs/test_framework_integration/spock.md index bbe06a43e80..8528faf4490 100644 --- a/docs/test_framework_integration/spock.md +++ b/docs/test_framework_integration/spock.md @@ -9,37 +9,9 @@ Specifying the `@Testcontainers` annotation will instruct Spock to start and stop all testcontainers accordingly. This annotation can be mixed with Spock's `@Shared` annotation to indicate, that containers shouldn't be restarted between tests. -```groovy -@Testcontainers -class DatabaseTest extends Specification { - - @Shared - PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer() - .withDatabaseName("foo") - .withUsername("foo") - .withPassword("secret") - - def "database is accessible"() { - - given: "a jdbc connection" - HikariConfig hikariConfig = new HikariConfig() - hikariConfig.setJdbcUrl(postgreSQLContainer.jdbcUrl) - hikariConfig.setUsername("foo") - hikariConfig.setPassword("secret") - HikariDataSource ds = new HikariDataSource(hikariConfig) - - when: "querying the database" - Statement statement = ds.getConnection().createStatement() - statement.execute("SELECT 1") - ResultSet resultSet = statement.getResultSet() - resultSet.next() - - then: "result is returned" - int resultSetInt = resultSet.getInt(1) - resultSetInt == 1 - } -} -``` + +[PostgresContainerIT](../../modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy) inside_block:PostgresContainerIT + ## Adding Testcontainers Spock support to your project dependencies diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy index 6e090e77c33..4ac095bed6f 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy @@ -9,6 +9,7 @@ import spock.lang.Specification import java.sql.ResultSet import java.sql.Statement +// PostgresContainerIT { @Testcontainers class PostgresContainerIT extends Specification { @@ -42,3 +43,4 @@ class PostgresContainerIT extends Specification { } } +// } From 53e02a5f5ff1d8db7d9ab04890e62ae25e639066 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 24 Jun 2020 08:32:00 +0100 Subject: [PATCH 0827/4969] Run correct subset of docker compose containers when `withServices`/`withScaledService` used (#2922) Co-authored-by: Afshin --- .../containers/DockerComposeContainer.java | 115 ++++++++++-------- ...ockerComposeContainerWithServicesTest.java | 107 ++++++++++++++++ .../compose-scaling-multiple-containers.yml | 7 ++ .../compose-with-inline-scale-test.yml | 5 + 4 files changed, 184 insertions(+), 50 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java create mode 100644 core/src/test/resources/compose-scaling-multiple-containers.yml create mode 100644 core/src/test/resources/compose-with-inline-scale-test.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 651bd9c8526..c3fe9ab17f9 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -2,9 +2,9 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Container; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Splitter; -import com.google.common.base.Strings; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.Uninterruptibles; @@ -56,6 +56,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import static org.testcontainers.containers.BindMode.READ_ONLY; @@ -196,23 +197,36 @@ public SELF withServices(@NonNull String... services) { } private void createServices() { - // Apply scaling - final String servicesWithScalingSettings = Stream.concat(services.stream(), scalingPreferences.keySet().stream()) - .map(service -> "--scale " + service + "=" + scalingPreferences.getOrDefault(service, 1)) + // services that have been explicitly requested to be started. If empty, all services should be started. + final String serviceNameArgs = Stream.concat( + services.stream(), // services that have been specified with `withServices` + scalingPreferences.keySet().stream() // services that are implicitly needed via `withScaledService` + ) + .distinct() .collect(joining(" ")); - String flags = "-d"; + // Apply scaling for the services specified using `withScaledService` + final String scalingOptions = scalingPreferences.entrySet().stream() + .map(entry -> "--scale " + entry.getKey() + "=" + entry.getValue()) + .distinct() + .collect(joining(" ")); + + String command = "up -d"; if (build) { - flags += " --build"; + command += " --build"; } - // Run the docker-compose container, which starts up the services - if(Strings.isNullOrEmpty(servicesWithScalingSettings)) { - runWithCompose("up " + flags); - } else { - runWithCompose("up " + flags + " " + servicesWithScalingSettings); + if (!isNullOrEmpty(scalingOptions)) { + command += " " + scalingOptions; + } + + if (!isNullOrEmpty(serviceNameArgs)) { + command += " " + serviceNameArgs; } + + // Run the docker-compose container, which starts up the services + runWithCompose(command); } private void waitUntilServiceStarted() { @@ -250,7 +264,7 @@ private void createServiceInstance(Container container) { private void waitUntilServiceStarted(String serviceName, ComposeServiceWaitStrategyTarget serviceInstance) { final WaitAllStrategy waitAllStrategy = waitStrategyMap.get(serviceName); - if(waitAllStrategy != null) { + if (waitAllStrategy != null) { waitAllStrategy.waitUntilReady(serviceInstance); } } @@ -273,24 +287,25 @@ private void runWithCompose(String cmd) { } dockerCompose - .withCommand(cmd) - .withEnv(env) - .invoke(); + .withCommand(cmd) + .withEnv(env) + .invoke(); } private void registerContainersForShutdown() { ResourceReaper.instance().registerFilterForCleanup(Arrays.asList( - new SimpleEntry<>("label", "com.docker.compose.project=" + project) + new SimpleEntry<>("label", "com.docker.compose.project=" + project) )); } - private List listChildContainers() { + @VisibleForTesting + List listChildContainers() { return dockerClient.listContainersCmd() - .withShowAll(true) - .exec().stream() - .filter(container -> Arrays.stream(container.getNames()).anyMatch(name -> - name.startsWith("/" + project))) - .collect(toList()); + .withShowAll(true) + .exec().stream() + .filter(container -> Arrays.stream(container.getNames()).anyMatch(name -> + name.startsWith("/" + project))) + .collect(toList()); } private void startAmbassadorContainers() { @@ -378,12 +393,12 @@ private void addWaitStrategy(String serviceInstanceName, @NonNull WaitStrategy w } /** - Specify the {@link WaitStrategy} to use to determine if the container is ready. + * Specify the {@link WaitStrategy} to use to determine if the container is ready. * - * @see org.testcontainers.containers.wait.strategy.Wait#defaultWaitStrategy() - * @param serviceName the name of the service to wait for + * @param serviceName the name of the service to wait for * @param waitStrategy the WaitStrategy to use * @return this + * @see org.testcontainers.containers.wait.strategy.Wait#defaultWaitStrategy() */ public SELF waitingFor(String serviceName, @NonNull WaitStrategy waitStrategy) { String serviceInstanceName = getServiceInstanceName(serviceName); @@ -420,8 +435,8 @@ public Integer getServicePort(String serviceName, Integer servicePort) { if (portMap == null) { throw new IllegalArgumentException("Could not get a port for '" + serviceName + "'. " + - "Testcontainers does not have an exposed port configured for '" + serviceName + "'. "+ - "To fix, please ensure that the service '" + serviceName + "' has ports exposed using .withExposedService(...)"); + "Testcontainers does not have an exposed port configured for '" + serviceName + "'. " + + "To fix, please ensure that the service '" + serviceName + "' has ports exposed using .withExposedService(...)"); } else { return ambassadorContainer.getMappedPort(portMap.get(servicePort)); } @@ -479,7 +494,7 @@ public SELF withTailChildContainers(boolean tailChildContainers) { * More than one consumer may be registered. * * @param serviceName the name of the service as set in the docker-compose.yml file - * @param consumer consumer that output frames should be sent to + * @param consumer consumer that output frames should be sent to * @return this instance, for chaining */ public SELF withLogConsumer(String serviceName, Consumer consumer) { @@ -579,10 +594,10 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { final String containerPwd = MountableFile.forHostPath(pwd).getFilesystemPath(); final List absoluteDockerComposeFiles = composeFiles.stream() - .map(File::getAbsolutePath) - .map(MountableFile::forHostPath) - .map(MountableFile::getFilesystemPath) - .collect(toList()); + .map(File::getAbsolutePath) + .map(MountableFile::forHostPath) + .map(MountableFile::getFilesystemPath) + .collect(toList()); final String composeFileEnvVariableValue = Joiner.on(UNIX_PATH_SEPERATOR).join(absoluteDockerComposeFiles); // we always need the UNIX path separator logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); addEnv(ENV_COMPOSE_FILE, composeFileEnvVariableValue); @@ -600,8 +615,8 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { private String getDockerSocketHostPath() { return SystemUtils.IS_OS_WINDOWS - ? "/" + DOCKER_SOCKET_PATH - : DOCKER_SOCKET_PATH; + ? "/" + DOCKER_SOCKET_PATH + : DOCKER_SOCKET_PATH; } @Override @@ -621,16 +636,16 @@ public void invoke() { AuditLogger.doComposeLog(this.getCommandParts(), this.getEnv()); final Integer exitCode = this.dockerClient.inspectContainerCmd(getContainerId()) - .exec() - .getState() - .getExitCode(); + .exec() + .getState() + .getExitCode(); if (exitCode == null || exitCode != 0) { throw new ContainerLaunchException( - "Containerised Docker Compose exited abnormally with code " + - exitCode + - " whilst running command: " + - StringUtils.join(this.getCommandParts(), ' ')); + "Containerised Docker Compose exited abnormally with code " + + exitCode + + " whilst running command: " + + StringUtils.join(this.getCommandParts(), ' ')); } } } @@ -691,23 +706,23 @@ public void invoke() { logger().info("Local Docker Compose is running command: {}", cmd); final List command = Splitter.onPattern(" ") - .omitEmptyStrings() - .splitToList(COMPOSE_EXECUTABLE + " " + cmd); + .omitEmptyStrings() + .splitToList(COMPOSE_EXECUTABLE + " " + cmd); try { new ProcessExecutor().command(command) - .redirectOutput(Slf4jStream.of(logger()).asInfo()) - .redirectError(Slf4jStream.of(logger()).asInfo()) // docker-compose will log pull information to stderr - .environment(environment) - .directory(pwd) - .exitValueNormal() - .executeNoTimeout(); + .redirectOutput(Slf4jStream.of(logger()).asInfo()) + .redirectError(Slf4jStream.of(logger()).asInfo()) // docker-compose will log pull information to stderr + .environment(environment) + .directory(pwd) + .exitValueNormal() + .executeNoTimeout(); logger().info("Docker Compose has finished running"); } catch (InvalidExitValueException e) { throw new ContainerLaunchException("Local Docker Compose exited abnormally with code " + - e.getExitValue() + " whilst running command: " + cmd); + e.getExitValue() + " whilst running command: " + cmd); } catch (Exception e) { throw new ContainerLaunchException("Error running local Docker Compose command: " + cmd, e); diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java new file mode 100644 index 00000000000..8927972e642 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java @@ -0,0 +1,107 @@ +package org.testcontainers.containers; + +import org.junit.Test; + +import java.io.File; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + + +public class DockerComposeContainerWithServicesTest { + + public static final File SIMPLE_COMPOSE_FILE = new File("src/test/resources/compose-scaling-multiple-containers.yml"); + public static final File COMPOSE_FILE_WITH_INLINE_SCALE = new File("src/test/resources/compose-with-inline-scale-test.yml"); + + @Test + public void testDesiredSubsetOfServicesAreStarted() { + try ( + DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) + .withServices("redis") + ) { + compose.start(); + + verifyStartedContainers(compose, "redis_1"); + } + } + + @Test + public void testDesiredSubsetOfScaledServicesAreStarted() { + try ( + DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) + .withScaledService("redis", 2) + ) { + compose.start(); + + verifyStartedContainers(compose, "redis_1", "redis_2"); + } + } + + @Test + public void testDesiredSubsetOfSpecifiedAndScaledServicesAreStarted() { + try ( + DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) + .withServices("redis") + .withScaledService("redis", 2) + ) { + compose.start(); + + verifyStartedContainers(compose, "redis_1", "redis_2"); + } + } + + @Test + public void testDesiredSubsetOfSpecifiedOrScaledServicesAreStarted() { + try ( + DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) + .withServices("other") + .withScaledService("redis", 2) + ) { + compose.start(); + + verifyStartedContainers(compose, "redis_1", "redis_2", "other_1"); + } + } + + @Test + public void testAllServicesAreStartedIfNotSpecified() { + try ( + DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) + ) { + compose.start(); + + verifyStartedContainers(compose, "redis_1", "other_1"); + } + } + + @Test + public void testScaleInComposeFileIsRespected() { + try ( + DockerComposeContainer compose = new DockerComposeContainer<>(COMPOSE_FILE_WITH_INLINE_SCALE) + ) { + compose.start(); + + // the compose file includes `scale: 3` for the redis container + verifyStartedContainers(compose, "redis_1", "redis_2", "redis_3"); + } + } + + private void verifyStartedContainers(final DockerComposeContainer compose, final String... names) { + final List containerNames = compose.listChildContainers().stream() + .flatMap(container -> Stream.of(container.getNames())) + .collect(Collectors.toList()); + + assertEquals("number of running services of docker-compose is the same as length of listOfServices", + names.length, containerNames.size()); + + for (final String expectedName : names) { + final long matches = containerNames.stream() + .filter(foundName -> foundName.endsWith(expectedName)) + .count(); + + assertEquals("container with name starting '" + expectedName + "' should be running", 1L, matches); + } + } +} diff --git a/core/src/test/resources/compose-scaling-multiple-containers.yml b/core/src/test/resources/compose-scaling-multiple-containers.yml new file mode 100644 index 00000000000..da5ac6f3a07 --- /dev/null +++ b/core/src/test/resources/compose-scaling-multiple-containers.yml @@ -0,0 +1,7 @@ +version: '2.4' +services: + redis: + image: redis + other: + image: alpine:3.5 + command: sleep 10000 diff --git a/core/src/test/resources/compose-with-inline-scale-test.yml b/core/src/test/resources/compose-with-inline-scale-test.yml new file mode 100644 index 00000000000..f2e7e8c1a79 --- /dev/null +++ b/core/src/test/resources/compose-with-inline-scale-test.yml @@ -0,0 +1,5 @@ +version: '2.4' +services: + redis: + image: redis + scale: 3 # legacy mechanism to specify scale From f07f31ec49fdfe02d0fc1a6c2674b62b08510736 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 25 Jun 2020 12:11:08 +0200 Subject: [PATCH 0828/4969] Continue on ciMate's error (#2933) --- .github/workflows/ci-docker-wormhole.yml | 1 + .github/workflows/ci-examples.yml | 1 + .github/workflows/ci.yml | 2 ++ 3 files changed, 4 insertions(+) diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index 3c6da54dc1f..f9e106d56b7 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -20,6 +20,7 @@ jobs: ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' - name: aggregate test reports with ciMate if: always() + continue-on-error: true env: CIMATE_PROJECT_ID: 2348n4vl run: | diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 8dab14e831c..d81a4ffb509 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -61,6 +61,7 @@ jobs: ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} - name: Aggregate Examples test reports with ciMate if: always() + continue-on-error: true env: CIMATE_PROJECT_ID: 2348n4vl CIMATE_CI_KEY: "Examples / ${{ runner.os }} / ${{matrix.gradle_args}}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2ca5d35daa..b965eb77dc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,6 +59,7 @@ jobs: ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} - name: Aggregate test reports with ciMate if: always() + continue-on-error: true env: CIMATE_PROJECT_ID: 2348n4vl CIMATE_CI_KEY: "CI / ${{ runner.os }} / ${{matrix.gradle_args}}" @@ -77,6 +78,7 @@ jobs: ./gradlew --no-daemon --scan testcontainers:test --tests '*EventStreamTest' - name: aggregate test reports with ciMate if: always() + continue-on-error: true env: CIMATE_PROJECT_ID: 2348n4vl CIMATE_CI_KEY: "CI / Apache HttpClient5" From d09491bdc2fa1dd50c12c66650a2928642d0a037 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 25 Jun 2020 12:17:51 +0200 Subject: [PATCH 0829/4969] Update to `docker-java` 3.2.5 (#2938) --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 0e0a41f4914..e1fb724597e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -157,14 +157,14 @@ dependencies { compile "net.java.dev.jna:jna-platform:5.5.0" - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.4') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.5') { exclude(group: 'net.java.dev.jna') exclude(group: 'com.google.code.findbug') exclude(group: 'org.slf4j') exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.4') { + shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.5') { exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } From 60537db11726a278d0259dd4b08771910278814d Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 25 Jun 2020 11:58:20 +0100 Subject: [PATCH 0830/4969] Pin version of RabbitMQ image to `3.7.25-management-alpine` (#2941) --- .../java/org/testcontainers/containers/RabbitMQContainer.java | 2 +- .../org/testcontainers/containers/RabbitMQContainerTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index 49423201d14..d8d46f51b1c 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -28,7 +28,7 @@ public class RabbitMQContainer extends GenericContainer { * The image defaults to the official RabbitmQ image: RabbitMQ. */ private static final String DEFAULT_IMAGE_NAME = "rabbitmq"; - private static final String DEFAULT_TAG = "3.7-management-alpine"; + private static final String DEFAULT_TAG = "3.7.25-management-alpine"; private static final int DEFAULT_AMQP_PORT = 5672; private static final int DEFAULT_AMQPS_PORT = 5671; diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index 27ac38f55ce..d8e9c7658c0 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -31,7 +31,7 @@ */ public class RabbitMQContainerTest { - public static final String DEFAULT_IMAGE = "rabbitmq:3.7-management-alpine"; + public static final String DEFAULT_IMAGE = "rabbitmq:3.7.25-management-alpine"; public static final int DEFAULT_AMQPS_PORT = 5671; public static final int DEFAULT_AMQP_PORT = 5672; public static final int DEFAULT_HTTPS_PORT = 15671; From a4d67a68d37b1fbd804daa513c9b93fb4d3cb05c Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 25 Jun 2020 12:58:49 +0200 Subject: [PATCH 0831/4969] Delete pom.xml (#2937) --- examples/singleton-container/pom.xml | 43 ---------------------------- 1 file changed, 43 deletions(-) delete mode 100644 examples/singleton-container/pom.xml diff --git a/examples/singleton-container/pom.xml b/examples/singleton-container/pom.xml deleted file mode 100644 index 710c32d6b80..00000000000 --- a/examples/singleton-container/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - testcontainers-java-examples - org.testcontainers.examples - NOVERSION - - 4.0.0 - - singleton-container - - - - redis.clients - jedis - 3.0.1 - - - com.google.code.gson - gson - 2.8.5 - - - com.google.guava - guava - 23.0 - - - org.slf4j - slf4j-api - 1.7.25 - provided - - - ch.qos.logback - logback-classic - 1.2.3 - test - - - From 22c64030140f9c67023be498faa795709c00ebcd Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 25 Jun 2020 22:38:30 +0200 Subject: [PATCH 0832/4969] Cache Ryuk's failure to prevent the double start (#2935) see #2395 --- .../org/testcontainers/DockerClientFactory.java | 17 +++++++++++------ .../testcontainers/DockerClientFactoryTest.java | 6 +++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 50c0f3d021c..95e0c9838ba 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -66,7 +66,7 @@ public class DockerClientFactory { DockerClient dockerClient; @VisibleForTesting - RuntimeException cachedChecksFailure; + RuntimeException cachedClientFailure; private String activeApiVersion; private String activeExecutionDriver; @@ -139,9 +139,9 @@ public DockerClient client() { } // fail-fast if checks have failed previously - if (cachedChecksFailure != null) { - log.debug("There is a cached checks failure - throwing", cachedChecksFailure); - throw cachedChecksFailure; + if (cachedClientFailure != null) { + log.debug("There is a cached checks failure - throwing", cachedClientFailure); + throw cachedClientFailure; } final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); @@ -170,7 +170,12 @@ public void close() { boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); if (useRyuk) { log.debug("Ryuk is enabled"); - ryukContainerId = ResourceReaper.start(hostIpAddress, client); + try { + ryukContainerId = ResourceReaper.start(hostIpAddress, client); + } catch (RuntimeException e) { + cachedClientFailure = e; + throw e; + } log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit"); } else { log.debug("Ryuk is disabled"); @@ -201,7 +206,7 @@ public void close() { ); } } catch (RuntimeException e) { - cachedChecksFailure = e; + cachedClientFailure = e; throw e; } } else { diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index 60fd69e9fd3..04edd407959 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -71,7 +71,7 @@ public void failedChecksFailFast() { DockerClientFactory instance = new DockerClientFactory(); DockerClient dockerClient = instance.dockerClient; - assertThat(instance.cachedChecksFailure).isNull(); + assertThat(instance.cachedClientFailure).isNull(); try { // Remove cached client to force the initialization logic instance.dockerClient = null; @@ -80,12 +80,12 @@ public void failedChecksFailFast() { assertThatThrownBy(instance::client).isInstanceOf(DockerException.class); RuntimeException failure = new IllegalStateException("Boom!"); - instance.cachedChecksFailure = failure; + instance.cachedClientFailure = failure; // Fail fast assertThatThrownBy(instance::client).isEqualTo(failure); } finally { instance.dockerClient = dockerClient; - instance.cachedChecksFailure = null; + instance.cachedClientFailure = null; } } } From f4400a09ef3fef2d98e1fa0085508a8989ab8662 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 25 Jun 2020 22:39:00 +0200 Subject: [PATCH 0833/4969] Do not resolve `LazyFuture` from `RemoteDockerImage#toString` (#2930) --- .../testcontainers/utility/LazyFuture.java | 30 +++++++++++-------- .../images/RemoteDockerImageTest.java | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/LazyFuture.java b/core/src/main/java/org/testcontainers/utility/LazyFuture.java index b0aa4346cbb..758082f5185 100644 --- a/core/src/main/java/org/testcontainers/utility/LazyFuture.java +++ b/core/src/main/java/org/testcontainers/utility/LazyFuture.java @@ -2,10 +2,10 @@ import lombok.AccessLevel; import lombok.Getter; -import lombok.experimental.Delegate; import org.rnorth.ducttape.timeouts.Timeouts; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; /** * Future implementation with lazy result evaluation in the same Thread as caller. @@ -14,31 +14,37 @@ */ public abstract class LazyFuture implements Future { - @Delegate(excludes = Excludes.class) - private final Future delegate = CompletableFuture.completedFuture(null); - @Getter(value = AccessLevel.MODULE, lazy = true) private final T resolvedValue = resolve(); abstract protected T resolve(); @Override - public T get() throws InterruptedException, ExecutionException { + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return ((AtomicReference) resolvedValue).get() != null; + } + + @Override + public T get() { return getResolvedValue(); } @Override - public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public T get(long timeout, TimeUnit unit) throws TimeoutException { try { return Timeouts.getWithTimeout((int) timeout, unit, this::get); } catch (org.rnorth.ducttape.TimeoutException e) { throw new TimeoutException(e.getMessage()); } } - - private interface Excludes { - T get(); - - T get(long timeout, TimeUnit unit); - } } diff --git a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java index c62f15653b3..6b6a82559bf 100644 --- a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java +++ b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java @@ -6,8 +6,11 @@ import org.junit.Test; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.LazyFuture; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; public class RemoteDockerImageTest { @@ -44,4 +47,31 @@ public void toStringDoesntResolveImageNameFuture() { imageNameFuture.complete(imageName); assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); } + + @Test(timeout=5000L) + public void toStringDoesntResolveLazyFuture() throws Exception { + String imageName = Base58.randomString(8).toLowerCase(); + AtomicBoolean resolved = new AtomicBoolean(false); + Future imageNameFuture = new LazyFuture() { + @Override + protected String resolve() { + resolved.set(true); + return imageName; + } + }; + + // verify that we've set up the test properly + assertFalse(imageNameFuture.isDone()); + + RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture); + assertThat(remoteDockerImage.toString(), containsString("imageName=")); + + // Make sure the act of calling toString doesn't resolve the imageNameFuture + assertFalse(imageNameFuture.isDone()); + assertFalse(resolved.get()); + + // Trigger resolve + imageNameFuture.get(); + assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); + } } From 6a005390d670632d63cef2c6bf8939cf76725341 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 26 Jun 2020 10:17:51 +0200 Subject: [PATCH 0834/4969] Remove implicit network in `KafkaContainer` (#2932) --- .../containers/KafkaContainer.java | 23 ------------------- .../containers/KafkaContainerTest.java | 22 ------------------ 2 files changed, 45 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index bb92f85b03c..9746849be29 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -29,8 +29,6 @@ public class KafkaContainer extends GenericContainer { private int port = PORT_NOT_ASSIGNED; - private boolean useImplicitNetwork = true; - public KafkaContainer() { this("5.2.1"); } @@ -38,7 +36,6 @@ public KafkaContainer() { public KafkaContainer(String confluentPlatformVersion) { super(TestcontainersConfiguration.getInstance().getKafkaImage() + ":" + confluentPlatformVersion); - super.withNetwork(Network.SHARED); withExposedPorts(KAFKA_PORT); // Use two listeners with different names, it will force Kafka to communicate with itself via internal @@ -54,26 +51,6 @@ public KafkaContainer(String confluentPlatformVersion) { withEnv("KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS", "0"); } - @Override - public KafkaContainer withNetwork(Network network) { - useImplicitNetwork = false; - return super.withNetwork(network); - } - - @Override - public Network getNetwork() { - if (useImplicitNetwork) { - // TODO Only for backward compatibility, to be removed soon - logger().warn( - "Deprecation warning! " + - "KafkaContainer#getNetwork without an explicitly set network. " + - "Consider using KafkaContainer#withNetwork", - new Exception("Deprecated method") - ); - } - return super.getNetwork(); - } - public KafkaContainer withEmbeddedZookeeper() { externalZookeeperConnect = null; return self(); diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 1490caa3328..c5d719295ed 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -31,28 +31,6 @@ public void testUsage() throws Exception { } } - /** - * @deprecated the {@link Network} should be set explicitly with {@link KafkaContainer#withNetwork(Network)}. - */ - @Test - @Deprecated - public void testExternalZookeeperWithKafkaNetwork() throws Exception { - try ( - KafkaContainer kafka = new KafkaContainer() - .withExternalZookeeper("zookeeper:2181"); - - GenericContainer zookeeper = new GenericContainer("confluentinc/cp-zookeeper:4.0.0") - .withNetwork(kafka.getNetwork()) - .withNetworkAliases("zookeeper") - .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); - ) { - zookeeper.start(); - kafka.start(); - - testKafkaFunctionality(kafka.getBootstrapServers()); - } - } - @Test public void testExternalZookeeperWithExternalNetwork() throws Exception { try ( From bde786cd0b22ef03ca99bbd557264310f9da4ef3 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 29 Jun 2020 21:36:48 +0100 Subject: [PATCH 0835/4969] Add initial bounty policy documentation. (#2954) --- CONTRIBUTING.md | 8 ++++++++ docs/bounty.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 3 files changed, 60 insertions(+) create mode 100644 docs/bounty.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ffa95a477db..83afa8a9ea8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,3 +3,11 @@ Please see the [main contributing guidelines](./docs/contributing.md). There are additional docs describing [contributing documentation changes](./docs/contributing_docs.md). + +### GitHub Sponsorship + +Testcontainers is [in the GitHub Sponsors program](https://github.com/sponsors/testcontainers)! + +This repository is supported by our sponsors, meaning that issues are eligible to have a 'bounty' attached to them by sponsors. + +Please see [the bounty policy page](https://testcontainers.org/bounty) if you are interested, either as a sponsor or as a contributor. \ No newline at end of file diff --git a/docs/bounty.md b/docs/bounty.md new file mode 100644 index 00000000000..56ee501062c --- /dev/null +++ b/docs/bounty.md @@ -0,0 +1,51 @@ +# Testcontainers issue bounty policy + +## General + +We want to use issue bounties to encourage contributions in areas that are important to our sponsors, or tricky to solve. +This includes bug fixes and new features. +We hope that this will provide incentives to tackle issues, and gives sponsors a way to influence where development time is expended. +We also want to reward our contributors, some of whom make huge efforts to improve Testcontainers and help their fellow developers! + +!!! note + It's early days for our use of sponsorship, so we expect to evolve this policy over time, possibly without notice. In the event of any ambiguity or dispute, the [Testcontainers org core maintainers](#organisation-core-maintainers) have the final say. + + If you'd like to suggest an improvement to this policy, we'd be grateful for your input - please raise a pull request! + +## For Sponsors + +Sponsors will be able to create a number of 'bounties' per month, varying according to sponsorship tier. + +As a sponsor, the process for creating a bounty is as follows: + +* Raise an issue, or find an existing issue that describes the bug or feature. +* Start a discussion with the [Testcontainers org core maintainers](#organisation-core-maintainers) to agree that the issue is suitable for a bounty, and how much the reward amount should be. +* Once agreed, we will assign a label to the issue so that interested developers can find it. + +Sponsors can create up to 1 or 3 bounties (according to tier) _per calendar month_ - i.e. the counter resets on the 1st of each month. +If a sponsor does not use their full quota of bounty credits in a calendar month, they cannot be rolled over to the next month. + +Bounties will expire 90 days after creation - after this time, if they have not been resolved we will close them. + +## For Contributors + +As a contributor, the process for working on an issue with a bounty attached is: + +* Find an issue with a bounty attached to it and no assignee, clarify the requirements if necessary, and consider how you would approach working on it. +* Start a discussion with the [Testcontainers org core maintainers](#organisation-core-maintainers) and the bounty owner. To avoid unpleasant surprises at review time, we'll try to confirm that we're happy with your proposed solution. +* If we're happy with your proposed solution, we will assign the ticket to you. +* Once work is complete, we will go through the PR process as usual and merge the work when finished. +* To receive the bounty reward, [raise an invoice](https://opencollective.com/testcontainers/expenses/new) on Open Collective, following the expenses policy on that page. + +Note that a 20% cut of the bounty amount will normally be assigned to project maintainers for PR review work. +We believe this reflects that PR review can often be a significant amount of work for some issues - and also gives maintainers an incentive to complete the review and unlock the bounty reward! +Some pull requests are so well done that very little review is necessary. If that happens, the maintainers may choose not to take a cut of the bounty, and instead release the full amount to the contributor. + +## Organisation core maintainers + +The organisation core maintainers are: + +* Richard North (@rnorth) +* Sergei Egorov (@bsideup) +* Kevin Wittek (@kiview) + diff --git a/mkdocs.yml b/mkdocs.yml index 795a2bdb4e2..b8372e81ed8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -89,5 +89,6 @@ nav: - Contributing: - contributing.md - contributing_docs.md + - bounty.md extra: latest_version: 1.14.3 From 96de42be8fc635196c6fc55bb39c02125897e732 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 29 Jun 2020 21:38:28 +0100 Subject: [PATCH 0836/4969] Create FUNDING.yml --- .github/FUNDING.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..9889f256efc --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: [testcontainers] From 4ab556ce4527dd0574a377751e82f94832707f83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 21:45:07 +0100 Subject: [PATCH 0837/4969] Bump aws-java-sdk-s3 from 1.11.807 to 1.11.812 in /modules/localstack (#2948) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.807 to 1.11.812. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.807...1.11.812) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index a04c04a4751..ee726826b54 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.807' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.812' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From 0cc880eb6c4b93feea3ae50175625fd7062e5df3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 21:45:20 +0100 Subject: [PATCH 0838/4969] Bump aws-java-sdk-sqs from 1.11.807 to 1.11.812 in /modules/localstack (#2949) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.807 to 1.11.812. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.807...1.11.812) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ee726826b54..04a18626bad 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.812' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.807' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.812' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.13.41' } From c48f7077415e0e87d27ffd2247c00d70492f2513 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 21:45:36 +0100 Subject: [PATCH 0839/4969] Bump mariadb-java-client from 2.6.0 to 2.6.1 in /modules/mariadb (#2950) Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.6.0...2.6.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 38862c7f03c..a4f2f951233 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:0.8.2-alpha2' testCompile project(':jdbc-test') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.0' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.1' testCompile testFixtures(project(':r2dbc')) testCompile 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' From 1ad7ffa3bffc71c1768816c8fb86dbbe72186f24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 21:46:00 +0100 Subject: [PATCH 0840/4969] Bump aws-java-sdk-dynamodb from 1.11.807 to 1.11.812 in /modules/dynalite (#2953) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.807 to 1.11.812. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.807...1.11.812) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 7101f40552f..8045c273496 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.807' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.479' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.812' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.812' } From b0dbd3190e20a09ed3d0030d3cf23174190c82f1 Mon Sep 17 00:00:00 2001 From: Simon Schneider <10846939+raynigon@users.noreply.github.com> Date: Mon, 29 Jun 2020 23:02:21 +0200 Subject: [PATCH 0841/4969] Convert Docs for Webdriver Containers (#2927) Co-authored-by: Richard North --- docs/modules/webdriver_containers.md | 62 ++++++---------- ...ChromeRecordingWebDriverContainerTest.java | 73 ++++++++++++++----- .../junit/ChromeWebDriverContainerTest.java | 2 + .../junit/FirefoxWebDriverContainerTest.java | 2 + .../LocalServerWebDriverContainerTest.java | 4 + 5 files changed, 86 insertions(+), 57 deletions(-) diff --git a/docs/modules/webdriver_containers.md b/docs/modules/webdriver_containers.md index 70c06d9dbdd..40b27a5207f 100644 --- a/docs/modules/webdriver_containers.md +++ b/docs/modules/webdriver_containers.md @@ -22,70 +22,54 @@ every test. ## Example The following field in your JUnit UI test class will prepare a container running Chrome: -```java -@Rule -public BrowserWebDriverContainer chrome = - new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()); -``` + +[Chrome](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java) inside_block:junitRule + + Now, instead of instantiating an instance of WebDriver directly, use the following to obtain an instance inside your test methods: -```java -RemoteWebDriver driver = chrome.getWebDriver(); -``` + +[RemoteWebDriver](../../modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java) inside_block:getWebDriver + You can then use this driver instance like a regular WebDriver. Note that, if you want to test a **web application running on the host machine** (the machine the JUnit tests are running on - which is quite likely), you'll need to replace any references to `localhost` with an IP address that the Docker container can reach. Use the `getTestHostIpAddress()` method, e.g.: -```java -driver.get("http://" + chrome.getTestHostIpAddress() + ":8080/"); -``` + +[Open Web Page](../../modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java) inside_block:getPage + + ## Options ### Other browsers At the moment, Chrome and Firefox are supported. To switch, simply change the first parameter to the rule constructor: -```java -new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()); -``` - -or -```java -new BrowserWebDriverContainer() - .withCapabilities(new FirefoxOptions()); -``` + +[Chrome](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java) inside_block:junitRule +[Firefox](../../modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java) inside_block:junitRule + ### Recording videos By default, no videos will be recorded. However, you can instruct Testcontainers to capture videos for all tests or just for failing tests. -To do this, simply add extra parameters to the rule constructor: -```java -new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()) - .withRecordingMode(VncRecordingMode.RECORD_ALL, new File("./target/")) -``` + +[Record all Tests](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordAll +[Record failing Tests](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordFailing + -or if you only want videos for test failures: -```java -new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()) - .withRecordingMode(VncRecordingMode.RECORD_FAILING, new File("./target/")) -``` Note that the seconds parameter to `withRecordingMode` should be a directory where recordings can be saved. If you would like to customise the file name of the recording, or provide a different directory at runtime based on the description of the test and/or its success or failure, you may provide a custom recording file factory as follows: -```java -new BrowserWebDriverContainer() - //... - .withRecordingFileFactory(new CustomRecordingFileFactory()) -``` + +[CustomRecordingFileFactory](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:withRecordingFileFactory + + Note the factory must implement `org.testcontainers.containers.RecordingFileFactory`. diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java index 3872e3d8dd2..ead9a21ae4f 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java @@ -12,9 +12,12 @@ import org.testcontainers.containers.DefaultRecordingFileFactory; import org.testcontainers.lifecycle.TestDescription; +import java.io.File; import java.util.Optional; -import static org.junit.Assert.assertTrue; + +import static org.junit.Assert.assertEquals; import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; +import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_FAILING; @RunWith(Enclosed.class) public class ChromeRecordingWebDriverContainerTest extends BaseWebDriverContainerTest { @@ -26,10 +29,14 @@ public static class ChromeThatRecordsAllTests { @Test public void recordingTestThatShouldBeRecordedAndRetained() { + File target = vncRecordingDirectory.getRoot(); try ( + // recordAll { + // To do this, simply add extra parameters to the rule constructor: BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, vncRecordingDirectory.getRoot()) + .withRecordingMode(RECORD_ALL, target) + // } .withRecordingFileFactory(new DefaultRecordingFileFactory()) ) { chrome.start(); @@ -48,7 +55,7 @@ public String getFilesystemFriendlyName() { }, Optional.empty()); String[] files = vncRecordingDirectory.getRoot().list(new PatternFilenameFilter("PASSED-.*\\.flv")); - assertTrue("Recorded file not found", files.length == 1); + assertEquals("Recorded file not found", 1, files.length); } } } @@ -56,28 +63,58 @@ public String getFilesystemFriendlyName() { public static class ChromeThatRecordsFailingTests { @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()); + public TemporaryFolder vncRecordingDirectory = new TemporaryFolder(); @Test public void recordingTestThatShouldBeRecordedButNotPersisted() { - doSimpleExplore(chrome); + try ( + // withRecordingFileFactory { + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() + // } + .withCapabilities(new ChromeOptions()) + // withRecordingFileFactory { + .withRecordingFileFactory(new CustomRecordingFileFactory()) + // } + ) { + chrome.start(); + + doSimpleExplore(chrome); + } } @Test public void recordingTestThatShouldBeRecordedAndRetained() { - doSimpleExplore(chrome); - chrome.afterTest(new TestDescription() { - @Override - public String getTestId() { - return getFilesystemFriendlyName(); - } - - @Override - public String getFilesystemFriendlyName() { - return "ChromeThatRecordsFailingTests-recordingTestThatShouldBeRecordedAndRetained"; - } - }, Optional.of(new RuntimeException("Force writing of video file."))); + File target = vncRecordingDirectory.getRoot(); + try ( + // recordFailing { + // or if you only want videos for test failures: + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() + .withCapabilities(new ChromeOptions()) + .withRecordingMode(RECORD_FAILING, target) + // } + .withRecordingFileFactory(new DefaultRecordingFileFactory()) + ) { + chrome.start(); + + doSimpleExplore(chrome); + chrome.afterTest(new TestDescription() { + @Override + public String getTestId() { + return getFilesystemFriendlyName(); + } + + @Override + public String getFilesystemFriendlyName() { + return "ChromeThatRecordsFailingTests-recordingTestThatShouldBeRecordedAndRetained"; + } + }, Optional.of(new RuntimeException("Force writing of video file."))); + + String[] files = vncRecordingDirectory.getRoot().list(new PatternFilenameFilter("FAILED-.*\\.flv")); + assertEquals("Recorded file not found", 1, files.length); + } + } + + private static class CustomRecordingFileFactory extends DefaultRecordingFileFactory { } } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java index 7914e1bd810..92ba4e2cd37 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java @@ -11,9 +11,11 @@ */ public class ChromeWebDriverContainerTest extends BaseWebDriverContainerTest { + // junitRule { @Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() .withCapabilities(new ChromeOptions()); + // } @Before public void checkBrowserIsIndeedChrome() { diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java index 21b03164102..1f687aab762 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java @@ -11,9 +11,11 @@ */ public class FirefoxWebDriverContainerTest extends BaseWebDriverContainerTest { + // junitRule { @Rule public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer() .withCapabilities(new FirefoxOptions()); + // } @Before public void checkBrowserIsIndeedFirefox() { diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java index 0cee0cf49e2..f7d626c15b5 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java @@ -49,11 +49,15 @@ public void setupLocalServer() throws Exception { @Test public void testConnection() { + // getWebDriver { RemoteWebDriver driver = chrome.getWebDriver(); + // } // Construct a URL that the browser container can access + // getPage { String hostIpAddress = chrome.getTestHostIpAddress(); driver.get("http://" + hostIpAddress + ":" + localPort); + // } String headingText = driver.findElement(By.cssSelector("h1")).getText().trim(); From f0da2f3365a20b8a7f7d62ebc0b55098e95e5665 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 22:03:08 +0100 Subject: [PATCH 0842/4969] Bump s3 from 2.13.41 to 2.13.46 in /modules/localstack (#2947) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 04a18626bad..44a7e3fb6a8 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.812' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.13.41' + testCompile 'software.amazon.awssdk:s3:2.13.46' } From eecaa9a0461740d08e6393753cdd63e45b356088 Mon Sep 17 00:00:00 2001 From: JeanBaptisteWATENBERG Date: Mon, 29 Jun 2020 23:45:55 +0200 Subject: [PATCH 0843/4969] RabbitMQ: correct `shouldMountConfigurationFileSysctl` test so that it exercises the `withRabbitMQConfigSysctl` method (#2945) --- .../org/testcontainers/containers/RabbitMQContainerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index d8e9c7658c0..4c2787bf5ab 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -156,7 +156,7 @@ public void shouldMountConfigurationFileSysctl() { try (RabbitMQContainer container = new RabbitMQContainer()) { - container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); + container.withRabbitMQConfigSysctl(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); container.start(); assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.conf"); From d03768bdf6c5c39d4f0382a98f3defbd0e2144d1 Mon Sep 17 00:00:00 2001 From: Simon Schneider <10846939+raynigon@users.noreply.github.com> Date: Mon, 29 Jun 2020 23:47:00 +0200 Subject: [PATCH 0844/4969] Convert Docs for Kafka Module #1158 (#2925) --- docs/modules/kafka.md | 36 ++++++++++--------- .../containers/KafkaContainerTest.java | 32 +++++++++++++++++ 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index a96a0a0b43a..35ac37b6906 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -11,41 +11,45 @@ More precisely Testcontainers uses the official Docker images for [Confluent OSS ## Example The following field in your JUnit test class will prepare a container running Kafka: -```java -@Rule -public KafkaContainer kafka = new KafkaContainer(); -``` + +[JUnit Rule](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:junitRule + Now your tests or any other process running on your machine can get access to running Kafka broker by using the following bootstrap server location: -```java -kafka.getBootstrapServers() -``` + + +[Bootstrap Servers](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:getBootstrapServers + + ## Options ### Selecting Kafka version You can select a version of Confluent Platform by passing it to the container's constructor: -```java -new KafkaContainer("4.1.2") -``` + +[Version Constructor](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:constructorWithVersion + + + The correspondence between Confluent Platform versions and Kafka versions can be seen [in Confluent documentation](https://docs.confluent.io/current/installation/versions-interoperability.html#cp-and-apache-kafka-compatibility) ### Using external Zookeeper If for some reason you want to use an externally running Zookeeper, then just pass its location during construction: -```java -new KafkaContainer().withExternalZookeeper("localhost:2181") -``` + +[External Zookeeper](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:withExternalZookeeper + + ## Multi-container usage If your test needs to run some other Docker container which needs access to the Kafka, do the following: * Run your other container on the same network as Kafka container, e.g.: -```java -new GenericContainer("myImage").withNetwork(kafka.getNetwork()) -``` + +[Network](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:withKafkaNetwork + * Use `kafka.getNetworkAliases().get(0)+":9092"` as bootstrap server location. Or just give your Kafka container a network alias of your liking. diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index c5d719295ed..25bc1b5022c 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -10,6 +10,7 @@ import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.Rule; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; @@ -23,6 +24,11 @@ public class KafkaContainerTest { + // junitRule { + @Rule + public KafkaContainer kafka = new KafkaContainer(); + // } + @Test public void testUsage() throws Exception { try (KafkaContainer kafka = new KafkaContainer()) { @@ -31,22 +37,48 @@ public void testUsage() throws Exception { } } + + @Test + public void testUsageWithVersion() throws Exception { + try ( + // constructorWithVersion { + KafkaContainer kafka = new KafkaContainer("4.1.2") + // } + ) { + kafka.start(); + testKafkaFunctionality( + // getBootstrapServers { + kafka.getBootstrapServers() + // } + ); + } + } + @Test public void testExternalZookeeperWithExternalNetwork() throws Exception { try ( Network network = Network.newNetwork(); + // withExternalZookeeper { KafkaContainer kafka = new KafkaContainer() .withNetwork(network) .withExternalZookeeper("zookeeper:2181"); + // } GenericContainer zookeeper = new GenericContainer("confluentinc/cp-zookeeper:4.0.0") .withNetwork(network) .withNetworkAliases("zookeeper") .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); + + // withKafkaNetwork { + GenericContainer application = new GenericContainer("alpine").withNetwork(kafka.getNetwork()) + // } + .withNetworkAliases("dummy") + .withCommand("sleep 10000") ) { zookeeper.start(); kafka.start(); + application.start(); testKafkaFunctionality(kafka.getBootstrapServers()); } From 6186598c9b518e71fcc55ff313a5ac1460ff3df9 Mon Sep 17 00:00:00 2001 From: Kirill Merkushev Date: Tue, 30 Jun 2020 16:49:03 +0200 Subject: [PATCH 0845/4969] Make it possible to enable functions worker in PulsarContainer (#2711) * Method to enable functions worker in pulsar container This change should simplify a bit pulsar functions development experience Tried here: https://github.com/lanwen/pulsar-functions-example Without waiter pulsar could return random 503, depending on how fast was a call. * treat functions worker method as a flag to enable in configure real functions upload test * upd pulsar to 2.5.1 * don't store jar * expect error for functions without worker * reduce the changeset Co-authored-by: Sergei Egorov --- modules/pulsar/build.gradle | 1 + .../containers/PulsarContainer.java | 23 +++++++++++++- .../containers/PulsarContainerTest.java | 30 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 371aa0c11d0..b0a76d673ad 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,4 +5,5 @@ dependencies { testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.5.1' } diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index c9532979057..936759efb1a 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.utility.TestcontainersConfiguration; /** @@ -14,6 +15,8 @@ public class PulsarContainer extends GenericContainer { private static final String PULSAR_VERSION = "2.2.0"; + private boolean functionsWorkerEnabled = false; + public PulsarContainer() { this(PULSAR_VERSION); } @@ -25,6 +28,25 @@ public PulsarContainer(String pulsarVersion) { waitingFor(Wait.forHttp(METRICS_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); } + @Override + protected void configure() { + super.configure(); + + if (functionsWorkerEnabled) { + withCommand("/pulsar/bin/pulsar", "standalone"); + waitingFor( + new WaitAllStrategy() + .withStrategy(waitStrategy) + .withStrategy(Wait.forLogMessage(".*Function worker service started.*", 1)) + ); + } + } + + public PulsarContainer withFunctionsWorker() { + functionsWorkerEnabled = true; + return this; + } + public String getPulsarBrokerUrl() { return String.format("pulsar://%s:%s", getHost(), getMappedPort(BROKER_PORT)); } @@ -33,4 +55,3 @@ public String getHttpServiceUrl() { return String.format("http://%s:%s", getHost(), getMappedPort(BROKER_HTTP_PORT)); } } - diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index cacf79729e0..e9d41516670 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -1,5 +1,7 @@ package org.testcontainers.containers; +import org.apache.pulsar.client.admin.PulsarAdmin; +import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.Producer; @@ -10,6 +12,7 @@ import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class PulsarContainerTest { @@ -23,6 +26,33 @@ public void testUsage() throws Exception { } } + @Test + public void shouldNotEnableFunctionsWorkerByDefault() throws Exception { + try (PulsarContainer pulsar = new PulsarContainer("2.5.1")) { + pulsar.start(); + + PulsarAdmin pulsarAdmin = PulsarAdmin.builder() + .serviceHttpUrl(pulsar.getHttpServiceUrl()) + .build(); + + assertThatThrownBy(() -> pulsarAdmin.functions().getFunctions("public", "default")) + .isInstanceOf(PulsarAdminException.class); + } + } + + @Test + public void shouldWaitForFunctionsWorkerStarted() throws Exception { + try (PulsarContainer pulsar = new PulsarContainer("2.5.1").withFunctionsWorker()) { + pulsar.start(); + + PulsarAdmin pulsarAdmin = PulsarAdmin.builder() + .serviceHttpUrl(pulsar.getHttpServiceUrl()) + .build(); + + assertThat(pulsarAdmin.functions().getFunctions("public", "default")).hasSize(0); + } + } + protected void testPulsarFunctionality(String pulsarBrokerUrl) throws Exception { try ( From 25a9aa51a11d3c050da8b6b532dac50ef8e227ba Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 30 Jun 2020 21:02:45 +0100 Subject: [PATCH 0846/4969] Add backers (#2958) Co-authored-by: Kevin Wittek --- docs/index.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/index.md b/docs/index.md index 8b3ffda05d2..d665557cff1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -119,6 +119,21 @@ testImplementation('org.testcontainers:mysql') //no version specified * [Transferwise](https://transferwise.com/) - Integration testing for different RDBMS, kafka and micro services * [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) +## Sponsors + +Testcontainers is on Github Sponsors! Please consider sponsoring us to sustain the project and help us improve it further. + + + +### Backers + +A huge thank you to our backers: + +* [Philip Riecks (@rieckpil)](https://github.com/rieckpil) +* [Karl Heinz Marbaise (@khmarbaise)](https://github.com/khmarbaise) +* [Sascha Frinken (@sascha-frinken)](https://github.com/sascha-frinken) + + ## License See [LICENSE](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/LICENSE). From 923472ff114d99b2ac0e199a86829879c24c8471 Mon Sep 17 00:00:00 2001 From: kezhenxu94 Date: Fri, 3 Jul 2020 23:36:34 +0800 Subject: [PATCH 0847/4969] Add Apache SkyWalking to the list of users (#2967) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index d665557cff1..6c8bf49f08f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -118,6 +118,7 @@ testImplementation('org.testcontainers:mysql') //no version specified * [Marquez](https://marquezproject.github.io/marquez) - PostgreSQL integration testing * [Transferwise](https://transferwise.com/) - Integration testing for different RDBMS, kafka and micro services * [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) +* [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) ## Sponsors From 7eb504a411337b4fb3c0772cf5938a2272f6bf3a Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Sun, 5 Jul 2020 17:04:36 +0200 Subject: [PATCH 0848/4969] Add Windows Server 2019 as unsupported to docs (#2963) --- docs/supported_docker_environment/windows.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/supported_docker_environment/windows.md b/docs/supported_docker_environment/windows.md index 6afab5972f2..9a50a844b04 100644 --- a/docs/supported_docker_environment/windows.md +++ b/docs/supported_docker_environment/windows.md @@ -5,6 +5,7 @@ * Docker version 17.06 is confirmed to work on Windows 10 with Hyper-V. * Testcontainers supports communication with Docker on Docker for Windows using named pipes. * WSL2 backend is supported starting with Windows 10 2004. (**Beta**) + * Docker on Windows Server 2019 is currently **not supported** (also note [this issue](https://github.com/testcontainers/testcontainers-java/issues/2960)). ## Limitations The following features are not available or do not work correctly so make sure you do not use them or use them with From 66e6a2fb171f9102d699dbd863d4401d5fbfcb6c Mon Sep 17 00:00:00 2001 From: Thomas Schmidt Date: Sun, 5 Jul 2020 18:06:13 +0200 Subject: [PATCH 0849/4969] Adapt docs to non deprecated way of setting --memory and --memory-swap (#2511) Co-authored-by: Thomas Schmidt Co-authored-by: Richard North --- .../generic/src/test/java/generic/CmdModifierTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index 6d075c0bccc..172a821b178 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -18,10 +18,15 @@ public class CmdModifierTest { // } // memory { + private long memoryInBytes = 8 * 1024 * 1024; + private long memorySwapInBytes = 12 * 1024 * 1024; + @Rule public GenericContainer memoryLimitedRedis = new GenericContainer<>("redis:3.0.2") - .withCreateContainerCmdModifier(cmd -> cmd.withMemory((long) 8 * 1024 * 1024)) - .withCreateContainerCmdModifier(cmd -> cmd.withMemorySwap((long) 12 * 1024 * 1024)); + .withCreateContainerCmdModifier(cmd -> cmd.getHostConfig() + .withMemory(memoryInBytes) + .withMemorySwap(memorySwapInBytes) + ); // } From 965fcf552dcc27e1fbffd01a50e9a33ea496120c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 08:33:29 +0100 Subject: [PATCH 0850/4969] Bump tomcat-jdbc from 9.0.36 to 9.0.37 in /modules/jdbc-test (#2969) Bumps tomcat-jdbc from 9.0.36 to 9.0.37. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index e901869f04e..0c06ad083e0 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -15,7 +15,7 @@ dependencies { } compile 'commons-dbutils:commons-dbutils:1.7' - compile 'org.apache.tomcat:tomcat-jdbc:9.0.36' + compile 'org.apache.tomcat:tomcat-jdbc:9.0.37' compile 'org.vibur:vibur-dbcp:25.0' compile 'mysql:mysql-connector-java:8.0.20' } From f7c027f20779dbfd30eb8592994ae495097f263e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 08:33:37 +0100 Subject: [PATCH 0851/4969] Bump rest-assured from 4.3.0 to 4.3.1 in /modules/vault (#2970) Bumps [rest-assured](https://github.com/jayway/rest-assured) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/jayway/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/jayway/rest-assured/compare/rest-assured-4.3.0...rest-assured-4.3.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 2b9f702f9d9..0d094905198 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { compile project(':testcontainers') testCompile 'com.bettercloud:vault-java-driver:5.1.0' - testCompile 'io.rest-assured:rest-assured:4.3.0' + testCompile 'io.rest-assured:rest-assured:4.3.1' testCompile 'org.assertj:assertj-core:3.16.1' } From 8c689fa4e1f32dd0f8db7d79b2b6e2137975de9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 08:33:47 +0100 Subject: [PATCH 0852/4969] Bump tomcat-jdbc from 9.0.36 to 9.0.37 in /modules/jdbc (#2971) Bumps tomcat-jdbc from 9.0.36 to 9.0.37. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 3b6aea15c59..cd10c7a98c3 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.36' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.37' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' } From d41e04ca46a4adfeee9dc311acb31c18566dc821 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 08:33:57 +0100 Subject: [PATCH 0853/4969] Bump s3 from 2.13.46 to 2.13.50 in /modules/localstack (#2972) Bumps s3 from 2.13.46 to 2.13.50. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 44a7e3fb6a8..8945c082685 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.812' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.13.46' + testCompile 'software.amazon.awssdk:s3:2.13.50' } From ddfa60a1932de7b23a73c8ff85a2fb6febbcfb3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 08:34:06 +0100 Subject: [PATCH 0854/4969] Bump aws-java-sdk-s3 from 1.11.812 to 1.11.816 in /modules/localstack (#2973) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.812 to 1.11.816. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.812...1.11.816) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8945c082685..6e9e44af320 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.812' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.807' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.816' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.816' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.812' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.13.50' From af4b1a312d6523e08f21bbcb69dcafd74597b733 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 08:34:25 +0100 Subject: [PATCH 0855/4969] Bump pulsar-client-admin from 2.5.1 to 2.6.0 in /modules/pulsar (#2975) Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.5.1 to 2.6.0. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.5.1...v2.6.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index b0a76d673ad..a8f55696a65 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.1' - testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.5.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.0' } From c13aea3f02989f3c9294ec5ca23ed0a59a4b1eaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 08:34:34 +0100 Subject: [PATCH 0856/4969] Bump aws-java-sdk-dynamodb from 1.11.812 to 1.11.816 in /modules/dynalite (#2976) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.812 to 1.11.816. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.812...1.11.816) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 8045c273496..b3919a3eaf3 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.812' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.816' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.812' } From 448d05fc7da5fd5d1bd7744201202d8da52abb4c Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 6 Jul 2020 20:01:16 +0100 Subject: [PATCH 0857/4969] Add breaking change and deprecation sections to release notes (#2978) --- .github/release-drafter.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index af82504717a..4da341055c2 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -5,10 +5,14 @@ template: | $CHANGES categories: + - title: ⚠️ Breaking API changes + label: type/breaking-api-change - title: 🚀 Features & Enhancements labels: - type/feature - type/enhancement + - title: ☠️ Deprecations + label: type/deprecation - title: 🐛 Bug Fixes label: type/bug - title: 📖 Documentation From ddbaf94a21aabe2b2e98d16fd735e0917e88a7d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2020 08:53:47 +0100 Subject: [PATCH 0858/4969] Bump cucumber-java from 5.7.0 to 6.1.1 in /examples (#2919) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 5.7.0 to 6.1.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v5.7.0...v6.1.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index e4c44c0e063..d17837f1518 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:5.7.0' + testImplementation 'io.cucumber:cucumber-java:6.1.1' testImplementation 'io.cucumber:cucumber-junit:6.1.1' testImplementation 'org.testcontainers:selenium' } From 1c97b978ac6ccfba0119986c22e4ac6d9ac955fa Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 9 Jul 2020 17:52:06 +0200 Subject: [PATCH 0859/4969] Un-shade docker-java-api (#2882) This PR makes Testcontainers depend on `docker-java-api` instead of including it into our JAR unshaded. Note that `docker-java-core` and `docker-java-transport-okhttp` remain shaded due to their transitive dependencies like Guava or now-in-Kotlin OkHttp. The transition requires a breaking change in the `DockerClientProviderStrategy` API and includes a rework. The rework also includes an improvement that removes one Docker API call (`/_ping`) and instead reuses the `/_info` one. --- build.gradle | 5 - core/build.gradle | 38 ++++- .../testcontainers/JarFileShadingTest.java | 11 +- .../testcontainers/PublicBinaryAPITest.java | 7 +- .../testcontainers/DockerClientFactory.java | 27 ++- .../containers/GenericContainer.java | 8 +- .../output/FrameConsumerResultCallback.java | 2 +- .../DockerClientProviderStrategy.java | 154 ++++++++++-------- .../DockerMachineClientProviderStrategy.java | 87 +++++----- ...dSystemPropertyClientProviderStrategy.java | 44 ++--- .../LogToStringContainerCallback.java | 10 +- .../NpipeSocketClientProviderStrategy.java | 57 ++----- ...oxiedUnixSocketClientProviderStrategy.java | 31 ---- .../dockerclient/TransportConfig.java | 18 ++ .../UnixSocketClientProviderStrategy.java | 53 ++---- .../WindowsClientProviderStrategy.java | 41 ----- .../images/LoggedPullImageResultCallback.java | 2 +- ...eLimitedLoggedPullImageResultCallback.java | 2 +- .../images/builder/ImageFromDockerfile.java | 2 +- .../resources/META-INF/services/README.md | 1 - ....dockerclient.DockerClientProviderStrategy | 1 - ...ded.com.fasterxml.jackson.core.JsonFactory | 1 - ...ded.com.fasterxml.jackson.core.ObjectCodec | 1 - ...ockerjava.api.command.DockerCmdExecFactory | 1 - ...ers.shaded.javax.ws.rs.ext.RuntimeDelegate | 1 - ...fish.hk2.extension.ServiceLocatorGenerator | 1 - ...external.generator.ServiceLocatorGenerator | 1 - 27 files changed, 268 insertions(+), 339 deletions(-) delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java create mode 100644 core/src/main/java/org/testcontainers/dockerclient/TransportConfig.java delete mode 100644 core/src/main/java/org/testcontainers/dockerclient/WindowsClientProviderStrategy.java delete mode 100644 core/src/main/resources/META-INF/services/README.md delete mode 100755 core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.JsonFactory delete mode 100755 core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.ObjectCodec delete mode 100644 core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.github.dockerjava.api.command.DockerCmdExecFactory delete mode 100644 core/src/main/resources/META-INF/services/org.testcontainers.shaded.javax.ws.rs.ext.RuntimeDelegate delete mode 100644 core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.glassfish.hk2.extension.ServiceLocatorGenerator delete mode 100644 core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.jvnet.hk2.external.generator.ServiceLocatorGenerator diff --git a/build.gradle b/build.gradle index 382ecdf161e..b7830992b07 100644 --- a/build.gradle +++ b/build.gradle @@ -122,11 +122,6 @@ subprojects { for (pkg in packages) { pkg = pkg.replaceAll('/', '.') - if (pkg.startsWith("com.github.dockerjava.")) { - // Keep docker-java's package inside the final jar - continue; - } - tasks.shadowJar.relocate(pkg, "org.testcontainers.shaded.${pkg}") } } diff --git a/core/build.gradle b/core/build.gradle index e1fb724597e..98452944bd0 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -100,17 +100,33 @@ task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { "org.testcontainers.containers.wait.WaitAllStrategy", "org.testcontainers.containers.wait.WaitStrategy", "org.testcontainers.dockerclient.AuditLoggingDockerClient", + "org.testcontainers.dockerclient.LogToStringContainerCallback", + "org.testcontainers.dockerclient.DockerMachineClientProviderStrategy", + "org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy", + "org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy", + "org.testcontainers.dockerclient.ProxiedUnixSocketClientProviderStrategy", + "org.testcontainers.dockerclient.WindowsClientProviderStrategy", + "org.testcontainers.dockerclient.UnixSocketClientProviderStrategy", "org.testcontainers.dockerclient.auth.AuthDelegatingDockerClientConfig", "org.testcontainers.containers.GenericContainer\$AbstractWaitStrategy", "org.testcontainers.dockerclient.transport.okhttp.NamedPipeSocketFactory", "org.testcontainers.dockerclient.transport.okhttp.OkHttpDockerCmdExecFactory", "org.testcontainers.dockerclient.transport.okhttp.UnixSocketFactory", + "org.testcontainers.containers.output.FrameConsumerResultCallback", + "org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback", ] methodExcludes = [ "org.testcontainers.dockerclient.DockerClientConfigUtils#getDetectedDockerHostIp()", "org.testcontainers.dockerclient.DockerClientConfigUtils#getDockerHostIpAddress(com.github.dockerjava.core.DockerClientConfig)", + "org.testcontainers.dockerclient.DockerClientProviderStrategy#checkOSType()", + "org.testcontainers.dockerclient.DockerClientProviderStrategy#getClientForConfig(com.github.dockerjava.core.DockerClientConfig)", + "org.testcontainers.dockerclient.DockerClientProviderStrategy#ping(com.github.dockerjava.api.DockerClient, int)", + "org.testcontainers.dockerclient.DockerClientProviderStrategy#test()", + + "org.testcontainers.dockerclient.UnixSocketClientProviderStrategy#tryConfiguration(java.lang.String)", + "org.testcontainers.utility.ResourceReaper#start(java.lang.String, com.github.dockerjava.api.DockerClient, boolean)", "org.testcontainers.containers.Container#fetchDockerDaemonInfo()", @@ -126,6 +142,10 @@ task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { "org.testcontainers.containers.GenericContainer#containerId", "org.testcontainers.containers.GenericContainer#containerName", "org.testcontainers.containers.GenericContainer#dockerDaemonInfo", + + "org.testcontainers.dockerclient.DockerClientProviderStrategy#LOGGER", + "org.testcontainers.dockerclient.DockerClientProviderStrategy#client", + "org.testcontainers.dockerclient.DockerClientProviderStrategy#config", ] onlyBinaryIncompatibleModified = true @@ -150,25 +170,27 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } - compile ('org.rnorth.visible-assertions:visible-assertions:2.1.2') { - // Excluded in favor of jna-platform below - exclude(group: "net.java.dev.jna", module: "jna") - } + compile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compile "net.java.dev.jna:jna-platform:5.5.0" + compile "com.github.docker-java:docker-java-api:3.2.5" - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.5') { - exclude(group: 'net.java.dev.jna') + shaded ('com.github.docker-java:docker-java-core:3.2.5') { + exclude(group: 'com.github.docker-java', module: 'docker-java-api') + exclude(group: 'com.github.docker-java', module: 'docker-java-transport') + exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') exclude(group: 'com.google.code.findbug') exclude(group: 'org.slf4j') exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-zerodep:3.2.5') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.5') { + exclude(group: 'com.github.docker-java', module: 'docker-java-core') exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } + compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.5' + shaded "org.yaml:snakeyaml:1.25" shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' diff --git a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java index 587ab6277f6..4cf7b3a9e9f 100644 --- a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java +++ b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java @@ -15,21 +15,12 @@ public class JarFileShadingTest extends AbstractJarFileTest { public void testPackages() throws Exception { assertThatFileList(root).containsOnly( "org", - "META-INF", - "com" + "META-INF" ); assertThatFileList(root.resolve("org")).containsOnly( "testcontainers" ); - - assertThatFileList(root.resolve("com")).containsOnly( - "github" - ); - - assertThatFileList(root.resolve("com").resolve("github")).containsOnly( - "dockerjava" - ); } @Test diff --git a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java index 93d1a759096..6a5a766d24e 100644 --- a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java +++ b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java @@ -88,10 +88,11 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IO @Before public void setUp() { - Assume.assumeFalse(classNode.name.startsWith("com.github.dockerjava.")); switch (classNode.name) { - // TODO should go to docker-java project - case "org/testcontainers/dockerclient/auth/AuthDelegatingDockerClientConfig": + // Necessary evil + case "org/testcontainers/dockerclient/UnixSocketClientProviderStrategy": + case "org/testcontainers/dockerclient/DockerClientProviderStrategy": + case "org/testcontainers/dockerclient/WindowsClientProviderStrategy": Assume.assumeTrue(false); } } diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 95e0c9838ba..baebe164c48 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -1,16 +1,17 @@ package org.testcontainers; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AccessMode; import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.Image; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Version; import com.github.dockerjava.api.model.Volume; -import com.github.dockerjava.core.command.ExecStartResultCallback; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import lombok.Getter; @@ -26,6 +27,7 @@ import org.testcontainers.utility.TestcontainersConfiguration; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -148,7 +150,7 @@ public DockerClient client() { String hostIpAddress = strategy.getDockerHostIpAddress(); log.info("Docker host IP address is {}", hostIpAddress); - final DockerClient client = new DelegatingDockerClient(strategy.getClient()) { + final DockerClient client = new DelegatingDockerClient(strategy.getDockerClient()) { @Override public void close() { throw new IllegalStateException("You should never close the global DockerClient!"); @@ -228,7 +230,24 @@ private void checkDiskSpace(DockerClient dockerClient, String id) { try { dockerClient .execStartCmd(dockerClient.execCreateCmd(id).withAttachStdout(true).withCmd("df", "-P").exec().getId()) - .exec(new ExecStartResultCallback(outputStream, null)) + .exec(new ResultCallback.Adapter() { + @Override + public void onNext(Frame frame) { + if (frame == null) { + return; + } + switch (frame.getStreamType()) { + case RAW: + case STDOUT: + try { + outputStream.write(frame.getPayload()); + outputStream.flush(); + } catch (IOException e) { + onError(e); + } + } + } + }) .awaitCompletion(); } catch (Exception e) { log.debug("Can't exec disk checking command", e); @@ -295,7 +314,7 @@ public String dockerHostIpAddress() { public T runInsideDocker(Consumer createContainerCmdConsumer, BiFunction block) { // We can't use client() here because it might create an infinite loop - return runInsideDocker(getOrInitializeStrategy().getClient(), createContainerCmdConsumer, block); + return runInsideDocker(getOrInitializeStrategy().getDockerClient(), createContainerCmdConsumer, block); } private T runInsideDocker(DockerClient client, Consumer createContainerCmdConsumer, BiFunction block) { diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 072129de60c..417826e83b5 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -17,6 +17,7 @@ import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.api.model.VolumesFrom; +import com.github.dockerjava.core.DefaultDockerClientConfig; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; @@ -514,12 +515,15 @@ void checksumFile(File file, Checksum checksum) { @UnstableAPI @SneakyThrows(JsonProcessingException.class) final String hash(CreateContainerCmd createCommand) { - // TODO add Testcontainers' version to the hash - byte[] commandJson = new ObjectMapper() + DefaultDockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); + + byte[] commandJson = dockerClientConfig.getObjectMapper() + .copy() .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY) .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) .writeValueAsBytes(createCommand); + // TODO add Testcontainers' version to the hash return Hashing.sha1().hashBytes(commandJson).toString(); } diff --git a/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java b/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java index 6894b9ec4b8..8c7480320a8 100644 --- a/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java +++ b/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java @@ -1,9 +1,9 @@ package org.testcontainers.containers.output; +import com.github.dockerjava.api.async.ResultCallbackTemplate; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.StreamType; -import com.github.dockerjava.core.async.ResultCallbackTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 9573613c613..3f288d015d0 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -1,14 +1,17 @@ package org.testcontainers.dockerclient; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Network; -import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; import com.github.dockerjava.okhttp.OkDockerHttpClient; import com.github.dockerjava.transport.DockerHttpClient; import com.github.dockerjava.zerodep.ZerodepDockerHttpClient; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; @@ -16,8 +19,6 @@ import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.rnorth.ducttape.unreliables.Unreliables; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.testcontainers.utility.TestcontainersConfiguration; import java.net.URI; @@ -32,27 +33,21 @@ /** * Mechanism to find a viable Docker client configuration according to the host system environment. */ +@Slf4j public abstract class DockerClientProviderStrategy { - protected DockerClient client; - protected DockerClientConfig config; + @Getter(lazy = true) + private final DockerClient dockerClient = getClientForConfig(getTransportConfig()); private String dockerHostIpAddress; - private static final RateLimiter PING_RATE_LIMITER = RateLimiterBuilder.newBuilder() - .withRate(2, TimeUnit.SECONDS) + private final RateLimiter PING_RATE_LIMITER = RateLimiterBuilder.newBuilder() + .withRate(10, TimeUnit.SECONDS) .withConstantThroughput() .build(); private static final AtomicBoolean FAIL_FAST_ALWAYS = new AtomicBoolean(false); - protected static final Logger LOGGER = LoggerFactory.getLogger(DockerClientProviderStrategy.class); - - /** - * @throws InvalidConfigurationException if this strategy fails - */ - public abstract void test() throws InvalidConfigurationException; - /** * @return a short textual description of the strategy */ @@ -73,6 +68,35 @@ protected int getPriority() { return 0; } + /** + * @throws InvalidConfigurationException if this strategy fails + */ + public abstract TransportConfig getTransportConfig() throws InvalidConfigurationException; + + /** + * @return a usable, tested, Docker client configuration for the host system environment + * + * @deprecated use {@link #getDockerClient()} + */ + @Deprecated + public DockerClient getClient() { + DockerClient dockerClient = getDockerClient(); + try { + Unreliables.retryUntilSuccess(30, TimeUnit.SECONDS, () -> { + return PING_RATE_LIMITER.getWhenReady(() -> { + log.debug("Pinging docker daemon..."); + dockerClient.pingCmd().exec(); + log.debug("Pinged"); + return true; + }); + }); + } catch (TimeoutException e) { + IOUtils.closeQuietly(dockerClient); + throw e; + } + return dockerClient; + } + /** * Determine the right DockerClientConfig to use for building clients by trial-and-error. * @@ -96,19 +120,19 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List strategyClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(it); return Stream.of(strategyClass.newInstance()); } catch (ClassNotFoundException e) { - LOGGER.warn("Can't instantiate a strategy from {} (ClassNotFoundException). " + + log.warn("Can't instantiate a strategy from {} (ClassNotFoundException). " + "This probably means that cached configuration refers to a client provider " + "class that is not available in this version of Testcontainers. Other " + "strategies will be tried instead.", it); return Stream.empty(); } catch (InstantiationException | IllegalAccessException e) { - LOGGER.warn("Can't instantiate a strategy from {}", it, e); + log.warn("Can't instantiate a strategy from {}", it, e); return Stream.empty(); } }) // Ignore persisted strategy if it's not persistable anymore .filter(DockerClientProviderStrategy::isPersistable) - .peek(strategy -> LOGGER.info("Loaded {} from ~/.testcontainers.properties, will try it first", strategy.getClass().getName())), + .peek(strategy -> log.info("Loaded {} from ~/.testcontainers.properties, will try it first", strategy.getClass().getName())), strategies .stream() .filter(DockerClientProviderStrategy::isApplicable) @@ -116,16 +140,35 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List { try { - strategy.test(); - LOGGER.info("Found Docker environment with {}", strategy.getDescription()); - LOGGER.debug( + DockerClient dockerClient = strategy.getDockerClient(); + + Info info; + try { + info = Unreliables.retryUntilSuccess(30, TimeUnit.SECONDS, () -> { + return strategy.PING_RATE_LIMITER.getWhenReady(() -> { + log.debug("Pinging docker daemon..."); + return dockerClient.infoCmd().exec(); + }); + }); + } catch (TimeoutException e) { + IOUtils.closeQuietly(dockerClient); + throw e; + } + log.info("Found Docker environment with {}", strategy.getDescription()); + log.debug( "Transport type: '{}', Docker host: '{}'", TestcontainersConfiguration.getInstance().getTransportType(), - strategy.config != null - ? strategy.config.getDockerHost() - : "" + strategy.getTransportConfig().getDockerHost() ); - strategy.checkOSType(); + + log.debug("Checking Docker OS type for {}", strategy.getDescription()); + String osType = info.getOsType(); + if (StringUtils.isBlank(osType)) { + log.warn("Could not determine Docker OS type"); + } else if (!osType.equals("linux")) { + log.warn("{} is currently not supported", osType); + throw new InvalidConfigurationException(osType + " containers are currently not supported"); + } if (strategy.isPersistable()) { TestcontainersConfiguration.getInstance().updateGlobalConfig("docker.client.strategy", strategy.getClass().getName()); @@ -155,73 +198,57 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List { - LOGGER.error("Could not find a valid Docker environment. Please check configuration. Attempted configurations were:"); + log.error("Could not find a valid Docker environment. Please check configuration. Attempted configurations were:"); for (String failureMessage : configurationFailures) { - LOGGER.error(" " + failureMessage); + log.error(" " + failureMessage); } - LOGGER.error("As no valid configuration was found, execution cannot continue"); + log.error("As no valid configuration was found, execution cannot continue"); FAIL_FAST_ALWAYS.set(true); return new IllegalStateException("Could not find a valid Docker environment. Please see logs and check configuration"); }); } - /** - * @return a usable, tested, Docker client configuration for the host system environment - */ - public DockerClient getClient() { - return new AuditLoggingDockerClient(client); - } - - protected DockerClient getClientForConfig(DockerClientConfig config) { - config = new AuthDelegatingDockerClientConfig(config); + public static DockerClient getClientForConfig(TransportConfig transportConfig) { final DockerHttpClient dockerHttpClient; String transportType = TestcontainersConfiguration.getInstance().getTransportType(); switch (transportType) { case "okhttp": dockerHttpClient = new OkDockerHttpClient.Builder() - .dockerHost(config.getDockerHost()) - .sslConfig(config.getSSLConfig()) + .dockerHost(transportConfig.getDockerHost()) + .sslConfig(transportConfig.getSslConfig()) .build(); break; case "httpclient5": dockerHttpClient = new ZerodepDockerHttpClient.Builder() - .dockerHost(config.getDockerHost()) - .sslConfig(config.getSSLConfig()) + .dockerHost(transportConfig.getDockerHost()) + .sslConfig(transportConfig.getSslConfig()) .build(); break; default: throw new IllegalArgumentException("Unknown transport type '" + transportType + "'"); } - return DockerClientImpl.getInstance(config, dockerHttpClient); - } - - protected void ping(DockerClient client, int timeoutInSeconds) { - try { - Unreliables.retryUntilSuccess(timeoutInSeconds, TimeUnit.SECONDS, () -> { - return PING_RATE_LIMITER.getWhenReady(() -> { - LOGGER.debug("Pinging docker daemon..."); - client.pingCmd().exec(); - return true; - }); - }); - } catch (TimeoutException e) { - IOUtils.closeQuietly(client); - throw e; - } + return DockerClientImpl.getInstance( + new AuthDelegatingDockerClientConfig( + DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerHost(transportConfig.getDockerHost().toString()) + .build() + ), + dockerHttpClient + ); } public synchronized String getDockerHostIpAddress() { if (dockerHostIpAddress == null) { - dockerHostIpAddress = resolveDockerHostIpAddress(client, config.getDockerHost()); + dockerHostIpAddress = resolveDockerHostIpAddress(getDockerClient(), getTransportConfig().getDockerHost()); } return dockerHostIpAddress; } @@ -254,15 +281,4 @@ static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost) { return null; } } - - protected void checkOSType() { - LOGGER.debug("Checking Docker OS type for {}", this.getDescription()); - String osType = client.infoCmd().exec().getOsType(); - if (StringUtils.isBlank(osType)) { - LOGGER.warn("Could not determine Docker OS type"); - } else if (!osType.equals("linux")) { - LOGGER.warn("{} is currently not supported", osType); - throw new InvalidConfigurationException(osType + " containers are currently not supported"); - } - } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java index fac092044c7..2b0454c1ee6 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java @@ -1,10 +1,12 @@ package org.testcontainers.dockerclient; -import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.LocalDirectorySSLConfig; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.testcontainers.utility.CommandLine; import org.testcontainers.utility.DockerMachineClient; +import java.net.URI; import java.nio.file.Paths; import java.util.Arrays; import java.util.Optional; @@ -13,15 +15,56 @@ /** * Use Docker machine (if available on the PATH) to locate a Docker environment. + * + * @deprecated this class is used by the SPI and should not be used directly */ @Slf4j -public class DockerMachineClientProviderStrategy extends DockerClientProviderStrategy { - private static final String PING_TIMEOUT_DEFAULT = "30"; - private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.dockermachineprovider.timeout"; +@Deprecated +public final class DockerMachineClientProviderStrategy extends DockerClientProviderStrategy { + + @Getter(lazy = true) + private final TransportConfig transportConfig = resolveTransportConfig(); + + private TransportConfig resolveTransportConfig() throws InvalidConfigurationException { + boolean installed = DockerMachineClient.instance().isInstalled(); + checkArgument(installed, "docker-machine executable was not found on PATH (" + Arrays.toString(CommandLine.getSystemPath()) + ")"); + + Optional machineNameOptional = DockerMachineClient.instance().getDefaultMachine(); + checkArgument(machineNameOptional.isPresent(), "docker-machine is installed but no default machine could be found"); + String machineName = machineNameOptional.get(); + + log.info("Found docker-machine, and will use machine named {}", machineName); + + DockerMachineClient.instance().ensureMachineRunning(machineName); + + String dockerDaemonIpAddress = DockerMachineClient.instance().getDockerDaemonIpAddress(machineName); + + log.info("Docker daemon IP address for docker machine {} is {}", machineName, dockerDaemonIpAddress); + + return TransportConfig.builder() + .dockerHost(URI.create("tcp://" + dockerDaemonIpAddress + ":2376")) + .sslConfig( + new LocalDirectorySSLConfig( + Paths.get(System.getProperty("user.home") + "/.docker/machine/certs/").toString() + ) + ) + .build(); + } @Override protected boolean isApplicable() { - return DockerMachineClient.instance().isInstalled(); + boolean installed = DockerMachineClient.instance().isInstalled(); + if (!installed) { + log.info("docker-machine executable was not found on PATH ({})", Arrays.toString(CommandLine.getSystemPath())); + return false; + } + + Optional machineNameOptional = DockerMachineClient.instance().getDefaultMachine(); + if (!machineNameOptional.isPresent()) { + log.info("docker-machine is installed but no default machine could be found"); + } + + return true; } @Override @@ -34,40 +77,6 @@ protected int getPriority() { return EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 100; } - @Override - public void test() throws InvalidConfigurationException { - - try { - boolean installed = DockerMachineClient.instance().isInstalled(); - checkArgument(installed, "docker-machine executable was not found on PATH (" + Arrays.toString(CommandLine.getSystemPath()) + ")"); - - Optional machineNameOptional = DockerMachineClient.instance().getDefaultMachine(); - checkArgument(machineNameOptional.isPresent(), "docker-machine is installed but no default machine could be found"); - String machineName = machineNameOptional.get(); - - log.info("Found docker-machine, and will use machine named {}", machineName); - - DockerMachineClient.instance().ensureMachineRunning(machineName); - - String dockerDaemonIpAddress = DockerMachineClient.instance().getDockerDaemonIpAddress(machineName); - - log.info("Docker daemon IP address for docker machine {} is {}", machineName, dockerDaemonIpAddress); - - config = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost("tcp://" + dockerDaemonIpAddress + ":2376") - .withDockerTlsVerify(true) - .withDockerCertPath(Paths.get(System.getProperty("user.home") + "/.docker/machine/certs/").toString()) - .build(); - client = getClientForConfig(config); - } catch (Exception e) { - throw new InvalidConfigurationException(e.getMessage()); - } - - // If the docker-machine VM has started, the docker daemon may still not be ready. Retry pinging until it works. - final int timeout = Integer.parseInt(System.getProperty(PING_TIMEOUT_PROPERTY_NAME, PING_TIMEOUT_DEFAULT)); - ping(client, timeout); - } - @Override public String getDescription() { return "docker-machine"; diff --git a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java index 4b02eded72b..c95c9242a07 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java @@ -1,29 +1,28 @@ package org.testcontainers.dockerclient; import com.github.dockerjava.core.DefaultDockerClientConfig; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.SystemUtils; +import com.github.dockerjava.core.DockerClientConfig; /** * Use environment variables and system properties (as supported by the underlying DockerClient DefaultConfigBuilder) * to try and locate a docker environment. + * + * @deprecated this class is used by the SPI and should not be used directly */ -@Slf4j -public class EnvironmentAndSystemPropertyClientProviderStrategy extends DockerClientProviderStrategy { +@Deprecated +public final class EnvironmentAndSystemPropertyClientProviderStrategy extends DockerClientProviderStrategy { public static final int PRIORITY = 100; - private static final String PING_TIMEOUT_DEFAULT = "10"; - private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.environmentprovider.timeout"; - - public EnvironmentAndSystemPropertyClientProviderStrategy() { - // Try using environment variables - config = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); - } + // Try using environment variables + private final DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); @Override - protected boolean isApplicable() { - return "tcp".equalsIgnoreCase(config.getDockerHost().getScheme()) || SystemUtils.IS_OS_LINUX; + public TransportConfig getTransportConfig() { + return TransportConfig.builder() + .dockerHost(dockerClientConfig.getDockerHost()) + .sslConfig(dockerClientConfig.getSSLConfig()) + .build(); } @Override @@ -31,25 +30,8 @@ protected int getPriority() { return PRIORITY; } - @Override - public void test() throws InvalidConfigurationException { - - try { - client = getClientForConfig(config); - - final int timeout = Integer.parseInt(System.getProperty(PING_TIMEOUT_PROPERTY_NAME, PING_TIMEOUT_DEFAULT)); - ping(client, timeout); - } catch (Exception | UnsatisfiedLinkError e) { - log.error("ping failed with configuration {} due to {}", getDescription(), e.toString(), e); - throw new InvalidConfigurationException("ping failed"); - } - - log.info("Found docker client settings from environment"); - } - @Override public String getDescription() { - return "Environment variables, system properties and defaults. Resolved dockerHost=" + - (config != null ? config.getDockerHost() : ""); + return "Environment variables, system properties and defaults. Resolved dockerHost=" + dockerClientConfig.getDockerHost(); } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java b/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java index e0ffce7c3a1..d376b685a91 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java +++ b/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java @@ -1,15 +1,19 @@ package org.testcontainers.dockerclient; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.model.Frame; -import com.github.dockerjava.core.command.LogContainerResultCallback; -public class LogToStringContainerCallback extends LogContainerResultCallback { +/** + * + * @deprecated use {@link ResultCallback.Adapter} + */ +@Deprecated +public class LogToStringContainerCallback extends ResultCallback.Adapter { private final StringBuffer log = new StringBuffer(); @Override public void onNext(Frame frame) { log.append(new String(frame.getPayload())); - super.onNext(frame); } @Override diff --git a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java index 329bde36433..fc3c65fd3dd 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java @@ -1,53 +1,31 @@ package org.testcontainers.dockerclient; -import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.DockerClientConfig; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.SystemUtils; -import org.jetbrains.annotations.NotNull; -@Slf4j -public class NpipeSocketClientProviderStrategy extends DockerClientProviderStrategy { +import java.net.URI; + +/** + * + * @deprecated this class is used by the SPI and should not be used directly + */ +@Deprecated +public final class NpipeSocketClientProviderStrategy extends DockerClientProviderStrategy { protected static final String DOCKER_SOCK_PATH = "//./pipe/docker_engine"; private static final String SOCKET_LOCATION = "npipe://" + DOCKER_SOCK_PATH; - private static final String PING_TIMEOUT_DEFAULT = "10"; - private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.npipesocketprovider.timeout"; - public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 20; @Override - protected boolean isApplicable() { - return SystemUtils.IS_OS_WINDOWS; + public TransportConfig getTransportConfig() { + return TransportConfig.builder() + .dockerHost(URI.create(SOCKET_LOCATION)) + .build(); } @Override - public void test() throws InvalidConfigurationException { - try { - config = tryConfiguration(); - log.info("Accessing docker with {}", getDescription()); - } catch (Exception | UnsatisfiedLinkError e) { - throw new InvalidConfigurationException("ping failed", e); - } - } - - @NotNull - private DockerClientConfig tryConfiguration() { - config = new DelegatingDockerClientConfig( - DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost(SOCKET_LOCATION) - .withDockerTlsVerify(false) - .build() - ); - client = getClientForConfig(config); - - final int timeout = Integer.parseInt(System.getProperty(PING_TIMEOUT_PROPERTY_NAME, PING_TIMEOUT_DEFAULT)); - ping(client, timeout); - - return config; + protected boolean isApplicable() { + return SystemUtils.IS_OS_WINDOWS; } @Override @@ -59,11 +37,4 @@ public String getDescription() { protected int getPriority() { return PRIORITY; } - - @RequiredArgsConstructor - private static class DelegatingDockerClientConfig implements DockerClientConfig { - - @Delegate - final DockerClientConfig dockerClientConfig; - } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java deleted file mode 100644 index b1a21da724c..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/ProxiedUnixSocketClientProviderStrategy.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.testcontainers.dockerclient; - -/** - * @deprecated no longer needed since `docker-java` supports all transport modes now - */ -@Deprecated -public class ProxiedUnixSocketClientProviderStrategy extends UnixSocketClientProviderStrategy { - - public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 100; - - @Override - protected boolean isApplicable() { - return false; - } - - @Override - protected int getPriority() { - return PRIORITY; - } - - @Override - public void test() throws InvalidConfigurationException { - throw new InvalidConfigurationException("Deprecated"); - } - - @Override - public String getDescription() { - return "[Deprecated] local Unix socket (via TCP proxy)"; - } - -} diff --git a/core/src/main/java/org/testcontainers/dockerclient/TransportConfig.java b/core/src/main/java/org/testcontainers/dockerclient/TransportConfig.java new file mode 100644 index 00000000000..cbd1278b179 --- /dev/null +++ b/core/src/main/java/org/testcontainers/dockerclient/TransportConfig.java @@ -0,0 +1,18 @@ +package org.testcontainers.dockerclient; + +import com.github.dockerjava.transport.SSLConfig; +import lombok.Builder; +import lombok.Value; +import org.jetbrains.annotations.Nullable; + +import java.net.URI; + +@Builder +@Value +public class TransportConfig { + + URI dockerHost; + + @Nullable + SSLConfig sslConfig; +} diff --git a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java index ea192f9b557..fd4ef4f9e6e 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java @@ -1,48 +1,27 @@ package org.testcontainers.dockerclient; -import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.DockerClientConfig; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.SystemUtils; -import org.jetbrains.annotations.NotNull; -import org.testcontainers.utility.ComparableVersion; import java.io.IOException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -@Slf4j -public class UnixSocketClientProviderStrategy extends DockerClientProviderStrategy { +/** + * + * @deprecated this class is used by the SPI and should not be used directly + */ +@Deprecated +public final class UnixSocketClientProviderStrategy extends DockerClientProviderStrategy { protected static final String DOCKER_SOCK_PATH = "/var/run/docker.sock"; private static final String SOCKET_LOCATION = "unix://" + DOCKER_SOCK_PATH; private static final int SOCKET_FILE_MODE_MASK = 0xc000; - private static final String PING_TIMEOUT_DEFAULT = "10"; - private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.unixsocketprovider.timeout"; public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 20; @Override - protected boolean isApplicable() { - final boolean nettyDoesSupportMacUnixSockets = SystemUtils.IS_OS_MAC_OSX && - ComparableVersion.OS_VERSION.isGreaterThanOrEqualTo("10.12"); - - return SystemUtils.IS_OS_LINUX || nettyDoesSupportMacUnixSockets; - } - - @Override - public void test() throws InvalidConfigurationException { - try { - config = tryConfiguration(SOCKET_LOCATION); - log.info("Accessing docker with local Unix socket"); - } catch (Exception | UnsatisfiedLinkError e) { - throw new InvalidConfigurationException("ping failed", e); - } - } - - @NotNull - protected DockerClientConfig tryConfiguration(String dockerHost) { - + public TransportConfig getTransportConfig() throws InvalidConfigurationException { Path dockerSocketFile = Paths.get(DOCKER_SOCK_PATH); Integer mode; try { @@ -55,16 +34,14 @@ protected DockerClientConfig tryConfiguration(String dockerHost) { throw new InvalidConfigurationException("Found docker unix domain socket but file mode was not as expected (expected: srwxr-xr-x). This problem is possibly due to occurrence of this issue in the past: https://github.com/docker/docker/issues/13121"); } - config = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost(dockerHost) - .withDockerTlsVerify(false) - .build(); - client = getClientForConfig(config); - - final int timeout = Integer.parseInt(System.getProperty(PING_TIMEOUT_PROPERTY_NAME, PING_TIMEOUT_DEFAULT)); - ping(client, timeout); + return TransportConfig.builder() + .dockerHost(URI.create(SOCKET_LOCATION)) + .build(); + } - return config; + @Override + protected boolean isApplicable() { + return SystemUtils.IS_OS_LINUX; } @Override diff --git a/core/src/main/java/org/testcontainers/dockerclient/WindowsClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/WindowsClientProviderStrategy.java deleted file mode 100644 index f53ac10d044..00000000000 --- a/core/src/main/java/org/testcontainers/dockerclient/WindowsClientProviderStrategy.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.testcontainers.dockerclient; - -import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.DockerClientConfig; -import org.apache.commons.lang.SystemUtils; -import org.jetbrains.annotations.NotNull; - -public class WindowsClientProviderStrategy extends DockerClientProviderStrategy { - - private static final int PING_TIMEOUT_DEFAULT = 5; - private static final String PING_TIMEOUT_PROPERTY_NAME = "testcontainers.windowsprovider.timeout"; - - @Override - protected boolean isApplicable() { - return SystemUtils.IS_OS_WINDOWS; - } - - @Override - public void test() throws InvalidConfigurationException { - config = tryConfiguration("tcp://localhost:2375"); - } - - @Override - public String getDescription() { - return "Docker for Windows (via TCP port 2375)"; - } - - @NotNull - protected DockerClientConfig tryConfiguration(String dockerHost) { - config = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost(dockerHost) - .withDockerTlsVerify(false) - .build(); - client = getClientForConfig(config); - - final int timeout = Integer.getInteger(PING_TIMEOUT_PROPERTY_NAME, PING_TIMEOUT_DEFAULT); - ping(client, timeout); - - return config; - } -} diff --git a/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java b/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java index 71b797298aa..2ba8ba6df11 100644 --- a/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java +++ b/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java @@ -1,7 +1,7 @@ package org.testcontainers.images; +import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.model.PullResponseItem; -import com.github.dockerjava.core.command.PullImageResultCallback; import org.slf4j.Logger; import java.io.Closeable; diff --git a/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java index 274eedefded..b6d8539c3e8 100644 --- a/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java +++ b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java @@ -1,7 +1,7 @@ package org.testcontainers.images; +import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.model.PullResponseItem; -import com.github.dockerjava.core.command.PullImageResultCallback; import org.slf4j.Logger; import org.testcontainers.utility.TestcontainersConfiguration; diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 638db2e351d..133b6e1c4b0 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -2,8 +2,8 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.BuildImageCmd; +import com.github.dockerjava.api.command.BuildImageResultCallback; import com.github.dockerjava.api.model.BuildResponseItem; -import com.github.dockerjava.core.command.BuildImageResultCallback; import lombok.Cleanup; import lombok.Getter; import lombok.extern.slf4j.Slf4j; diff --git a/core/src/main/resources/META-INF/services/README.md b/core/src/main/resources/META-INF/services/README.md deleted file mode 100644 index fd11f50456e..00000000000 --- a/core/src/main/resources/META-INF/services/README.md +++ /dev/null @@ -1 +0,0 @@ -The contents of this folder is a workaround for issues described here: https://github.com/KostyaSha/docker-java-shade/issues/1 \ No newline at end of file diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy index cde7fc827e4..006c3ec7f82 100644 --- a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy +++ b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy @@ -1,5 +1,4 @@ org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy org.testcontainers.dockerclient.UnixSocketClientProviderStrategy org.testcontainers.dockerclient.DockerMachineClientProviderStrategy -org.testcontainers.dockerclient.WindowsClientProviderStrategy org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.JsonFactory b/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.JsonFactory deleted file mode 100755 index 239a78a0a82..00000000000 --- a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.JsonFactory +++ /dev/null @@ -1 +0,0 @@ -com.fasterxml.jackson.core.JsonFactory diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.ObjectCodec b/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.ObjectCodec deleted file mode 100755 index f126bb401c2..00000000000 --- a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.fasterxml.jackson.core.ObjectCodec +++ /dev/null @@ -1 +0,0 @@ -com.fasterxml.jackson.databind.ObjectMapper diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.github.dockerjava.api.command.DockerCmdExecFactory b/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.github.dockerjava.api.command.DockerCmdExecFactory deleted file mode 100644 index f0686bc9f31..00000000000 --- a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.com.github.dockerjava.api.command.DockerCmdExecFactory +++ /dev/null @@ -1 +0,0 @@ -com.github.dockerjava.jaxrs.DockerCmdExecFactoryImpl \ No newline at end of file diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.javax.ws.rs.ext.RuntimeDelegate b/core/src/main/resources/META-INF/services/org.testcontainers.shaded.javax.ws.rs.ext.RuntimeDelegate deleted file mode 100644 index 550198cfdf7..00000000000 --- a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.javax.ws.rs.ext.RuntimeDelegate +++ /dev/null @@ -1 +0,0 @@ -org.glassfish.jersey.internal.RuntimeDelegateImpl \ No newline at end of file diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.glassfish.hk2.extension.ServiceLocatorGenerator b/core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.glassfish.hk2.extension.ServiceLocatorGenerator deleted file mode 100644 index 7834b52dd6d..00000000000 --- a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.glassfish.hk2.extension.ServiceLocatorGenerator +++ /dev/null @@ -1 +0,0 @@ -org.jvnet.hk2.external.generator.ServiceLocatorGeneratorImpl diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.jvnet.hk2.external.generator.ServiceLocatorGenerator b/core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.jvnet.hk2.external.generator.ServiceLocatorGenerator deleted file mode 100644 index 25f6b0c3fc9..00000000000 --- a/core/src/main/resources/META-INF/services/org.testcontainers.shaded.org.jvnet.hk2.external.generator.ServiceLocatorGenerator +++ /dev/null @@ -1 +0,0 @@ -org.testcontainers.shaded.org.jvnet.hk2.external.generator.ServiceLocatorGeneratorImpl From 8e57ae60565f24c01ec7ef964dc37130a022eba4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 11 Jul 2020 20:14:44 +0200 Subject: [PATCH 0860/4969] Use `EnvAndSysPropClientProviderStrategy` only if `DOCKER_HOST` is set (#2987) --- .../EnvironmentAndSystemPropertyClientProviderStrategy.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java index c95c9242a07..e0afba9af93 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java @@ -17,6 +17,11 @@ public final class EnvironmentAndSystemPropertyClientProviderStrategy extends Do // Try using environment variables private final DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); + @Override + protected boolean isApplicable() { + return System.getenv("DOCKER_HOST") != null; + } + @Override public TransportConfig getTransportConfig() { return TransportConfig.builder() From 74a9240473ef2404ff9b8bd76f53f33607401cae Mon Sep 17 00:00:00 2001 From: Simon Schneider <10846939+raynigon@users.noreply.github.com> Date: Sun, 12 Jul 2020 13:58:10 +0200 Subject: [PATCH 0861/4969] Convert Docs for the Junit5 (#2977) Co-authored-by: Richard North --- docs/test_framework_integration/junit_5.md | 75 +++---------------- .../junit/jupiter/MixedLifecycleTests.java | 38 ++++++++++ ...ntainersNestedRestartedContainerTests.java | 13 +++- 3 files changed, 59 insertions(+), 67 deletions(-) create mode 100644 modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java diff --git a/docs/test_framework_integration/junit_5.md b/docs/test_framework_integration/junit_5.md index 11798484b0f..7f3689c0301 100644 --- a/docs/test_framework_integration/junit_5.md +++ b/docs/test_framework_integration/junit_5.md @@ -23,28 +23,9 @@ executed. Containers declared as instance fields will be started and stopped for unsupported and may have unintended side effects. *Example:* -```java -@Testcontainers -class MyTestcontainersTests { - - // will be shared between test methods - @Container - private static final MySQLContainer MY_SQL_CONTAINER = new MySQLContainer(); - - // will be started before and stopped after each test method - @Container - private PostgreSQLContainer postgresqlContainer = new PostgreSQLContainer() - .withDatabaseName("foo") - .withUsername("foo") - .withPassword("secret"); - @Test - void test() { - assertTrue(MY_SQL_CONTAINER.isRunning()); - assertTrue(postgresqlContainer.isRunning()); - } -} -``` - + +[Mixed Lifecycle](../../modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java) inside_block:testClass + ## Examples @@ -55,36 +36,10 @@ To use the Testcontainers extension annotate your test class with `@Testcontaine To define a restarted container, define an instance field inside your test class and annotate it with the `@Container` annotation. -```java -@Testcontainers -class SomeTest { - - @Container - private MySQLContainer mySQLContainer = new MySQLContainer(); - - @Test - void someTestMethod() { - String url = mySQLContainer.getJdbcUrl(); - - // create a connection and run test as normal - } - - @Nested - class NestedTests { + +[Restarted Containers](../../modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java) inside_block:testClass + - @Container - private final PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(); - - void nestedTestMethod() { - // top level container is restarted for nested methods - String mySqlUrl = mySQLContainer.getJdbcUrl(); - - // nested containers are only available inside their nested class - String postgresUrl = postgreSQLContainer.getJdbcUrl(); - } - } -} -``` ### Shared containers @@ -92,21 +47,9 @@ Shared containers are defined as static fields in a top level test class and hav Note that shared containers can't be declared inside nested test classes. This is because nested test classes have to be defined non-static and can't therefore have static fields. -```java -@Testcontainers -class SomeTest { - - @Container - private static final MySQLContainer MY_SQL_CONTAINER = new MySQLContainer(); - - @Test - void someTestMethod() { - String url = MY_SQL_CONTAINER.getJdbcUrl(); - - // create a connection and run test as normal - } -} -``` + +[Shared Container](../../modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java) lines:18-23,32-33,35-36 + ## Singleton containers diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java new file mode 100644 index 00000000000..791c887cc19 --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java @@ -0,0 +1,38 @@ +package org.testcontainers.junit.jupiter; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.containers.wait.strategy.Wait; + +import static org.junit.jupiter.api.Assertions.assertTrue; + + +// testClass { +@Testcontainers +class MixedLifecycleTests { + + // will be shared between test methods + @Container + private static final MySQLContainer MY_SQL_CONTAINER = new MySQLContainer(); + + // will be started before and stopped after each test method + @Container + private PostgreSQLContainer postgresqlContainer = new PostgreSQLContainer() + .withDatabaseName("foo") + .withUsername("foo") + .withPassword("secret"); + + @Test + void test() { + assertTrue(MY_SQL_CONTAINER.isRunning()); + assertTrue(postgresqlContainer.isRunning()); + } +} +// } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java index 4d27c410979..fb753744425 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java @@ -8,21 +8,26 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +// testClass { @Testcontainers class TestcontainersNestedRestartedContainerTests { @Container private final GenericContainer topLevelContainer = new GenericContainer("httpd:2.4-alpine") .withExposedPorts(80); + // }} private static String topLevelContainerId; private static String nestedContainerId; + // testClass { @Test void top_level_container_should_be_running() { assertTrue(topLevelContainer.isRunning()); +// }} topLevelContainerId = topLevelContainer.getContainerId(); +// testClass {{ } @Nested @@ -34,16 +39,20 @@ class NestedTestCase { @Test void both_containers_should_be_running() { + // top level container is restarted for nested methods assertTrue(topLevelContainer.isRunning()); + // nested containers are only available inside their nested class assertTrue(nestedContainer.isRunning()); - +// }}} if (nestedContainerId == null) { nestedContainerId = nestedContainer.getContainerId(); } else { assertNotEquals(nestedContainerId, nestedContainer.getContainerId()); } +// testClass {{ } + // } @Test void containers_should_not_be_the_same() { assertNotEquals(topLevelContainer.getContainerId(), nestedContainer.getContainerId()); @@ -65,5 +74,7 @@ void ids_should_not_change() { assertNotEquals(nestedContainerId, nestedContainer.getContainerId()); } } +// testClass {{{ } } +// } From c137996b2932b223d22cdd81215e96b098a28255 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 12 Jul 2020 18:22:54 +0200 Subject: [PATCH 0862/4969] Allow overriding detected host (#2991) --- .../dockerclient/DockerClientProviderStrategy.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 3f288d015d0..e21c75a581d 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -255,6 +255,11 @@ public synchronized String getDockerHostIpAddress() { @VisibleForTesting static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost) { + String hostOverride = System.getenv("TESTCONTAINERS_HOST_OVERRIDE"); + if (!StringUtils.isBlank(hostOverride)) { + return hostOverride; + } + switch (dockerHost.getScheme()) { case "http": case "https": From 50c778fa39c8adab5b0ee078ee47b074482112ac Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 15 Jul 2020 14:14:07 +0200 Subject: [PATCH 0863/4969] Add a rootless Docker strategy (#2985) Closes #2943, #1770 --- .github/workflows/ci-rootless.yml | 31 ++++++++++ .github/workflows/ci.yml | 2 +- .../testcontainers/DockerClientFactory.java | 15 +++++ .../containers/DockerComposeContainer.java | 24 ++++---- .../RootlessDockerClientProviderStrategy.java | 58 +++++++++++++++++++ .../UnixSocketClientProviderStrategy.java | 2 +- .../utility/ResourceReaper.java | 2 +- ....dockerclient.DockerClientProviderStrategy | 1 + .../DockerComposeOverridesTest.java | 13 ++++- .../containers/GenericContainerTest.java | 6 ++ .../DockerClientConfigUtilsTest.java | 5 ++ .../auth-config/docker-credential-fake | 12 ++-- docs/features/configuration.md | 17 ++++++ 13 files changed, 167 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/ci-rootless.yml create mode 100644 core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java rename core/src/test/java/org/testcontainers/{junit => containers}/DockerComposeOverridesTest.java (90%) diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml new file mode 100644 index 00000000000..e752747b804 --- /dev/null +++ b/.github/workflows/ci-rootless.yml @@ -0,0 +1,31 @@ +name: CI-Docker-Rootless + +on: + pull_request: {} + push: { branches: [ master ] } + +jobs: + test: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: debug + run: id -u; whoami + - name: uninstall rootful Docker + run: sudo apt-get -q -y --purge remove moby-engine moby-buildx && sudo rm -rf /var/run/docker.sock + - name: install rootless Docker + run: curl -fsSL https://get.docker.com/rootless | sh + - name: start rootless Docker + run: PATH=$HOME/bin:$PATH XDG_RUNTIME_DIR=/tmp/docker-$(id -u) dockerd-rootless.sh --experimental --storage-driver vfs & + - name: Build with Gradle + run: XDG_RUNTIME_DIR=/tmp/docker-$(id -u) ./gradlew --no-daemon --scan testcontainers:test + - name: aggregate test reports with ciMate + if: always() + continue-on-error: true + env: + CIMATE_PROJECT_ID: 2348n4vl + CIMATE_CI_KEY: "CI / rootless Docker" + run: | + wget -q https://get.cimate.io/release/linux/cimate + chmod +x cimate + ./cimate "**/TEST-*.xml" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b965eb77dc9..668dde2b28c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: run: docker image prune -af - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | - ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} + ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} - name: Aggregate test reports with ciMate if: always() continue-on-error: true diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index baebe164c48..b9c4d508f25 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -18,6 +18,7 @@ import lombok.SneakyThrows; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; @@ -29,6 +30,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -129,6 +131,19 @@ private DockerClientProviderStrategy getOrInitializeStrategy() { return strategy; } + @UnstableAPI + public String getDockerUnixSocketPath() { + String dockerSocketOverride = System.getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); + if (!StringUtils.isBlank(dockerSocketOverride)) { + return dockerSocketOverride; + } + + URI dockerHost = getOrInitializeStrategy().getTransportConfig().getDockerHost(); + return "unix".equals(dockerHost.getScheme()) + ? dockerHost.getRawPath() + : "/var/run/docker.sock"; + } + /** * * @return a new initialized Docker client diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index c3fe9ab17f9..8c07c036d11 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -59,7 +59,6 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -import static org.testcontainers.containers.BindMode.READ_ONLY; import static org.testcontainers.containers.BindMode.READ_WRITE; /** @@ -580,7 +579,6 @@ interface DockerCompose { */ class ContainerisedDockerCompose extends GenericContainer implements DockerCompose { - private static final String DOCKER_SOCKET_PATH = "/var/run/docker.sock"; public static final char UNIX_PATH_SEPERATOR = ':'; public ContainerisedDockerCompose(List composeFiles, String identifier) { @@ -601,24 +599,18 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { final String composeFileEnvVariableValue = Joiner.on(UNIX_PATH_SEPERATOR).join(absoluteDockerComposeFiles); // we always need the UNIX path separator logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); addEnv(ENV_COMPOSE_FILE, composeFileEnvVariableValue); - addFileSystemBind(pwd, containerPwd, READ_ONLY); + addFileSystemBind(pwd, containerPwd, READ_WRITE); // Ensure that compose can access docker. Since the container is assumed to be running on the same machine // as the docker daemon, just mapping the docker control socket is OK. // As there seems to be a problem with mapping to the /var/run directory in certain environments (e.g. CircleCI) // we map the socket file outside of /var/run, as just /docker.sock - addFileSystemBind(getDockerSocketHostPath(), "/docker.sock", READ_WRITE); + addFileSystemBind("/" + DockerClientFactory.instance().getDockerUnixSocketPath(), "/docker.sock", READ_WRITE); addEnv("DOCKER_HOST", "unix:///docker.sock"); setStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy()); setWorkingDirectory(containerPwd); } - private String getDockerSocketHostPath() { - return SystemUtils.IS_OS_WINDOWS - ? "/" + DOCKER_SOCKET_PATH - : DOCKER_SOCKET_PATH; - } - @Override public void invoke() { super.start(); @@ -681,16 +673,26 @@ public DockerCompose withEnv(Map env) { return this; } + @VisibleForTesting + static boolean executableExists() { + return CommandLine.executableExists(COMPOSE_EXECUTABLE); + } + @Override public void invoke() { // bail out early - if (!CommandLine.executableExists(COMPOSE_EXECUTABLE)) { + if (!executableExists()) { throw new ContainerLaunchException("Local Docker Compose not found. Is " + COMPOSE_EXECUTABLE + " on the PATH?"); } final Map environment = Maps.newHashMap(env); environment.put(ENV_PROJECT_NAME, identifier); + String dockerHost = System.getenv("DOCKER_HOST"); + if (dockerHost == null) { + dockerHost = "unix://" + DockerClientFactory.instance().getDockerUnixSocketPath(); + } + environment.put("DOCKER_HOST", dockerHost); final Stream absoluteDockerComposeFilePaths = composeFiles.stream() .map(File::getAbsolutePath) diff --git a/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java new file mode 100644 index 00000000000..cc6b23e506d --- /dev/null +++ b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java @@ -0,0 +1,58 @@ +package org.testcontainers.dockerclient; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import org.apache.commons.lang.SystemUtils; + +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * + * @deprecated this class is used by the SPI and should not be used directly + */ +@Deprecated +public final class RootlessDockerClientProviderStrategy extends DockerClientProviderStrategy { + + public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY + 1; + + private Path getSocketPath() { + String xdgRuntimeDir = System.getenv("XDG_RUNTIME_DIR"); + if (xdgRuntimeDir == null) { + xdgRuntimeDir = "/run/user/" + LibC.INSTANCE.getuid(); + } + return Paths.get(xdgRuntimeDir).resolve("docker.sock"); + } + + @Override + public TransportConfig getTransportConfig() throws InvalidConfigurationException { + return TransportConfig.builder() + .dockerHost(URI.create("unix://" + getSocketPath().toString())) + .build(); + } + + @Override + protected boolean isApplicable() { + return SystemUtils.IS_OS_LINUX && Files.exists(getSocketPath()); + } + + @Override + public String getDescription() { + return "Rootless Docker accessed via Unix socket (" + getSocketPath() + ")"; + } + + @Override + protected int getPriority() { + return PRIORITY; + } + + private interface LibC extends Library { + + LibC INSTANCE = Native.loadLibrary("c", LibC.class); + + int getuid(); + } + +} diff --git a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java index fd4ef4f9e6e..6f030ada279 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java @@ -41,7 +41,7 @@ public TransportConfig getTransportConfig() throws InvalidConfigurationException @Override protected boolean isApplicable() { - return SystemUtils.IS_OS_LINUX; + return SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC; } @Override diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 5d89ab886e7..e9c0f68a82b 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -76,7 +76,7 @@ public static String start(String hostIpAddress, DockerClient client) { DockerClientFactory.instance().checkAndPullImage(client, ryukImage); List binds = new ArrayList<>(); - binds.add(new Bind("//var/run/docker.sock", new Volume("/var/run/docker.sock"))); + binds.add(new Bind("/" + DockerClientFactory.instance().getDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); String ryukContainerId = client.createContainerCmd(ryukImage) .withHostConfig(new HostConfig().withAutoRemove(true)) diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy index 006c3ec7f82..d9cbad0ebff 100644 --- a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy +++ b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy @@ -2,3 +2,4 @@ org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrate org.testcontainers.dockerclient.UnixSocketClientProviderStrategy org.testcontainers.dockerclient.DockerMachineClientProviderStrategy org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy +org.testcontainers.dockerclient.RootlessDockerClientProviderStrategy diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeOverridesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java similarity index 90% rename from core/src/test/java/org/testcontainers/junit/DockerComposeOverridesTest.java rename to core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java index 6413694d1c5..9e9eb27b509 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeOverridesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java @@ -1,6 +1,8 @@ -package org.testcontainers.junit; +package org.testcontainers.containers; import com.google.common.util.concurrent.Uninterruptibles; +import org.assertj.core.api.Assumptions; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -48,6 +50,15 @@ public static Iterable data() { }); } + @Before + public void setUp() { + if (localMode) { + Assumptions.assumeThat(LocalDockerCompose.executableExists()) + .as("docker-compose executable exists") + .isTrue(); + } + } + @Test public void test() { try (DockerComposeContainer compose = diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 78a7a3b1bef..134bdf18f30 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -2,13 +2,16 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse.ContainerState; +import com.github.dockerjava.api.model.Info; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; +import org.assertj.core.api.Assumptions; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; @@ -21,6 +24,9 @@ public class GenericContainerTest { @Test public void shouldReportOOMAfterWait() { + Info info = DockerClientFactory.instance().client().infoCmd().exec(); + // Poor man's rootless Docker detection :D + Assumptions.assumeThat(info.getDriver()).doesNotContain("vfs"); try ( GenericContainer container = new GenericContainer<>() .withStartupCheckStrategy(new NoopStartupCheckStrategy()) diff --git a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java index 353d6ea94e7..442c2efd950 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java @@ -1,6 +1,7 @@ package org.testcontainers.dockerclient; import com.github.dockerjava.api.DockerClient; +import org.assertj.core.api.Assumptions; import org.junit.Test; import org.testcontainers.DockerClientFactory; @@ -16,6 +17,10 @@ public class DockerClientConfigUtilsTest { @Test public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() { + Assumptions.assumeThat(DockerClientConfigUtils.IN_A_CONTAINER) + .as("in a container") + .isFalse(); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("unix:///var/run/docker.sock")); assertEquals("localhost", actual); } diff --git a/core/src/test/resources/auth-config/docker-credential-fake b/core/src/test/resources/auth-config/docker-credential-fake index 880009f2c2a..753e62ca347 100755 --- a/core/src/test/resources/auth-config/docker-credential-fake +++ b/core/src/test/resources/auth-config/docker-credential-fake @@ -1,21 +1,21 @@ -#!/bin/bash +#!/bin/sh -if [[ $1 != "get" ]]; then +if [ $1 != "get" ]; then exit 1 fi read inputLine -if [[ $inputLine == "registry2.example.com" ]]; then +if [ "$inputLine" = "registry2.example.com" ]; then echo Fake credentials not found on credentials store \'$inputLine\' 1>&2 exit 1 fi -if [[ $inputLine == "https://not.a.real.registry/url" ]]; then +if [ "$inputLine" = "https://not.a.real.registry/url" ]; then echo Fake credentials not found on credentials store \'$inputLine\' 1>&2 exit 1 fi -if [[ $inputLine == "registry.example.com" ]]; then +if [ "$inputLine" = "registry.example.com" ]; then echo '{' \ ' "ServerURL": "url",' \ ' "Username": "username",' \ @@ -23,7 +23,7 @@ if [[ $inputLine == "registry.example.com" ]]; then '}' exit 0 fi -if [[ $inputLine == "registrytoken.example.com" ]]; then +if [ "$inputLine" = "registrytoken.example.com" ]; then echo '{' \ ' "ServerURL": "url",' \ ' "Username": "",' \ diff --git a/docs/features/configuration.md b/docs/features/configuration.md index f0172b3c978..8b12f8e8d54 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -72,3 +72,20 @@ but does not allow starting privileged containers, you can turn off the Ryuk con > **pull.pause.timeout = 30** > By default Testcontainers will abort the pull of an image if the pull appears stalled (no data transferred) for longer than this duration (in seconds). + +## Customizing Docker host detection + +Testcontainers will attempt to detect the Docker environment and configure everything. + +However, sometimes a customization is required. For that, you can provide the following environment variables: + +> **DOCKER_HOST** = unix:///var/run/docker.sock +> See [Docker environment variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables) +> +> **TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE** +> Path to Docker's socket. Used by Ryuk, Docker Compose, and a few other containers that need to perform Docker actions. +> Example: `/var/run/docker-alt.sock` +> +> **TESTCONTAINERS_HOST_OVERRIDE** +> Docker's host on which ports are exposed. +> Example: `docker.svc.local` From cce8a7f7db57278eb81c878c4879a50479917a4d Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 15 Jul 2020 16:48:47 +0200 Subject: [PATCH 0864/4969] Added jOOQ to the who's using section, and me to the backers section (#2996) --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 6c8bf49f08f..7619146c8b5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -119,6 +119,7 @@ testImplementation('org.testcontainers:mysql') //no version specified * [Transferwise](https://transferwise.com/) - Integration testing for different RDBMS, kafka and micro services * [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) * [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) +* [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS ## Sponsors @@ -133,6 +134,7 @@ A huge thank you to our backers: * [Philip Riecks (@rieckpil)](https://github.com/rieckpil) * [Karl Heinz Marbaise (@khmarbaise)](https://github.com/khmarbaise) * [Sascha Frinken (@sascha-frinken)](https://github.com/sascha-frinken) +* [Lukas Eder (@lukaseder)](https://github.com/lukaseder) ## License From f8954ff7c0cdd3e0ff3c13e484cab4f221c6f7ea Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 15 Jul 2020 16:21:18 +0100 Subject: [PATCH 0865/4969] Add fkorotkov to backers (#2997) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 7619146c8b5..94224c3c0db 100644 --- a/docs/index.md +++ b/docs/index.md @@ -135,6 +135,7 @@ A huge thank you to our backers: * [Karl Heinz Marbaise (@khmarbaise)](https://github.com/khmarbaise) * [Sascha Frinken (@sascha-frinken)](https://github.com/sascha-frinken) * [Lukas Eder (@lukaseder)](https://github.com/lukaseder) +* [Fedor Korotkov (@fedor)](https://github.com/fkorotkov) ## License From 977058da8e63a06f08e91aed2afd0c22df59641f Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 15 Jul 2020 16:25:21 +0100 Subject: [PATCH 0866/4969] Add dreis2211 to backers And use github username, not twitter handle, for Fedor --- docs/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 94224c3c0db..4894297f034 100644 --- a/docs/index.md +++ b/docs/index.md @@ -135,7 +135,8 @@ A huge thank you to our backers: * [Karl Heinz Marbaise (@khmarbaise)](https://github.com/khmarbaise) * [Sascha Frinken (@sascha-frinken)](https://github.com/sascha-frinken) * [Lukas Eder (@lukaseder)](https://github.com/lukaseder) -* [Fedor Korotkov (@fedor)](https://github.com/fkorotkov) +* [Fedor Korotkov (@fkorotkov)](https://github.com/fkorotkov) +* [Christoph Dreis (@dreis2211)](https://github.com/dreis2211) ## License From a5c28943992e491c688603982a517c59c7a02d8f Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 16 Jul 2020 11:34:49 +0200 Subject: [PATCH 0867/4969] Fix local Docker Compose (#2998) * Fix local Docker Compose * set `DOCKER_TLS_VERIFY` as well --- .../org/testcontainers/DockerClientFactory.java | 10 ++++++++-- .../containers/DockerComposeContainer.java | 17 +++++++++++++++-- .../testcontainers/utility/ResourceReaper.java | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index b9c4d508f25..f91b075cdb2 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -21,6 +21,7 @@ import org.apache.commons.lang.StringUtils; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; +import org.testcontainers.dockerclient.TransportConfig; import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.MountableFile; @@ -132,13 +133,18 @@ private DockerClientProviderStrategy getOrInitializeStrategy() { } @UnstableAPI - public String getDockerUnixSocketPath() { + public TransportConfig getTransportConfig() { + return getOrInitializeStrategy().getTransportConfig(); + } + + @UnstableAPI + public String getRemoteDockerUnixSocketPath() { String dockerSocketOverride = System.getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); if (!StringUtils.isBlank(dockerSocketOverride)) { return dockerSocketOverride; } - URI dockerHost = getOrInitializeStrategy().getTransportConfig().getDockerHost(); + URI dockerHost = getTransportConfig().getDockerHost(); return "unix".equals(dockerHost.getScheme()) ? dockerHost.getRawPath() : "/var/run/docker.sock"; diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 8c07c036d11..50a58ba8c87 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -2,6 +2,8 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.core.LocalDirectorySSLConfig; +import com.github.dockerjava.transport.SSLConfig; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Splitter; @@ -22,6 +24,7 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.dockerclient.TransportConfig; import org.testcontainers.lifecycle.Startable; import org.testcontainers.utility.AuditLogger; import org.testcontainers.utility.Base58; @@ -605,7 +608,7 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { // as the docker daemon, just mapping the docker control socket is OK. // As there seems to be a problem with mapping to the /var/run directory in certain environments (e.g. CircleCI) // we map the socket file outside of /var/run, as just /docker.sock - addFileSystemBind("/" + DockerClientFactory.instance().getDockerUnixSocketPath(), "/docker.sock", READ_WRITE); + addFileSystemBind("/" + DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), "/docker.sock", READ_WRITE); addEnv("DOCKER_HOST", "unix:///docker.sock"); setStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy()); setWorkingDirectory(containerPwd); @@ -690,7 +693,17 @@ public void invoke() { String dockerHost = System.getenv("DOCKER_HOST"); if (dockerHost == null) { - dockerHost = "unix://" + DockerClientFactory.instance().getDockerUnixSocketPath(); + TransportConfig transportConfig = DockerClientFactory.instance().getTransportConfig(); + SSLConfig sslConfig = transportConfig.getSslConfig(); + if (sslConfig != null) { + if (sslConfig instanceof LocalDirectorySSLConfig) { + environment.put("DOCKER_CERT_PATH", ((LocalDirectorySSLConfig) sslConfig).getDockerCertPath()); + environment.put("DOCKER_TLS_VERIFY", "true"); + } else { + logger().warn("Couldn't set DOCKER_CERT_PATH. `sslConfig` is present but it's not LocalDirectorySSLConfig."); + } + } + dockerHost = transportConfig.getDockerHost().toString(); } environment.put("DOCKER_HOST", dockerHost); diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index e9c0f68a82b..0a0728e9306 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -76,7 +76,7 @@ public static String start(String hostIpAddress, DockerClient client) { DockerClientFactory.instance().checkAndPullImage(client, ryukImage); List binds = new ArrayList<>(); - binds.add(new Bind("/" + DockerClientFactory.instance().getDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); + binds.add(new Bind("/" + DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); String ryukContainerId = client.createContainerCmd(ryukImage) .withHostConfig(new HostConfig().withAutoRemove(true)) From 6e8c18e1a3d9a75c86e86577b684bfdb8ce61160 Mon Sep 17 00:00:00 2001 From: Aaron Whiteside Date: Sun, 19 Jul 2020 20:44:41 +1000 Subject: [PATCH 0868/4969] couchbase: include error response from couchbase in checkSuccessfulResponse() (#3006) Also minor logging cleanup, and prevented an exception from being swallowed. fixes #2799 Co-authored-by: Aaron Whiteside --- .../couchbase/CouchbaseContainer.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index ee4b3212cac..4a95334752a 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -168,7 +168,7 @@ protected void configure() { .map("healthy"::equals) .orElse(false); } catch (IOException e) { - logger().error("Unable to parse response {}", response); + logger().error("Unable to parse response {}", response, e); return false; } }) @@ -337,10 +337,10 @@ private void configureIndexer() { * Based on the user-configured bucket definitions, creating buckets and corresponding indexes if needed. */ private void createBuckets() { - logger().debug("Creating " + buckets.size() + " buckets (and corresponding indexes)."); + logger().debug("Creating {} buckets (and corresponding indexes).", buckets.size()); for (BucketDefinition bucket : buckets) { - logger().debug("Creating bucket \"" + bucket.getName() + "\""); + logger().debug("Creating bucket \"{}\"", bucket.getName()); @Cleanup Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder() .add("name", bucket.getName()) @@ -382,7 +382,7 @@ private void createBuckets() { checkSuccessfulResponse(queryResponse, "Could not create primary index for bucket " + bucket.getName()); } else { - logger().info("Primary index creation for bucket " + bucket.getName() + " ignored, since QUERY service is not present."); + logger().info("Primary index creation for bucket {} ignored, since QUERY service is not present.", bucket.getName()); } } } @@ -406,7 +406,16 @@ private String getInternalIpAddress() { */ private void checkSuccessfulResponse(final Response response, final String message) { if (!response.isSuccessful()) { - throw new IllegalStateException(message + ": " + response.toString()); + String body = null; + if (response.body() != null) { + try { + body = response.body().string(); + } catch (IOException e) { + logger().debug("Unable to read body of response: {}", response, e); + } + } + + throw new IllegalStateException(message + ": " + response.toString() + ", body=" + (body == null ? "" : body)); } } From 3c391bf51db8c80156771e8366e30d5ccb44410c Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Sun, 19 Jul 2020 12:47:21 +0200 Subject: [PATCH 0869/4969] Maintain deterministic order in withCopyFileToContainer (#2897) --- .../java/org/testcontainers/containers/GenericContainer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 417826e83b5..b3dcf469cfc 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -79,6 +79,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -180,7 +181,8 @@ public class GenericContainer> @Nullable private Long shmSize; - private Map copyToFileContainerPathMap = new HashMap<>(); + // Maintain order in which entries are added, as earlier target location may be a prefix of a later location. + private Map copyToFileContainerPathMap = new LinkedHashMap<>(); protected final Set dependencies = new HashSet<>(); From fd823a14f8d791def4b04b10e2f8f47b76c02edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=B6ckling?= Date: Sun, 19 Jul 2020 13:20:55 +0200 Subject: [PATCH 0870/4969] Make WaitStrategy's regex in PrestoContainer work with newer image (#2992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Böckling --- .../java/org/testcontainers/containers/PrestoContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index 56488525734..c3f25c40ac8 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -30,7 +30,7 @@ public PrestoContainer() { public PrestoContainer(final String dockerImageName) { super(dockerImageName); this.waitStrategy = new LogMessageWaitStrategy() - .withRegEx(".*io.prestosql.server.PrestoServer\\s+======== SERVER STARTED ========.*") + .withRegEx(".*======== SERVER STARTED ========.*") .withStartupTimeout(Duration.of(60, SECONDS)); addExposedPort(PRESTO_PORT); From c3f53b3a63e6b0bc800a7f0fbce91ce95a8986b3 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 19 Jul 2020 13:32:40 +0100 Subject: [PATCH 0871/4969] Deprecate ambiguous constructors (#2839) Our constructors for `GenericContainer` and all the classes that inherit from it tend to be a bit inconsistent. In some places, a no-args constructor is favoured, in other places a String parameter is favoured - which can be either a full image name or a tag. This raises confusion, and in the case of an image tag being the parameter, it restricts which images people can easily use. Another problem this raises is when the container class specifies a default tag version: this frequently falls out of date. We're stuck for options: some users (and image maintainers) would like to see newer image versions being used, but this could be a breaking change for existing users. This is especially risky when a major version bump is proposed. This change aims to: - Deprecate 'ambiguous' constructors for containers - any no-args or String-arg constructor gets this treatment. - Introduce a new constructor which accepts a `DockerImageName` object. This class is preferred to a String because its meaning is unambiguous. - Enhance `DockerImageName` with a static factory method and a convenience `withTag` method so that users can easily create and derive new instances. - Update all modules to follow suit --- .../testcontainers/DockerClientFactory.java | 2 +- .../containers/DockerComposeContainer.java | 2 +- .../FixedHostPortGenericContainer.java | 5 + .../containers/GenericContainer.java | 19 +++- .../containers/PortForwardingContainer.java | 4 +- .../containers/SocatContainer.java | 9 +- .../containers/VncRecordingContainer.java | 2 +- .../AuthDelegatingDockerClientConfig.java | 2 +- .../images/AbstractImagePullPolicy.java | 2 +- .../images/LocalImagesCache.java | 2 +- .../images/RemoteDockerImage.java | 16 ++- .../dockerfile/traits/FromStatementTrait.java | 2 +- .../utility/DockerImageName.java | 104 ++++++++++++------ .../utility/DockerMachineClient.java | 1 - .../utility/ResourceReaper.java | 4 +- .../utility/TestcontainersConfiguration.java | 45 ++++++++ .../OutOfPackageImagePullPolicyTest.java | 4 +- .../java/org/testcontainers/DaemonTest.java | 5 +- .../DockerClientFactoryTest.java | 2 +- .../java/org/testcontainers/TestImages.java | 13 +++ .../containers/ExposedHostTest.java | 28 +++-- .../FailureDetectingExternalResourceTest.java | 1 + .../containers/GenericContainerTest.java | 5 +- .../containers/NetworkTest.java | 24 ++-- .../containers/ReusabilityUnitTests.java | 31 +++--- .../containers/output/ContainerLogsTest.java | 19 ++-- .../dockerclient/EventStreamTest.java | 4 +- .../dockerclient/ImagePullTest.java | 5 +- .../images/AgeBasedPullPolicyTest.java | 2 +- .../images/ImagePullPolicyTest.java | 44 ++++---- .../images/RemoteDockerImageTest.java | 11 +- .../images/builder/DockerignoreTest.java | 30 ++--- .../junit/CopyFileToContainerTest.java | 9 +- .../junit/DependenciesTest.java | 10 +- .../junit/DockerNetworkModeTest.java | 7 +- .../junit/FileOperationsTest.java | 11 +- .../junit/FixedHostPortContainerTest.java | 9 +- .../junit/GenericContainerRuleTest.java | 71 ++++++++---- .../junit/NonExistentImagePullTest.java | 3 +- .../junit/OutputStreamTest.java | 7 +- .../junit/OutputStreamWithTTYTest.java | 7 +- .../junit/WorkingDirectoryTest.java | 3 +- .../strategy/AbstractWaitStrategyTest.java | 20 ++-- .../strategy/HostPortWaitStrategyTest.java | 5 +- .../utility/AuthenticatedImagePullTest.java | 9 +- .../utility/DockerImageNameTest.java | 46 ++++++-- .../utility/RegistryAuthLocatorTest.java | 20 ++-- .../test/java/generic/CmdModifierTest.java | 5 +- .../src/test/java/generic/CommandsTest.java | 3 +- .../java/generic/ContainerCreationTest.java | 21 ++-- .../test/java/generic/ContainerLabelTest.java | 5 +- .../src/test/java/generic/ExecTest.java | 3 +- .../generic/MultiplePortsExposedTest.java | 3 +- .../test/java/generic/WaitStrategiesTest.java | 7 +- .../StartupCheckStrategyTest.java | 7 +- .../quickstart/RedisBackedCacheIntTest.java | 3 +- .../quickstart/RedisBackedCacheIntTest.java | 3 +- docs/features/creating_container.md | 16 ++- .../test/java/DisqueBackedMailSenderTest.java | 13 ++- .../test/java/SingleDisqueInstanceTest.java | 8 +- examples/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58910 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + examples/gradlew | 33 +++--- examples/gradlew.bat | 6 +- .../LinkedContainerTestImages.java | 8 ++ .../linkedcontainer/RedmineClientTest.java | 4 +- .../linkedcontainer/RedmineContainer.java | 3 +- .../containers/MongoDbContainer.java | 14 ++- .../containers/MongoDbContainerTest.java | 7 +- .../src/test/java/RedisBackedCacheTest.java | 7 +- .../src/test/java/RedisBackedCacheTest.java | 7 +- .../com/example/AbstractIntegrationTest.java | 3 +- .../test/java/com/example/SolrQueryTest.java | 21 ++-- .../com/example/AbstractIntegrationTest.java | 3 +- .../containers/CassandraContainer.java | 17 ++- .../containers/CassandraContainerTest.java | 29 +++-- .../containers/ClickHouseContainer.java | 14 +++ .../containers/ClickHouseProvider.java | 4 +- .../testcontainers/ClickhouseTestImages.java | 7 ++ .../clickhouse/SimpleClickhouseTest.java | 3 +- .../containers/CockroachContainer.java | 13 +++ .../CockroachContainerProvider.java | 4 +- .../testcontainers/CockroachDBTestImages.java | 7 ++ .../cockroachdb/SimpleCockroachDBTest.java | 7 +- .../couchbase/CouchbaseContainer.java | 19 +++- .../couchbase/CouchbaseContainerTest.java | 5 +- .../containers/Db2Container.java | 17 ++- .../containers/Db2ContainerProvider.java | 4 +- .../org/testcontainers/Db2TestImages.java | 7 ++ .../junit/db2/SimpleDb2Test.java | 5 +- .../dynamodb/DynaliteContainer.java | 18 ++- .../dynamodb/DynaliteContainerTest.java | 13 ++- .../elasticsearch/ElasticsearchContainer.java | 11 ++ .../ElasticsearchContainerTest.java | 47 +++++--- .../containers/InfluxDBContainer.java | 16 ++- .../containers/InfluxDBContainerTest.java | 2 +- .../InfluxDBContainerWithUserTest.java | 4 +- .../containers/InfluxDBTestImages.java | 7 ++ .../containers/JdbcDatabaseContainer.java | 11 +- .../jdbc/MissingJdbcDriverTest.java | 3 +- .../junit/jupiter/JUnitJupiterTestImages.java | 8 ++ .../junit/jupiter/PostgresContainerTests.java | 3 +- ...ntainersNestedRestartedContainerTests.java | 6 +- ...tcontainersNestedSharedContainerTests.java | 3 +- .../TestcontainersRestartBetweenTests.java | 3 +- .../TestcontainersSharedContainerTests.java | 3 +- .../jupiter/inheritance/RedisContainer.java | 7 +- .../containers/KafkaContainer.java | 15 ++- .../containers/KafkaContainerTest.java | 12 +- .../localstack/LocalStackContainer.java | 15 ++- .../localstack/LocalstackContainerTest.java | 15 ++- .../containers/MariaDBContainer.java | 14 +++ .../containers/MariaDBContainerProvider.java | 5 +- .../org/testcontainers/MariaDBTestImages.java | 7 ++ .../MariaDBR2DBCDatabaseContainerTest.java | 3 +- .../junit/mariadb/SimpleMariaDBTest.java | 11 +- .../containers/MockServerContainer.java | 15 ++- .../containers/MockServerContainerTest.java | 7 +- .../containers/MongoDBContainer.java | 13 +++ .../containers/MongoDBContainerTest.java | 4 +- .../containers/MSSQLServerContainer.java | 13 +++ .../MSSQLServerContainerProvider.java | 4 +- .../testcontainers/MSSQLServerTestImages.java | 7 ++ .../MSSQLR2DBCDatabaseContainerTest.java | 3 +- .../CustomPasswordMSSQLServerTest.java | 3 +- .../CustomizableMSSQLServerTest.java | 3 +- .../mssqlserver/SimpleMSSQLServerTest.java | 8 +- .../containers/MySQLContainer.java | 16 ++- .../containers/MySQLContainerProvider.java | 5 +- .../org/testcontainers/MySQLTestImages.java | 9 ++ .../MySQLR2DBCDatabaseContainerTest.java | 3 +- .../junit/mysql/CustomizableMysqlTest.java | 3 +- .../junit/mysql/MultiVersionMySQLTest.java | 7 +- .../junit/mysql/SimpleMySQLTest.java | 31 +++--- .../containers/Neo4jContainer.java | 33 ++++-- .../Neo4jContainerJUnitIntegrationTest.java | 11 +- .../containers/Neo4jContainerTest.java | 33 +++--- .../containers/Neo4jTestImages.java | 7 ++ .../containers/NginxContainer.java | 15 ++- .../testcontainers/junit/SimpleNginxTest.java | 5 +- .../containers/OracleContainer.java | 13 +++ .../containers/OrientDBContainer.java | 13 +++ .../containers/OrientDBContainerTest.java | 11 +- .../containers/PostgisContainerProvider.java | 5 +- .../containers/PostgreSQLContainer.java | 13 +++ .../PostgreSQLContainerProvider.java | 5 +- .../testcontainers/PostgreSQLTestImages.java | 7 ++ .../PostgreSQLConnectionURLTest.java | 7 ++ .../PostgreSQLR2DBCDatabaseContainerTest.java | 3 +- .../CustomizablePostgreSQLTest.java | 3 +- .../postgresql/SimplePostgreSQLTest.java | 11 +- .../containers/PrestoContainer.java | 13 +++ .../containers/PrestoContainerProvider.java | 5 +- .../org/testcontainers/PrestoTestImages.java | 8 ++ .../containers/PrestoContainerTest.java | 14 ++- .../containers/PulsarContainer.java | 20 +++- .../containers/PulsarContainerTest.java | 4 +- .../containers/RabbitMQContainer.java | 15 ++- ...RabbitMQContainerJUnitIntegrationTest.java | 2 +- .../containers/RabbitMQContainerTest.java | 51 ++++----- .../containers/RabbitMQTestImages.java | 7 ++ .../containers/BrowserWebDriverContainer.java | 34 ++++-- .../testcontainers/SeleniumTestImages.java | 7 ++ .../junit/LinkedContainerTest.java | 12 +- .../testcontainers/junit/Selenium3xTest.java | 4 +- ...ecificImageNameWebDriverContainerTest.java | 8 +- .../containers/SolrContainer.java | 25 +++-- .../containers/SolrContainerTest.java | 20 ++-- .../spock/MySqlContainerIT.groovy | 2 +- .../spock/PostgresContainerIT.groovy | 2 +- .../spock/SpockTestImages.groovy | 11 ++ .../spock/TestHierarchyIT.groovy | 2 +- .../TestLifecycleAwareContainerMock.java | 6 + ...TestcontainersRestartBetweenTestsIT.groovy | 2 +- .../TestcontainersSharedContainerIT.groovy | 2 +- .../containers/ToxiproxyContainer.java | 17 ++- .../containers/ToxiproxyTest.java | 15 ++- .../testcontainers/vault/VaultContainer.java | 13 +++ .../testcontainers/vault/VaultClientTest.java | 3 +- .../vault/VaultContainerTest.java | 2 +- .../testcontainers/vault/VaultTestImages.java | 7 ++ 181 files changed, 1445 insertions(+), 565 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/TestImages.java create mode 100644 examples/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/gradle/wrapper/gradle-wrapper.properties create mode 100644 examples/linked-container/src/test/java/com/example/linkedcontainer/LinkedContainerTestImages.java create mode 100644 modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java create mode 100644 modules/cockroachdb/src/test/java/org/testcontainers/CockroachDBTestImages.java create mode 100644 modules/db2/src/test/java/org/testcontainers/Db2TestImages.java create mode 100644 modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBTestImages.java create mode 100644 modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/JUnitJupiterTestImages.java create mode 100644 modules/mariadb/src/test/java/org/testcontainers/MariaDBTestImages.java create mode 100644 modules/mssqlserver/src/test/java/org/testcontainers/MSSQLServerTestImages.java create mode 100644 modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java create mode 100644 modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java create mode 100644 modules/postgresql/src/test/java/org/testcontainers/PostgreSQLTestImages.java create mode 100644 modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java create mode 100644 modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQTestImages.java create mode 100644 modules/selenium/src/test/java/org/testcontainers/SeleniumTestImages.java create mode 100644 modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy create mode 100644 modules/vault/src/test/java/org/testcontainers/vault/VaultTestImages.java diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index f91b075cdb2..1905fc7c098 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -60,7 +60,7 @@ public class DockerClientFactory { TESTCONTAINERS_SESSION_ID_LABEL, SESSION_ID ); - private static final String TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyImage(); + private static final String TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyDockerImageName().asCanonicalNameString(); private static DockerClientFactory instance; // Cached client configuration diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 50a58ba8c87..af1da29442f 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -586,7 +586,7 @@ class ContainerisedDockerCompose extends GenericContainer composeFiles, String identifier) { - super(TestcontainersConfiguration.getInstance().getDockerComposeContainerImage()); + super(TestcontainersConfiguration.getInstance().getDockerComposeDockerImageName()); addEnv(ENV_PROJECT_NAME, identifier); // Map the docker compose file into the container diff --git a/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java b/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java index 33c1c8e89bd..6477c28042e 100644 --- a/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java @@ -12,6 +12,11 @@ * not available - which could manifest as flaky or unstable tests.

*/ public class FixedHostPortGenericContainer> extends GenericContainer { + + /** + * @deprecated it is highly recommended that {@link FixedHostPortGenericContainer} not be used, as it risks port conflicts. + */ + @Deprecated public FixedHostPortGenericContainer(@NotNull String dockerImageName) { super(dockerImageName); } diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index b3dcf469cfc..22a6c2408d6 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -12,7 +12,6 @@ import com.github.dockerjava.api.model.ContainerNetwork; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.HostConfig; -import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Link; import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Volume; @@ -55,6 +54,7 @@ import org.testcontainers.lifecycle.TestDescription; import org.testcontainers.lifecycle.TestLifecycleAware; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.DockerMachineClient; import org.testcontainers.utility.MountableFile; @@ -227,10 +227,27 @@ public class GenericContainer> @Setter(AccessLevel.NONE) private boolean shouldBeReused = false; + + public GenericContainer(@NonNull final DockerImageName dockerImageName) { + this.image = new RemoteDockerImage(dockerImageName); + } + + public GenericContainer(@NonNull final RemoteDockerImage image) { + this.image = image; + } + + /** + * @deprecated use {@link GenericContainer(DockerImageName)} instead + */ + @Deprecated public GenericContainer() { this(TestcontainersConfiguration.getInstance().getTinyImage()); } + /** + * @deprecated use {@link GenericContainer(DockerImageName)} instead + */ + @Deprecated public GenericContainer(@NonNull final String dockerImageName) { this.setDockerImageName(dockerImageName); } diff --git a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java index 09f1d98bd2d..e42f2681675 100644 --- a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java @@ -19,7 +19,7 @@ public enum PortForwardingContainer { INSTANCE; - private GenericContainer container; + private GenericContainer container; private final Set> exposedPorts = Collections.newSetFromMap(new ConcurrentHashMap<>()); @@ -29,7 +29,7 @@ public enum PortForwardingContainer { @SneakyThrows private Connection createSSHSession() { String password = UUID.randomUUID().toString(); - container = new GenericContainer<>(TestcontainersConfiguration.getInstance().getSSHdImage()) + container = new GenericContainer<>(TestcontainersConfiguration.getInstance().getSSHdDockerImageName()) .withExposedPorts(22) .withEnv("PASSWORD", password) .withCommand( diff --git a/core/src/main/java/org/testcontainers/containers/SocatContainer.java b/core/src/main/java/org/testcontainers/containers/SocatContainer.java index 5949a14490d..fbca73eb29d 100644 --- a/core/src/main/java/org/testcontainers/containers/SocatContainer.java +++ b/core/src/main/java/org/testcontainers/containers/SocatContainer.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.TestcontainersConfiguration; import java.util.HashMap; @@ -16,7 +17,11 @@ public class SocatContainer extends GenericContainer { private final Map targets = new HashMap<>(); public SocatContainer() { - super(TestcontainersConfiguration.getInstance().getSocatContainerImage()); + this(TestcontainersConfiguration.getInstance().getSocatDockerImageName()); + } + + public SocatContainer(final DockerImageName dockerImageName) { + super(dockerImageName); withCreateContainerCmdModifier(it -> it.withEntrypoint("/bin/sh")); withCreateContainerCmdModifier(it -> it.withName("testcontainers-socat-" + Base58.randomString(8))); } @@ -39,4 +44,4 @@ protected void configure() { .collect(Collectors.joining(" & ")) ); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index fd48dd01f92..8ac060c2af6 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -52,7 +52,7 @@ public VncRecordingContainer(@NonNull GenericContainer targetContainer) { * Create a sidekick container and attach it to another container. The VNC output of that container will be recorded. */ public VncRecordingContainer(@NonNull Network network, @NonNull String targetNetworkAlias) throws IllegalStateException { - super(TestcontainersConfiguration.getInstance().getVncRecordedContainerImage()); + super(TestcontainersConfiguration.getInstance().getVncDockerImageName()); this.targetNetworkAlias = targetNetworkAlias; withNetwork(network); diff --git a/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java index c78a13c99ac..5acb7ab8835 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java @@ -40,7 +40,7 @@ public AuthConfig effectiveAuthConfig(String imageName) { } // try and obtain more accurate auth config using our resolution - final DockerImageName parsed = new DockerImageName(imageName); + final DockerImageName parsed = DockerImageName.parse(imageName); final AuthConfig effectiveAuthConfig = RegistryAuthLocator.instance() .lookupAuthConfig(parsed, fallbackAuthConfig); diff --git a/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java b/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java index 11c621eb08b..f5d75ad9617 100644 --- a/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java +++ b/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java @@ -12,7 +12,7 @@ public abstract class AbstractImagePullPolicy implements ImagePullPolicy { @Override public boolean shouldPull(DockerImageName imageName) { - Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); + Logger logger = DockerLoggerFactory.getLogger(imageName.asCanonicalNameString()); // Does our cache already know the image? ImageData cachedImageData = LOCAL_IMAGES_CACHE.get(imageName); diff --git a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java index e6b330d4c90..ec371ef830e 100644 --- a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java +++ b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java @@ -39,7 +39,7 @@ public Optional refreshCache(DockerImageName imageName) { InspectImageResponse response = null; try { - response = dockerClient.inspectImageCmd(imageName.toString()).exec(); + response = dockerClient.inspectImageCmd(imageName.asCanonicalNameString()).exec(); } catch (NotFoundException e) { log.trace("Image {} not found", imageName, e); } diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index d0e1313edf6..8d3a77c5680 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -38,12 +38,18 @@ public class RemoteDockerImage extends LazyFuture { @ToString.Exclude private DockerClient dockerClient = DockerClientFactory.lazyClient(); + public RemoteDockerImage(DockerImageName dockerImageName) { + this.imageNameFuture = CompletableFuture.completedFuture(dockerImageName); + } + + @Deprecated public RemoteDockerImage(String dockerImageName) { - this.imageNameFuture = CompletableFuture.completedFuture(new DockerImageName(dockerImageName)); + this.imageNameFuture = CompletableFuture.completedFuture(DockerImageName.parse(dockerImageName)); } + @Deprecated public RemoteDockerImage(@NonNull String repository, @NonNull String tag) { - this.imageNameFuture = CompletableFuture.completedFuture(new DockerImageName(repository, tag)); + this.imageNameFuture = CompletableFuture.completedFuture(DockerImageName.parse(repository).withTag(tag)); } public RemoteDockerImage(@NonNull Future imageFuture) { @@ -57,7 +63,7 @@ protected final String resolve() { Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); try { if (!imagePullPolicy.shouldPull(imageName)) { - return imageName.toString(); + return imageName.asCanonicalNameString(); } // The image is not available locally - pull it @@ -76,7 +82,7 @@ protected final String resolve() { LocalImagesCache.INSTANCE.refreshCache(imageName); - return imageName.toString(); + return imageName.asCanonicalNameString(); } catch (InterruptedException | InternalServerErrorException e) { // these classes of exception often relate to timeout/connection errors so should be retried lastFailure = e; @@ -104,7 +110,7 @@ private String imageNameToString() { } try { - return getImageName().toString(); + return getImageName().asCanonicalNameString(); } catch (InterruptedException | ExecutionException e) { return e.getMessage(); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java index 2a87cb08223..07077259df8 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java @@ -6,7 +6,7 @@ public interface FromStatementTrait & DockerfileBuilderTrait> { default SELF from(String dockerImageName) { - new DockerImageName(dockerImageName).assertValid(); + DockerImageName.parse(dockerImageName).assertValid(); return ((SELF) this).withStatement(new SingleArgumentStatement("FROM", dockerImageName)); } diff --git a/core/src/main/java/org/testcontainers/utility/DockerImageName.java b/core/src/main/java/org/testcontainers/utility/DockerImageName.java index d57f1044e80..b4a40be2f16 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerImageName.java +++ b/core/src/main/java/org/testcontainers/utility/DockerImageName.java @@ -2,12 +2,16 @@ import com.google.common.net.HostAndPort; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; import java.util.regex.Pattern; @EqualsAndHashCode(exclude = "rawName") +@AllArgsConstructor(access = AccessLevel.PRIVATE) public final class DockerImageName { /* Regex patterns used for validation */ @@ -19,22 +23,42 @@ public final class DockerImageName { private final String rawName; private final String registry; private final String repo; - private final Versioning versioning; + @NotNull private final Versioning versioning; - public DockerImageName(String name) { - this.rawName = name; - final int slashIndex = name.indexOf('/'); + /** + * Parses a docker image name from a provided string. + * + * @param fullImageName in standard Docker format, e.g. name:tag, + * some.registry/path/name:tag, + * some.registry/path/name@sha256:abcdef..., etc. + */ + public static DockerImageName parse(String fullImageName) { + return new DockerImageName(fullImageName); + } + + /** + * Parses a docker image name from a provided string. + * + * @param fullImageName in standard Docker format, e.g. name:tag, + * some.registry/path/name:tag, + * some.registry/path/name@sha256:abcdef..., etc. + * @deprecated use {@link DockerImageName#parse(String)} instead + */ + @Deprecated + public DockerImageName(String fullImageName) { + this.rawName = fullImageName; + final int slashIndex = fullImageName.indexOf('/'); String remoteName; if (slashIndex == -1 || - (!name.substring(0, slashIndex).contains(".") && - !name.substring(0, slashIndex).contains(":") && - !name.substring(0, slashIndex).equals("localhost"))) { + (!fullImageName.substring(0, slashIndex).contains(".") && + !fullImageName.substring(0, slashIndex).contains(":") && + !fullImageName.substring(0, slashIndex).equals("localhost"))) { registry = ""; - remoteName = name; + remoteName = fullImageName; } else { - registry = name.substring(0, slashIndex); - remoteName = name.substring(slashIndex + 1); + registry = fullImageName.substring(0, slashIndex); + remoteName = fullImageName.substring(slashIndex + 1); } if (remoteName.contains("@sha256:")) { @@ -49,28 +73,40 @@ public DockerImageName(String name) { } } - public DockerImageName(String name, String tag) { - this.rawName = name; - final int slashIndex = name.indexOf('/'); + /** + * Parses a docker image name from a provided string, and uses a separate provided version. + * + * @param nameWithoutTag in standard Docker format, e.g. name, + * some.registry/path/name, + * some.registry/path/name, etc. + * @param version a docker image version identifier, either as a tag or sha256 checksum, e.g. + * tag, + * sha256:abcdef.... + * @deprecated use {@link DockerImageName#parse(String)}.{@link DockerImageName#withTag(String)} instead + */ + @Deprecated + public DockerImageName(String nameWithoutTag, @NotNull String version) { + this.rawName = nameWithoutTag; + final int slashIndex = nameWithoutTag.indexOf('/'); String remoteName; if (slashIndex == -1 || - (!name.substring(0, slashIndex).contains(".") && - !name.substring(0, slashIndex).contains(":") && - !name.substring(0, slashIndex).equals("localhost"))) { + (!nameWithoutTag.substring(0, slashIndex).contains(".") && + !nameWithoutTag.substring(0, slashIndex).contains(":") && + !nameWithoutTag.substring(0, slashIndex).equals("localhost"))) { registry = ""; - remoteName = name; + remoteName = nameWithoutTag; } else { - registry = name.substring(0, slashIndex); - remoteName = name.substring(slashIndex + 1); + registry = nameWithoutTag.substring(0, slashIndex); + remoteName = nameWithoutTag.substring(slashIndex + 1); } - if (tag.startsWith("sha256:")) { + if (version.startsWith("sha256:")) { repo = remoteName; - versioning = new Sha256Versioning(tag.replace("sha256:", "")); + versioning = new Sha256Versioning(version.replace("sha256:", "")); } else { repo = remoteName; - versioning = new TagVersioning(tag); + versioning = new TagVersioning(version); } } @@ -92,13 +128,16 @@ public String getVersionPart() { return versioning.toString(); } + /** + * @return canonical name for the image + */ + public String asCanonicalNameString() { + return getUnversionedPart() + versioning.getSeparator() + versioning.toString(); + } + @Override public String toString() { - if (versioning == null) { - return getUnversionedPart(); - } else { - return getUnversionedPart() + versioning.getSeparator() + versioning.toString(); - } + return asCanonicalNameString(); } /** @@ -111,10 +150,6 @@ public void assertValid() { if (!REPO_NAME.matcher(repo).matches()) { throw new IllegalArgumentException(repo + " is not a valid Docker image name (in " + rawName + ")"); } - if (versioning == null) { - throw new IllegalArgumentException("No image tag was specified in docker image name " + - "(" + rawName + "). Please provide a tag; this may be 'latest' or a specific version"); - } if (!versioning.isValid()) { throw new IllegalArgumentException(versioning + " is not a valid image versioning identifier (in " + rawName + ")"); } @@ -124,8 +159,13 @@ public String getRegistry() { return registry; } + public DockerImageName withTag(final String newTag) { + return new DockerImageName(rawName, registry, repo, new TagVersioning(newTag)); + } + private interface Versioning { boolean isValid(); + String getSeparator(); } @@ -155,7 +195,7 @@ public String toString() { } @Data - private class Sha256Versioning implements Versioning { + private static class Sha256Versioning implements Versioning { public static final String HASH_REGEX = "[0-9a-fA-F]{32,}"; private final String hash; diff --git a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java index 240a6d5afb4..fe12e9f541d 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java +++ b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java @@ -1,7 +1,6 @@ package org.testcontainers.utility; import lombok.NonNull; - import org.apache.commons.lang.SystemUtils; import org.slf4j.Logger; diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 0a0728e9306..3448e73dce3 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -14,7 +14,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; import com.google.common.collect.Sets; - import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.rnorth.ducttape.ratelimits.RateLimiter; @@ -22,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -72,7 +72,7 @@ private ResourceReaper() { @SneakyThrows(InterruptedException.class) public static String start(String hostIpAddress, DockerClient client) { - String ryukImage = TestcontainersConfiguration.getInstance().getRyukImage(); + String ryukImage = TestcontainersConfiguration.getInstance().getRyukDockerImageName().asCanonicalNameString(); DockerClientFactory.instance().checkAndPullImage(client, ryukImage); List binds = new ArrayList<>(); diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index aa829573447..1939e8e21b3 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -63,50 +63,95 @@ public String getAmbassadorContainerImage() { return (String) properties.getOrDefault("ambassador.container.image", "richnorth/ambassador:latest"); } + @Deprecated public String getSocatContainerImage() { return (String) properties.getOrDefault("socat.container.image", "alpine/socat:latest"); } + public DockerImageName getSocatDockerImageName() { + return DockerImageName.parse(getSocatContainerImage()); + } + + @Deprecated public String getVncRecordedContainerImage() { return (String) properties.getOrDefault("vncrecorder.container.image", "testcontainers/vnc-recorder:1.1.0"); } + public DockerImageName getVncDockerImageName() { + return DockerImageName.parse(getVncRecordedContainerImage()); + } + + @Deprecated public String getDockerComposeContainerImage() { return (String) properties.getOrDefault("compose.container.image", "docker/compose:1.24.1"); } + public DockerImageName getDockerComposeDockerImageName() { + return DockerImageName.parse(getDockerComposeContainerImage()); + } + + @Deprecated public String getTinyImage() { return (String) properties.getOrDefault("tinyimage.container.image", "alpine:3.5"); } + public DockerImageName getTinyDockerImageName() { + return DockerImageName.parse(getTinyImage()); + } + public boolean isRyukPrivileged() { return Boolean.parseBoolean((String) properties.getOrDefault("ryuk.container.privileged", "false")); } + @Deprecated public String getRyukImage() { return (String) properties.getOrDefault("ryuk.container.image", "testcontainers/ryuk:0.3.0"); } + public DockerImageName getRyukDockerImageName() { + return DockerImageName.parse(getRyukImage()); + } + + @Deprecated public String getSSHdImage() { return (String) properties.getOrDefault("sshd.container.image", "testcontainers/sshd:1.0.0"); } + public DockerImageName getSSHdDockerImageName() { + return DockerImageName.parse(getSSHdImage()); + } + public Integer getRyukTimeout() { return Integer.parseInt((String) properties.getOrDefault("ryuk.container.timeout", "30")); } + @Deprecated public String getKafkaImage() { return (String) properties.getOrDefault("kafka.container.image", "confluentinc/cp-kafka"); } + public DockerImageName getKafkaDockerImageName() { + return DockerImageName.parse(getKafkaImage()); + } + + @Deprecated public String getPulsarImage() { return (String) properties.getOrDefault("pulsar.container.image", "apachepulsar/pulsar"); } + public DockerImageName getPulsarDockerImageName() { + return DockerImageName.parse(getPulsarImage()); + } + + @Deprecated public String getLocalStackImage() { return (String) properties.getOrDefault("localstack.container.image", "localstack/localstack"); } + public DockerImageName getLocalstackDockerImageName() { + return DockerImageName.parse(getLocalStackImage()); + } + public boolean isDisableChecks() { return Boolean.parseBoolean((String) environmentProperties.getOrDefault("checks.disable", "false")); } diff --git a/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java b/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java index 2da41a8344e..e4197c7c1f6 100644 --- a/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java +++ b/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java @@ -7,11 +7,13 @@ import org.testcontainers.images.ImageData; import org.testcontainers.utility.DockerImageName; +import static org.testcontainers.TestImages.TINY_IMAGE; + public class OutOfPackageImagePullPolicyTest { @Test public void shouldSupportCustomPoliciesOutOfTestContainersPackage() { try ( - GenericContainer container = new GenericContainer<>() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withImagePullPolicy(new AbstractImagePullPolicy() { @Override protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { diff --git a/core/src/test/java/org/testcontainers/DaemonTest.java b/core/src/test/java/org/testcontainers/DaemonTest.java index e339f30acc9..f08614c8cdc 100644 --- a/core/src/test/java/org/testcontainers/DaemonTest.java +++ b/core/src/test/java/org/testcontainers/DaemonTest.java @@ -10,6 +10,7 @@ import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; +import static org.testcontainers.TestImages.TINY_IMAGE; /** * This test forks a new JVM, otherwise it's not possible to reliably diff the threads @@ -19,10 +20,10 @@ public class DaemonTest { public static void main(String[] args) { Thread mainThread = Thread.currentThread(); - GenericContainer genericContainer = null; + GenericContainer genericContainer = null; try { - genericContainer = new GenericContainer().withCommand("top"); + genericContainer = new GenericContainer<>(TINY_IMAGE).withCommand("top"); genericContainer.start(); Set threads = new HashSet<>(Thread.getAllStackTraces().keySet()); diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index 04edd407959..030e4164f00 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -30,7 +30,7 @@ public void runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally() { try { //remove tiny image, so it will be pulled during next command run dockFactory.client() - .removeImageCmd(TestcontainersConfiguration.getInstance().getTinyImage()) + .removeImageCmd(TestcontainersConfiguration.getInstance().getTinyDockerImageName().asCanonicalNameString()) .withForce(true).exec(); } catch (NotFoundException ignored) { // Do not fail if it's not pulled yet diff --git a/core/src/test/java/org/testcontainers/TestImages.java b/core/src/test/java/org/testcontainers/TestImages.java new file mode 100644 index 00000000000..3f16e88d882 --- /dev/null +++ b/core/src/test/java/org/testcontainers/TestImages.java @@ -0,0 +1,13 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.TestcontainersConfiguration; + +public interface TestImages { + DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:3.0.2"); + DockerImageName RABBITMQ_IMAGE = DockerImageName.parse("rabbitmq:3.5.3"); + DockerImageName MONGODB_IMAGE = DockerImageName.parse("mongo:3.1.5"); + DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.2"); + DockerImageName DOCKER_REGISTRY_IMAGE = DockerImageName.parse("registry:2.7.0"); + DockerImageName TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyDockerImageName(); +} diff --git a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java index 8c98b0730b0..d17b0709dfa 100644 --- a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java +++ b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java @@ -12,6 +12,7 @@ import java.net.InetSocketAddress; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.testcontainers.TestImages.TINY_IMAGE; public class ExposedHostTest { @@ -31,9 +32,9 @@ public static void setUpClass() throws Exception { server.start(); Testcontainers.exposeHostPorts(server.getAddress().getPort()); - + Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 80)); - Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 81)); + Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 81)); } @AfterClass @@ -43,24 +44,33 @@ public static void tearDownClass() throws Exception { @Test public void testExposedHost() throws Exception { - assertResponse(new GenericContainer().withCommand("top"), server.getAddress().getPort()); + assertResponse(new GenericContainer<>(TINY_IMAGE) + .withCommand("top"), + server.getAddress().getPort()); } @Test public void testExposedHostWithNetwork() throws Exception { try (Network network = Network.newNetwork()) { - assertResponse(new GenericContainer().withNetwork(network).withCommand("top"), server.getAddress().getPort()); + assertResponse(new GenericContainer<>(TINY_IMAGE) + .withNetwork(network) + .withCommand("top"), + server.getAddress().getPort()); } } - + @Test public void testExposedHostPortOnFixedInternalPorts() throws Exception { - assertResponse(new GenericContainer().withCommand("top"), 80); - assertResponse(new GenericContainer().withCommand("top"), 81); - } + assertResponse(new GenericContainer<>(TINY_IMAGE) + .withCommand("top"), + 80); + assertResponse(new GenericContainer<>(TINY_IMAGE) + .withCommand("top"), + 81); + } @SneakyThrows - protected void assertResponse(GenericContainer container, int port) { + protected void assertResponse(GenericContainer container, int port) { try { container.start(); diff --git a/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java b/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java index 15a9eba7d17..63993bc24ff 100644 --- a/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java +++ b/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java @@ -3,6 +3,7 @@ import org.junit.Test; import org.junit.runner.Description; import org.junit.runners.model.Statement; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 134bdf18f30..5008ba5baca 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -11,6 +11,7 @@ import org.assertj.core.api.Assumptions; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.TestImages; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; @@ -28,7 +29,7 @@ public void shouldReportOOMAfterWait() { // Poor man's rootless Docker detection :D Assumptions.assumeThat(info.getDriver()).doesNotContain("vfs"); try ( - GenericContainer container = new GenericContainer<>() + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new NoopStartupCheckStrategy()) .waitingFor(new WaitForExitedState(ContainerState::getOOMKilled)) .withCreateContainerCmdModifier(it -> { @@ -49,7 +50,7 @@ public void shouldReportOOMAfterWait() { @Test public void shouldReportErrorAfterWait() { try ( - GenericContainer container = new GenericContainer<>() + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new NoopStartupCheckStrategy()) .waitingFor(new WaitForExitedState(state -> state.getExitCode() > 0)) .withCommand("sh", "-c", "usleep 100; exit 123") diff --git a/core/src/test/java/org/testcontainers/containers/NetworkTest.java b/core/src/test/java/org/testcontainers/containers/NetworkTest.java index b717b8dc81a..a39f0552a5a 100644 --- a/core/src/test/java/org/testcontainers/containers/NetworkTest.java +++ b/core/src/test/java/org/testcontainers/containers/NetworkTest.java @@ -5,9 +5,11 @@ import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.Network; +import org.testcontainers.TestImages; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; import static org.testcontainers.containers.Network.newNetwork; @RunWith(Enclosed.class) @@ -19,13 +21,13 @@ public static class WithRules { public Network network = newNetwork(); @Rule - public GenericContainer foo = new GenericContainer() + public GenericContainer foo = new GenericContainer<>(TestImages.TINY_IMAGE) .withNetwork(network) .withNetworkAliases("foo") .withCommand("/bin/sh", "-c", "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done"); @Rule - public GenericContainer bar = new GenericContainer() + public GenericContainer bar = new GenericContainer<>(TestImages.TINY_IMAGE) .withNetwork(network) .withCommand("top"); @@ -44,12 +46,12 @@ public void testNetworkSupport() throws Exception { try ( Network network = Network.newNetwork(); - GenericContainer foo = new GenericContainer() + GenericContainer foo = new GenericContainer<>(TestImages.TINY_IMAGE) .withNetwork(network) .withNetworkAliases("foo") .withCommand("/bin/sh", "-c", "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done"); - GenericContainer bar = new GenericContainer() + GenericContainer bar = new GenericContainer<>(TestImages.TINY_IMAGE) .withNetwork(network) .withCommand("top") ) { @@ -63,11 +65,11 @@ public void testNetworkSupport() throws Exception { } @Test - public void testBuilder() throws Exception { + public void testBuilder() { try ( Network network = Network.builder() .driver("macvlan") - .build(); + .build() ) { String id = network.getId(); assertEquals( @@ -79,11 +81,11 @@ public void testBuilder() throws Exception { } @Test - public void testModifiers() throws Exception { + public void testModifiers() { try ( Network network = Network.builder() .createNetworkCmdModifier(cmd -> cmd.withDriver("macvlan")) - .build(); + .build() ) { String id = network.getId(); assertEquals( @@ -95,7 +97,7 @@ public void testModifiers() throws Exception { } @Test - public void testReusability() throws Exception { + public void testReusability() { try (Network network = Network.newNetwork()) { String firstId = network.getId(); assertNotNull( diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index b2d4d327ba2..c212d04c33a 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -3,7 +3,12 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.command.*; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerCmd; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.command.ListContainersCmd; +import com.github.dockerjava.api.command.StartContainerCmd; import com.github.dockerjava.api.model.Container; import com.github.dockerjava.core.command.CreateContainerCmdImpl; import com.github.dockerjava.core.command.InspectContainerCmdImpl; @@ -35,7 +40,6 @@ import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -45,14 +49,11 @@ import static org.assertj.core.api.Assumptions.assumeThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; +import static org.testcontainers.TestImages.TINY_IMAGE; @RunWith(Enclosed.class) public class ReusabilityUnitTests { - static final CompletableFuture IMAGE_FUTURE = CompletableFuture.completedFuture( - TestcontainersConfiguration.getInstance().getTinyImage() - ); - @RunWith(Parameterized.class) @RequiredArgsConstructor @FieldDefaults(makeFinal = true) @@ -61,8 +62,8 @@ public static class CanBeReusedTest { @Parameterized.Parameters(name = "{0}") public static Object[][] data() { return new Object[][] { - { "generic", new GenericContainer(IMAGE_FUTURE), true }, - { "anonymous generic", new GenericContainer(IMAGE_FUTURE) {}, true }, + { "generic", new GenericContainer<>(TINY_IMAGE), true }, + { "anonymous generic", new GenericContainer(TINY_IMAGE) {}, true }, { "custom", new CustomContainer(), true }, { "anonymous custom", new CustomContainer() {}, true }, { "custom with containerIsCreated", new CustomContainerWithContainerIsCreated(), false }, @@ -84,16 +85,16 @@ public void shouldBeReusable() { } } - static class CustomContainer extends GenericContainer { + static class CustomContainer extends GenericContainer { CustomContainer() { - super(IMAGE_FUTURE); + super(TINY_IMAGE); } } - static class CustomContainerWithContainerIsCreated extends GenericContainer { + static class CustomContainerWithContainerIsCreated extends GenericContainer { CustomContainerWithContainerIsCreated() { - super(IMAGE_FUTURE); + super(TINY_IMAGE); } @Override @@ -109,7 +110,7 @@ public static class HooksTest extends AbstractReusabilityTest { List script = new ArrayList<>(); - GenericContainer container = makeReusable(new GenericContainer(IMAGE_FUTURE) { + GenericContainer container = makeReusable(new GenericContainer(TINY_IMAGE) { @Override protected boolean canBeReused() { @@ -188,7 +189,7 @@ public void shouldNotCallHookIfNotReused() { @FieldDefaults(makeFinal = true) public static class HashTest extends AbstractReusabilityTest { - protected GenericContainer container = makeReusable(new GenericContainer(IMAGE_FUTURE) { + protected GenericContainer container = makeReusable(new GenericContainer(TINY_IMAGE) { @Override public void copyFileToContainer(MountableFile mountableFile, String containerPath) { // NOOP @@ -296,7 +297,7 @@ public void shouldHashCopiedFiles() { @RunWith(BlockJUnit4ClassRunner.class) @FieldDefaults(makeFinal = true) public static class CopyFilesHashTest { - GenericContainer container = new GenericContainer(IMAGE_FUTURE); + GenericContainer container = new GenericContainer<>(TINY_IMAGE); @Test public void empty() { diff --git a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java index ad0e4c76ae2..05ef7373293 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java @@ -7,6 +7,7 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.ALPINE_IMAGE; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; @@ -15,7 +16,7 @@ public class ContainerLogsTest { @Test @Ignore("fails due to the timing of the shell's decision to flush") public void getLogsReturnsAllLogsToDate() { - try (GenericContainer container = shortLivedContainer()) { + try (GenericContainer container = shortLivedContainer()) { container.start(); final String logs = container.getLogs(); @@ -25,7 +26,7 @@ public void getLogsReturnsAllLogsToDate() { @Test public void getLogsContainsBothOutputTypes() { - try (GenericContainer container = shortLivedContainer()) { + try (GenericContainer container = shortLivedContainer()) { container.start(); // docsGetAllLogs { @@ -38,7 +39,7 @@ public void getLogsContainsBothOutputTypes() { @Test public void getLogsReturnsStdOutToDate() { - try (GenericContainer container = shortLivedContainer()) { + try (GenericContainer container = shortLivedContainer()) { container.start(); // docsGetStdOut { @@ -50,7 +51,7 @@ public void getLogsReturnsStdOutToDate() { @Test public void getLogsReturnsStdErrToDate() { - try (GenericContainer container = shortLivedContainer()) { + try (GenericContainer container = shortLivedContainer()) { container.start(); // docsGetStdErr { @@ -62,7 +63,7 @@ public void getLogsReturnsStdErrToDate() { @Test public void getLogsForLongRunningContainer() throws InterruptedException { - try (GenericContainer container = longRunningContainer()) { + try (GenericContainer container = longRunningContainer()) { container.start(); Thread.sleep(1000L); @@ -72,14 +73,14 @@ public void getLogsForLongRunningContainer() throws InterruptedException { } } - private static GenericContainer shortLivedContainer() { - return new GenericContainer("alpine:3.3") + private static GenericContainer shortLivedContainer() { + return new GenericContainer<>(ALPINE_IMAGE) .withCommand("/bin/sh", "-c", "echo -n 'stdout' && echo -n 'stderr' 1>&2") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); } - private static GenericContainer longRunningContainer() { - return new GenericContainer("alpine:3.3") + private static GenericContainer longRunningContainer() { + return new GenericContainer<>(ALPINE_IMAGE) .withCommand("ping -c 100 127.0.0.1"); } } diff --git a/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java b/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java index 4d7a4e21133..a43a001ca5b 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java @@ -16,6 +16,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static org.testcontainers.TestImages.TINY_IMAGE; + /** * Test that event streaming from the {@link DockerClient} works correctly */ @@ -32,7 +34,7 @@ public void test() throws IOException, InterruptedException { CountDownLatch latch = new CountDownLatch(1); try ( - GenericContainer container = new GenericContainer<>() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withCommand("true") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) ) { diff --git a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java index 6e319838888..fd936d26c19 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java @@ -5,11 +5,12 @@ import org.junit.runners.Parameterized; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.utility.DockerImageName; @RunWith(Parameterized.class) public class ImagePullTest { - private String image; + private final String image; @Parameterized.Parameters(name = "{0}") public static String[] parameters() { @@ -34,7 +35,7 @@ public ImagePullTest(String image) { @Test public void test() { - try (final GenericContainer container = new GenericContainer<>(image) + try (final GenericContainer container = new GenericContainer<>(DockerImageName.parse(image)) .withCommand("/bin/sh", "-c", "sleep 0") .withStartupCheckStrategy(new OneShotStartupCheckStrategy())) { container.start(); diff --git a/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java index 20b52798d40..e073fa0522a 100644 --- a/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java @@ -13,7 +13,7 @@ public class AgeBasedPullPolicyTest { - final DockerImageName imageName = new DockerImageName(UUID.randomUUID().toString()); + final DockerImageName imageName = DockerImageName.parse(UUID.randomUUID().toString()); @Test public void shouldPull() { diff --git a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java index 69e68f7f225..9b22f5e6166 100644 --- a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java @@ -1,12 +1,9 @@ package org.testcontainers.images; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; - import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.exception.NotFoundException; -import com.github.dockerjava.core.command.PullImageResultCallback; -import com.github.dockerjava.core.command.PushImageResultCallback; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -23,20 +20,24 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; + public class ImagePullPolicyTest { @ClassRule - public static GenericContainer registry = new GenericContainer<>("registry:2") + public static GenericContainer registry = new GenericContainer<>(DOCKER_REGISTRY_IMAGE) .withExposedPorts(5000); - private static String imageName; + private static DockerImageName imageName; @BeforeClass public static void beforeClass() throws Exception { String testRegistryAddress = registry.getHost() + ":" + registry.getFirstMappedPort(); String testImageName = testRegistryAddress + "/image-pull-policy-test"; String tag = UUID.randomUUID().toString(); - imageName = testImageName + ":" + tag; + imageName = DockerImageName.parse(testImageName).withTag(tag); DockerClient client = DockerClientFactory.instance().client(); String dummySourceImage = "hello-world:latest"; @@ -47,28 +48,22 @@ public static void beforeClass() throws Exception { // push the image to the registry client.tagImageCmd(dummyImageId, testImageName, tag).exec(); - client.pushImageCmd(imageName) - .exec(new PushImageResultCallback()) + client.pushImageCmd(imageName.asCanonicalNameString()) + .exec(new ResultCallback.Adapter<>()) .awaitCompletion(1, TimeUnit.MINUTES); } @AfterClass public static void afterClass() { - try { - DockerClientFactory.instance().client().removeImageCmd(imageName).withForce(true).exec(); - } catch (NotFoundException ignored) { - } + removeImage(); } @Before public void setUp() { // Clean up local cache - try { - DockerClientFactory.instance().client().removeImageCmd(imageName).withForce(true).exec(); - } catch (NotFoundException ignored) { - } + removeImage(); - LocalImagesCache.INSTANCE.cache.remove(new DockerImageName(imageName)); + LocalImagesCache.INSTANCE.cache.remove(imageName); } @Test @@ -90,7 +85,7 @@ public void shouldAlwaysPull() { container.start(); } - DockerClientFactory.instance().client().removeImageCmd(imageName).withForce(true).exec(); + removeImage(); try ( GenericContainer container = new GenericContainer<>(imageName) @@ -175,4 +170,13 @@ private void expectToFailWithNotFoundException(GenericContainer container) { } } + private static void removeImage() { + try { + DockerClientFactory.instance().client() + .removeImageCmd(imageName.asCanonicalNameString()) + .withForce(true) + .exec(); + } catch (NotFoundException ignored) { + } + } } diff --git a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java index 6b6a82559bf..d2ea3e7188a 100644 --- a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java +++ b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java @@ -1,23 +1,24 @@ package org.testcontainers.images; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; - import org.junit.Test; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.LazyFuture; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; + public class RemoteDockerImageTest { @Test public void toStringContainsOnlyImageName() { String imageName = Base58.randomString(8).toLowerCase(); - RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageName); + RemoteDockerImage remoteDockerImage = new RemoteDockerImage(DockerImageName.parse(imageName)); assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); } diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java index faf5fb950b8..b99a70a7650 100644 --- a/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java @@ -1,21 +1,21 @@ package org.testcontainers.images.builder; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.rnorth.visibleassertions.VisibleAssertions.fail; - -import java.nio.file.Path; -import java.nio.file.Paths; - +import com.github.dockerjava.api.exception.DockerClientException; import org.junit.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.utility.DockerImageName; -import com.github.dockerjava.api.exception.DockerClientException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.rnorth.visibleassertions.VisibleAssertions.fail; public class DockerignoreTest { - + private static final Path INVALID_DOCKERIGNORE_PATH = Paths.get("src/test/resources/dockerfile-build-invalid"); - + @Test public void testInvalidDockerignore() throws Exception { try { @@ -24,13 +24,13 @@ public void testInvalidDockerignore() throws Exception { .withDockerfile(INVALID_DOCKERIGNORE_PATH.resolve("Dockerfile")) .get(); fail("Should not be able to build an image with an invalid .dockerignore file"); - } + } catch (DockerClientException e) { if (!e.getMessage().contains("Invalid pattern")) throw e; } } - + @SuppressWarnings("resource") @Test public void testValidDockerignore() throws Exception { @@ -38,7 +38,7 @@ public void testValidDockerignore() throws Exception { .withFileFromPath(".", DockerfileBuildTest.RESOURCE_PATH) .withDockerfile(DockerfileBuildTest.RESOURCE_PATH.resolve("Dockerfile-currentdir")); try( - final GenericContainer container = new GenericContainer<>(img.get()) + final GenericContainer container = new GenericContainer(DockerImageName.parse(img.get())) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCommand("ls", "/") ) { @@ -46,11 +46,11 @@ public void testValidDockerignore() throws Exception { container.start(); final String logs = container.getLogs(); - assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, + assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, logs.contains("should_not_be_ignored.txt")); - assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, + assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, !logs.contains("should_be_ignored.txt")); } } - + } diff --git a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java index ed6ee561505..b0ed90d9c9e 100644 --- a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java @@ -11,6 +11,7 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.TINY_IMAGE; public class CopyFileToContainerTest { private static String containerPath = "/tmp/mappable-resource/"; @@ -19,7 +20,7 @@ public class CopyFileToContainerTest { @Test public void checkFileCopied() throws IOException, InterruptedException { try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withCommand("sleep", "3000") .withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), containerPath) ) { @@ -32,7 +33,7 @@ public void checkFileCopied() throws IOException, InterruptedException { @Test public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withCommand("sleep", "3000") .withClasspathResourceMapping("/mappable-resource/", containerPath, BindMode.READ_ONLY) ) { @@ -45,7 +46,7 @@ public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { @Test public void shouldUseCopyOnlyWithReadOnlyClasspathResources() { String resource = "/test_copy_to_container.txt"; - GenericContainer container = new GenericContainer<>() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withClasspathResourceMapping(resource, "/readOnly", BindMode.READ_ONLY) .withClasspathResourceMapping(resource, "/readOnlyNoSelinux", BindMode.READ_ONLY) @@ -64,7 +65,7 @@ public void shouldUseCopyOnlyWithReadOnlyClasspathResources() { public void shouldCreateFoldersStructureWithCopy() throws Exception { String resource = "/test_copy_to_container.txt"; try ( - GenericContainer container = new GenericContainer<>() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withCommand("sleep", "3000") .withClasspathResourceMapping(resource, "/a/b/c/file", BindMode.READ_ONLY) ) { diff --git a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java index 4f2ee01bc6d..bd82c58a7f7 100644 --- a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java +++ b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java @@ -16,6 +16,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.testcontainers.TestImages.TINY_IMAGE; + public class DependenciesTest { @Test @@ -23,7 +25,7 @@ public void shouldWorkWithSimpleDependency() { InvocationCountingStartable startable = new InvocationCountingStartable(); try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable) ) { @@ -40,7 +42,7 @@ public void shouldWorkWithMutlipleDependencies() { InvocationCountingStartable startable2 = new InvocationCountingStartable(); try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable1, startable2) ) { @@ -56,7 +58,7 @@ public void shouldStartEveryTime() { InvocationCountingStartable startable = new InvocationCountingStartable(); try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable) ) { @@ -83,7 +85,7 @@ public void shouldStartTransitiveDependencies() { startable.getDependencies().add(transitiveStartable); try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable) ) { diff --git a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java index 873160bdbc9..59c2a63127c 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java @@ -2,12 +2,13 @@ import com.github.dockerjava.api.model.NetworkSettings; import lombok.extern.slf4j.Slf4j; -import org.junit.*; +import org.junit.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.TINY_IMAGE; /** * Simple tests of named network modes - more may be possible, but may not be reproducible @@ -19,7 +20,7 @@ public class DockerNetworkModeTest { @Test public void testNoNetworkContainer() { try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCommand("true") .withNetworkMode("none") @@ -35,7 +36,7 @@ public void testNoNetworkContainer() { @Test public void testHostNetworkContainer() { try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCommand("true") .withNetworkMode("host") diff --git a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java index 95de9ef1b85..5e12fafc064 100644 --- a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java +++ b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java @@ -12,6 +12,7 @@ import java.io.IOException; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.ALPINE_IMAGE; public class FileOperationsTest { @@ -21,7 +22,7 @@ public class FileOperationsTest { @Test public void copyFileToContainerFileTest() throws Exception { try ( - GenericContainer alpineCopyToContainer = new GenericContainer("alpine:3.2") + GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) .withCommand("top") ) { alpineCopyToContainer.start(); @@ -39,7 +40,7 @@ public void copyFileToContainerFileTest() throws Exception { @Test public void copyFileToContainerFolderTest() throws Exception { try ( - GenericContainer alpineCopyToContainer = new GenericContainer("alpine:3.2") + GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) .withCommand("top") ) { alpineCopyToContainer.start(); @@ -57,7 +58,7 @@ public void copyFileToContainerFolderTest() throws Exception { @Test public void copyFolderToContainerFolderTest() throws Exception { try ( - GenericContainer alpineCopyToContainer = new GenericContainer("alpine:3.2") + GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) .withCommand("top") ) { @@ -76,7 +77,7 @@ public void copyFolderToContainerFolderTest() throws Exception { @Test(expected = NotFoundException.class) public void copyFromContainerShouldFailBecauseNoFileTest() throws NotFoundException { try ( - GenericContainer alpineCopyToContainer = new GenericContainer("alpine:3.2") + GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) .withCommand("top") ) { alpineCopyToContainer.start(); @@ -87,7 +88,7 @@ public void copyFromContainerShouldFailBecauseNoFileTest() throws NotFoundExcept @Test public void shouldCopyFileFromContainerTest() throws IOException { try ( - GenericContainer alpineCopyToContainer = new GenericContainer("alpine:3.2") + GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) .withCommand("top") ) { diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index 5fe49756ba1..34c039b4fd3 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -1,8 +1,5 @@ package org.testcontainers.junit; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; - import com.google.common.util.concurrent.Uninterruptibles; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; @@ -15,6 +12,10 @@ import java.net.Socket; import java.util.concurrent.TimeUnit; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.testcontainers.TestImages.TINY_IMAGE; + /** * Test of {@link FixedHostPortGenericContainer}. Note that this is not an example of typical use (usually, a container * should be a field on the test class annotated with @Rule or @TestRule). Instead, here, the lifecycle of the container @@ -46,7 +47,7 @@ public void testFixedHostPortMapping() throws IOException { // first find a free port on the docker host that will work for testing final Integer unusedHostPort; try ( - final GenericContainer echoServer = new GenericContainer<>(TEST_IMAGE) + final GenericContainer echoServer = new GenericContainer(TINY_IMAGE) .withExposedPorts(TEST_PORT) .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) ) { diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index b450244a84d..c13421029e0 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -6,10 +6,19 @@ import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; -import com.rabbitmq.client.*; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; import org.apache.commons.io.FileUtils; import org.bson.Document; -import org.junit.*; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; import org.rnorth.ducttape.RetryCountExceededException; import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.Container; @@ -18,7 +27,13 @@ import org.testcontainers.utility.Base58; import org.testcontainers.utility.TestEnvironment; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; import java.net.Socket; import java.time.Duration; import java.util.Arrays; @@ -30,7 +45,16 @@ import static java.util.Collections.singletonMap; import static org.hamcrest.CoreMatchers.equalTo; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.ALPINE_IMAGE; +import static org.testcontainers.TestImages.MONGODB_IMAGE; +import static org.testcontainers.TestImages.RABBITMQ_IMAGE; +import static org.testcontainers.TestImages.REDIS_IMAGE; +import static org.testcontainers.TestImages.TINY_IMAGE; import static org.testcontainers.containers.BindMode.READ_ONLY; import static org.testcontainers.containers.BindMode.READ_WRITE; import static org.testcontainers.containers.SelinuxContext.SHARED; @@ -47,6 +71,7 @@ public class GenericContainerRuleTest { private static final int RABBITMQ_PORT = 5672; private static final int MONGO_PORT = 27017; + /* * Test data setup */ @@ -61,29 +86,27 @@ public static void setupContent() throws FileNotFoundException { * Redis */ @ClassRule - public static GenericContainer redis = new GenericContainer("redis:3.0.2") + public static GenericContainer redis = new GenericContainer<>(REDIS_IMAGE) .withExposedPorts(REDIS_PORT); /** * RabbitMQ */ @ClassRule - public static GenericContainer rabbitMq = new GenericContainer("rabbitmq:3.5.3") + public static GenericContainer rabbitMq = new GenericContainer<>(RABBITMQ_IMAGE) .withExposedPorts(RABBITMQ_PORT); - /** * MongoDB */ @ClassRule - public static GenericContainer mongo = new GenericContainer("mongo:3.1.5") + public static GenericContainer mongo = new GenericContainer<>(MONGODB_IMAGE) .withExposedPorts(MONGO_PORT); - /** * Pass an environment variable to the container, then run a shell script that exposes the variable in a quick and * dirty way for testing. */ @ClassRule - public static GenericContainer alpineEnvVar = new GenericContainer<>("alpine:3.2") + public static GenericContainer alpineEnvVar = new GenericContainer<>(ALPINE_IMAGE) .withExposedPorts(80) .withEnv("MAGIC_NUMBER", "4") .withEnv("MAGIC_NUMBER", oldValue -> oldValue.orElse("") + "2") @@ -94,7 +117,7 @@ public static void setupContent() throws FileNotFoundException { * dirty way for testing. */ @ClassRule - public static GenericContainer alpineEnvVarFromMap = new GenericContainer("alpine:3.2") + public static GenericContainer alpineEnvVarFromMap = new GenericContainer<>(ALPINE_IMAGE) .withExposedPorts(80) .withEnv(ImmutableMap.of( "FIRST", "42", @@ -106,7 +129,7 @@ public static void setupContent() throws FileNotFoundException { * Map a file on the classpath to a file in the container, and then expose the content for testing. */ @ClassRule - public static GenericContainer alpineClasspathResource = new GenericContainer("alpine:3.2") + public static GenericContainer alpineClasspathResource = new GenericContainer<>(ALPINE_IMAGE) .withExposedPorts(80) .withClasspathResourceMapping("mappable-resource/test-resource.txt", "/content.txt", READ_ONLY) .withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done"); @@ -115,7 +138,7 @@ public static void setupContent() throws FileNotFoundException { * Map a file on the classpath to a file in the container, and then expose the content for testing. */ @ClassRule - public static GenericContainer alpineClasspathResourceSelinux = new GenericContainer("alpine:3.2") + public static GenericContainer alpineClasspathResourceSelinux = new GenericContainer<>(ALPINE_IMAGE) .withExposedPorts(80) .withClasspathResourceMapping("mappable-resource/test-resource.txt", "/content.txt", READ_WRITE, SHARED) .withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done"); @@ -124,14 +147,16 @@ public static void setupContent() throws FileNotFoundException { * Create a container with an extra host entry and expose the content of /etc/hosts for testing. */ @ClassRule - public static GenericContainer alpineExtrahost = new GenericContainer("alpine:3.2") + public static GenericContainer alpineExtrahost = new GenericContainer<>(ALPINE_IMAGE) .withExposedPorts(80) .withExtraHost("somehost", "192.168.1.10") .withCommand("/bin/sh", "-c", "while true; do cat /etc/hosts | nc -l -p 80; done"); @Test public void testIsRunning() { - try (GenericContainer container = new GenericContainer().withCommand("top")) { + try ( + GenericContainer container = new GenericContainer<>(TINY_IMAGE) + .withCommand("top")) { assertFalse("Container is not started and not running", container.isRunning()); container.start(); assertTrue("Container is started and running", container.isRunning()); @@ -141,7 +166,7 @@ public void testIsRunning() { @Test public void withTmpFsTest() throws Exception { try ( - GenericContainer container = new GenericContainer() + GenericContainer container = new GenericContainer<>(TINY_IMAGE) .withCommand("top") .withTmpFs(singletonMap("/testtmpfs", "rw")) ) { @@ -222,7 +247,7 @@ public void environmentFromMapTest() throws IOException { @Test public void customLabelTest() { - try (final GenericContainer alpineCustomLabel = new GenericContainer("alpine:3.2") + try (final GenericContainer alpineCustomLabel = new GenericContainer<>(ALPINE_IMAGE) .withLabel("our.custom", "label") .withCommand("top")) { @@ -240,7 +265,7 @@ public void exceptionThrownWhenTryingToOverrideTestcontainersLabels() { assertThrows("When trying to overwrite an 'org.testcontainers' label, withLabel() throws an exception", IllegalArgumentException.class, () -> { - new GenericContainer("alpine:3.2") + new GenericContainer<>(ALPINE_IMAGE) .withLabel("org.testcontainers.foo", "false"); } ); @@ -262,7 +287,7 @@ public void customClasspathResourceMappingWithSelinuxTest() throws IOException { } @Test - public void exceptionThrownWhenMappedPortNotFound() throws IOException { + public void exceptionThrownWhenMappedPortNotFound() { assertThrows("When the requested port is not mapped, getMappedPort() throws an exception", IllegalArgumentException.class, () -> { @@ -279,10 +304,10 @@ protected static void writeStringToFile(File contentFolder, String filename, Str } @Test @Ignore //TODO investigate intermittent failures - public void failFastWhenContainerHaltsImmediately() throws Exception { + public void failFastWhenContainerHaltsImmediately() { long startingTimeMs = System.currentTimeMillis(); - final GenericContainer failsImmediately = new GenericContainer("alpine:3.2") + final GenericContainer failsImmediately = new GenericContainer<>(ALPINE_IMAGE) .withCommand("/bin/sh", "-c", "return false") .withMinimumRunningDuration(Duration.ofMillis(100)); @@ -346,7 +371,7 @@ public void createContainerCmdHookTest() { // Use random name to avoid the conflicts between the tests String randomName = Base58.randomString(5); try( - GenericContainer container = new GenericContainer<>("redis:3.0.2") + GenericContainer container = new GenericContainer<>(REDIS_IMAGE) .withCommand("redis-server", "--help") .withCreateContainerCmdModifier(cmd -> cmd.withName("overrideMe")) // Preserves the order @@ -390,7 +415,7 @@ public void addingExposedPortTwiceShouldNotFail() { @Test public void sharedMemorySetTest() { - try (GenericContainer containerWithSharedMemory = new GenericContainer() + try (GenericContainer containerWithSharedMemory = new GenericContainer<>(TINY_IMAGE) .withSharedMemorySize(42L * FileUtils.ONE_MB) .withStartupCheckStrategy(new OneShotStartupCheckStrategy())) { diff --git a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java index d842829b4b6..95047779551 100644 --- a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java +++ b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java @@ -3,6 +3,7 @@ import org.junit.Test; import org.testcontainers.containers.ContainerFetchException; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; @@ -16,7 +17,7 @@ public void pullingNonExistentImageFailsGracefully() { assertThrows("Pulling a nonexistent container will cause an exception to be thrown", ContainerFetchException.class, () -> { - new GenericContainer("richnorth/nonexistent:latest").getDockerImageName(); + new GenericContainer<>(DockerImageName.parse("testcontainers/nonexistent:latest")).getDockerImageName(); }); } } diff --git a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java index 83ba05be86e..649a0b56fc4 100644 --- a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java +++ b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java @@ -14,7 +14,10 @@ import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.ALPINE_IMAGE; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; /** @@ -23,7 +26,7 @@ public class OutputStreamTest { @Rule - public GenericContainer container = new GenericContainer("alpine:3.2") + public GenericContainer container = new GenericContainer(ALPINE_IMAGE) .withCommand("ping -c 5 127.0.0.1"); private static final Logger LOGGER = LoggerFactory.getLogger(OutputStreamTest.class); diff --git a/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java b/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java index 0e7b66534b7..b15f63f4158 100644 --- a/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java +++ b/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java @@ -15,14 +15,17 @@ import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.ALPINE_IMAGE; import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; @Slf4j public class OutputStreamWithTTYTest { @Rule - public GenericContainer container = new GenericContainer<>("alpine:3.2") + public GenericContainer container = new GenericContainer<>(ALPINE_IMAGE) .withCommand("ls -1") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCreateContainerCmdModifier(command -> command.withTty(true)); diff --git a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java index 30230cc12ff..b23ddf2ca1c 100644 --- a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java +++ b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java @@ -6,6 +6,7 @@ import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.ALPINE_IMAGE; /** * Created by rnorth on 26/07/2016. @@ -13,7 +14,7 @@ public class WorkingDirectoryTest { @ClassRule - public static GenericContainer container = new GenericContainer("alpine:3.2") + public static GenericContainer container = new GenericContainer(ALPINE_IMAGE) .withWorkingDirectory("/etc") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCommand("ls", "-al"); diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java index 3d3c2f0606d..480536a54ef 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java @@ -4,6 +4,7 @@ import org.junit.Before; import org.rnorth.ducttape.RetryCountExceededException; import org.rnorth.visibleassertions.VisibleAssertions; +import org.testcontainers.TestImages; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.WaitStrategy; @@ -20,7 +21,6 @@ */ public abstract class AbstractWaitStrategyTest { static final long WAIT_TIMEOUT_MILLIS = 3000; - static final String IMAGE_NAME = "alpine:3.7"; /** * Indicates that the WaitStrategy has completed waiting successfully. @@ -38,36 +38,36 @@ public abstract class AbstractWaitStrategyTest { protected abstract W buildWaitStrategy(final AtomicBoolean ready); @Before - public void setUp() throws Exception { + public void setUp() { ready = new AtomicBoolean(false); } /** - * Starts a GenericContainer with the {@link #IMAGE_NAME} image, passing the given {@code shellCommand} as + * Starts a GenericContainer with the Alpine image, passing the given {@code shellCommand} as * a parameter to {@literal sh -c} (the container CMD). * * @param shellCommand the shell command to execute * @return the (unstarted) container */ - private GenericContainer startContainerWithCommand(String shellCommand) { + private GenericContainer startContainerWithCommand(String shellCommand) { return startContainerWithCommand(shellCommand, buildWaitStrategy(ready)); } /** - * Starts a GenericContainer with the {@link #IMAGE_NAME} image, passing the given {@code shellCommand} as + * Starts a GenericContainer with the Alpine image, passing the given {@code shellCommand} as * a parameter to {@literal sh -c} (the container CMD) and apply a give wait strategy. * Note that the timeout will be overwritten if any with {@link #WAIT_TIMEOUT_MILLIS}. * @param shellCommand the shell command to execute * @param waitStrategy The wait strategy to apply * @return the (unstarted) container */ - protected GenericContainer startContainerWithCommand(String shellCommand, WaitStrategy waitStrategy) { + protected GenericContainer startContainerWithCommand(String shellCommand, WaitStrategy waitStrategy) { return startContainerWithCommand(shellCommand, waitStrategy, 8080); } - protected GenericContainer startContainerWithCommand(String shellCommand, WaitStrategy waitStrategy, Integer... ports) { + protected GenericContainer startContainerWithCommand(String shellCommand, WaitStrategy waitStrategy, Integer... ports) { // apply WaitStrategy to container - return new GenericContainer(IMAGE_NAME) + return new GenericContainer<>(TestImages.ALPINE_IMAGE) .withExposedPorts(ports) .withCommand("sh", "-c", shellCommand) .waitingFor(waitStrategy.withStartupTimeout(Duration.ofMillis(WAIT_TIMEOUT_MILLIS))); @@ -98,7 +98,7 @@ protected void waitUntilReadyAndTimeout(String shellCommand) { * * @param container the container to start */ - protected void waitUntilReadyAndTimeout(GenericContainer container) { + protected void waitUntilReadyAndTimeout(GenericContainer container) { // start() blocks until successful or timeout VisibleAssertions.assertThrows("an exception is thrown when timeout occurs (" + WAIT_TIMEOUT_MILLIS + "ms)", ContainerLaunchException.class, @@ -111,7 +111,7 @@ protected void waitUntilReadyAndTimeout(GenericContainer container) { * * @param container the container to start */ - protected void waitUntilReadyAndSucceed(GenericContainer container) { + protected void waitUntilReadyAndSucceed(GenericContainer container) { // start() blocks until successful or timeout container.start(); diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java index d715b25aaf6..5c7d37a7da3 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java @@ -2,6 +2,7 @@ import org.junit.ClassRule; import org.junit.Test; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -15,10 +16,8 @@ */ public class HostPortWaitStrategyTest { - private static final String IMAGE_NAME = "alpine:3.7"; - @ClassRule - public static GenericContainer container = new GenericContainer(IMAGE_NAME).withExposedPorts() + public static GenericContainer container = new GenericContainer<>(TestImages.ALPINE_IMAGE).withExposedPorts() .withCommand("sh", "-c", "while true; do nc -lp 8080; done") .withExposedPorts(8080) .waitingFor(Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(10))); diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 3986255f248..0afb4d956a1 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; /** * This test checks the integration between Testcontainers and an authenticated registry, but uses @@ -45,7 +46,7 @@ public class AuthenticatedImagePullTest { @ClassRule public static GenericContainer authenticatedRegistry = new GenericContainer<>(new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { - builder.from("registry:2.7.0") + builder.from(DOCKER_REGISTRY_IMAGE.asCanonicalNameString()) .run("htpasswd -Bbn testuser notasecret > /htpasswd") .env("REGISTRY_AUTH", "htpasswd") .env("REGISTRY_AUTH_HTPASSWD_PATH", "/htpasswd") @@ -69,7 +70,7 @@ public static void setUp() throws InterruptedException { testImageName = testRegistryAddress + "/alpine"; testImageNameWithTag = testImageName + ":latest"; - final DockerImageName expectedName = new DockerImageName(testImageNameWithTag); + final DockerImageName expectedName = DockerImageName.parse(testImageNameWithTag); final AuthConfig authConfig = new AuthConfig() .withUsername("testuser") .withPassword("notasecret") @@ -99,7 +100,7 @@ public static void tearDown() { @Test public void testThatAuthLocatorIsUsedForContainerCreation() { // actually start a container, which will require an authenticated pull - try (final GenericContainer container = new GenericContainer<>(testImageNameWithTag) + try (final GenericContainer container = new GenericContainer<>(DockerImageName.parse(testImageNameWithTag)) .withCommand("/bin/sh", "-c", "sleep 10")) { container.start(); @@ -165,7 +166,7 @@ private Path getLocalTempFile(String s) throws IOException { private static void putImageInRegistry() throws InterruptedException { // It doesn't matter which image we use for this test, but use one that's likely to have been pulled already - final String dummySourceImage = TestcontainersConfiguration.getInstance().getRyukImage(); + final String dummySourceImage = TestcontainersConfiguration.getInstance().getRyukDockerImageName().asCanonicalNameString(); client.pullImageCmd(dummySourceImage) .exec(new PullImageResultCallback()) diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index 54488773652..b0ed9428a5d 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -35,7 +35,7 @@ public static String[] getNames() { @Test public void testValidNameAccepted() { - new DockerImageName(imageName).assertValid(); + DockerImageName.parse(imageName).assertValid(); } } @@ -56,7 +56,7 @@ public static String[] getNames() { @Test(expected = IllegalArgumentException.class) public void testInvalidNameRejected() { - new DockerImageName(imageName).assertValid(); + DockerImageName.parse(imageName).assertValid(); } } @@ -66,12 +66,18 @@ public static class Parsing { @Parameterized.Parameters(name = "{0}{1}{2}{3}{4}") public static String[][] getNames() { return new String[][]{ + {"", "", "myname", ":", null}, {"", "", "myname", ":", "latest"}, + {"", "", "repo/myname", ":", null}, {"", "", "repo/myname", ":", "latest"}, + {"registry.foo.com:1234", "/", "my-name", ":", null}, {"registry.foo.com:1234", "/", "my-name", ":", "1.0"}, {"registry.foo.com", "/", "my-name", ":", "1.0"}, + {"registry.foo.com:1234", "/", "repo_here/my-name", ":", null}, {"registry.foo.com:1234", "/", "repo_here/my-name", ":", "1.0"}, + {"1.2.3.4:1234", "/", "repo_here/my-name", ":", null}, {"1.2.3.4:1234", "/", "repo_here/my-name", ":", "1.0"}, + {"1.2.3.4:1234", "/", "my-name", ":", null}, {"1.2.3.4:1234", "/", "my-name", ":", "1.0"}, {"", "", "myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, {"", "", "repo/myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, @@ -98,22 +104,38 @@ public static String[][] getNames() { @Test public void testParsing() { final String unversionedPart = registry + registrySeparator + repo; - final String combined = unversionedPart + versionSeparator + version; + + String combined; + String canonicalName; + if (version != null) { + combined = unversionedPart + versionSeparator + version; + canonicalName = unversionedPart + versionSeparator + version; + } else { + combined = unversionedPart; + canonicalName = unversionedPart + ":latest"; + } VisibleAssertions.context("For " + combined); VisibleAssertions.context("Using single-arg constructor:", 2); - final DockerImageName imageName = new DockerImageName(combined); + final DockerImageName imageName = DockerImageName.parse(combined); assertEquals(combined + " has registry address: " + registry, registry, imageName.getRegistry()); assertEquals(combined + " has unversioned part: " + unversionedPart, unversionedPart, imageName.getUnversionedPart()); - assertEquals(combined + " has version part: " + version, version, imageName.getVersionPart()); - - VisibleAssertions.context("Using two-arg constructor:", 2); - - final DockerImageName imageNameFromSecondaryConstructor = new DockerImageName(unversionedPart, version); - assertEquals(combined + " has registry address: " + registry, registry, imageNameFromSecondaryConstructor.getRegistry()); - assertEquals(combined + " has unversioned part: " + unversionedPart, unversionedPart, imageNameFromSecondaryConstructor.getUnversionedPart()); - assertEquals(combined + " has version part: " + version, version, imageNameFromSecondaryConstructor.getVersionPart()); + if (version != null) { + assertEquals(combined + " has version part: " + version, version, imageName.getVersionPart()); + } else { + assertEquals(combined + " has implicit version: latest", "latest", imageName.getVersionPart()); + } + assertEquals(combined + " has canonical name: " + canonicalName, canonicalName, imageName.asCanonicalNameString()); + + if (version != null) { + VisibleAssertions.context("Using two-arg constructor:", 2); + + final DockerImageName imageNameFromSecondaryConstructor = new DockerImageName(unversionedPart, version); + assertEquals(combined + " has registry address: " + registry, registry, imageNameFromSecondaryConstructor.getRegistry()); + assertEquals(combined + " has unversioned part: " + unversionedPart, unversionedPart, imageNameFromSecondaryConstructor.getUnversionedPart()); + assertEquals(combined + " has version part: " + version, version, imageNameFromSecondaryConstructor.getVersionPart()); + } } } } diff --git a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java index e1cb595e903..a5e5ab4260d 100644 --- a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java +++ b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java @@ -18,7 +18,7 @@ public class RegistryAuthLocatorTest { public void lookupAuthConfigWithoutCredentials() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-empty.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("unauthenticated.registry.org/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("unauthenticated.registry.org/org/repo"), new AuthConfig()); assertEquals("Default docker registry URL is set on auth config", "https://index.docker.io/v1/", authConfig.getRegistryAddress()); assertNull("No username is set", authConfig.getUsername()); @@ -29,7 +29,7 @@ public void lookupAuthConfigWithoutCredentials() throws URISyntaxException { public void lookupAuthConfigWithBasicAuthCredentials() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-basic-auth.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); assertEquals("Default docker registry URL is set on auth config", "https://registry.example.com", authConfig.getRegistryAddress()); assertEquals("Username is set", "user", authConfig.getUsername()); @@ -40,7 +40,7 @@ public void lookupAuthConfigWithBasicAuthCredentials() throws URISyntaxException public void lookupAuthConfigWithJsonKeyCredentials() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-json-key.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); assertEquals("Default docker registry URL is set on auth config", "https://registry.example.com", authConfig.getRegistryAddress()); assertEquals("Username is set", "_json_key", authConfig.getUsername()); @@ -51,7 +51,7 @@ public void lookupAuthConfigWithJsonKeyCredentials() throws URISyntaxException { public void lookupAuthConfigUsingStore() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-store.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); @@ -62,7 +62,7 @@ public void lookupAuthConfigUsingStore() throws URISyntaxException { public void lookupAuthConfigUsingHelper() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-helper.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); @@ -73,7 +73,7 @@ public void lookupAuthConfigUsingHelper() throws URISyntaxException { public void lookupAuthConfigUsingHelperWithToken() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-helper-using-token.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registrytoken.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registrytoken.example.com/org/repo"), new AuthConfig()); assertEquals("Correct identitytoken is obtained from a credential store", "secret", authConfig.getIdentitytoken()); } @@ -82,7 +82,7 @@ public void lookupAuthConfigUsingHelperWithToken() throws URISyntaxException { public void lookupUsingHelperEmptyAuth() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-empty-auth-with-helper.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); @@ -93,7 +93,7 @@ public void lookupUsingHelperEmptyAuth() throws URISyntaxException { public void lookupNonEmptyAuthWithHelper() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-existing-auth-with-helper.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(new DockerImageName("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); assertEquals("Correct server URL is obtained from a credential helper", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential helper", "username", authConfig.getUsername()); @@ -105,7 +105,7 @@ public void lookupAuthConfigWithCredentialsNotFound() throws URISyntaxException Map notFoundMessagesReference = new HashMap<>(); final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-store.json", notFoundMessagesReference); - DockerImageName dockerImageName = new DockerImageName("registry2.example.com/org/repo"); + DockerImageName dockerImageName = DockerImageName.parse("registry2.example.com/org/repo"); final AuthConfig authConfig = authLocator.lookupAuthConfig(dockerImageName, new AuthConfig()); assertNull("No username should have been obtained from a credential store", authConfig.getUsername()); @@ -124,7 +124,7 @@ public void lookupAuthConfigWithCredentialsNotFound() throws URISyntaxException public void lookupAuthConfigWithCredStoreEmpty() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-store-empty.json"); - DockerImageName dockerImageName = new DockerImageName("registry2.example.com/org/repo"); + DockerImageName dockerImageName = DockerImageName.parse("registry2.example.com/org/repo"); final AuthConfig authConfig = authLocator.lookupAuthConfig(dockerImageName, new AuthConfig()); assertNull("CredStore field will be ignored, because value is blank", authConfig.getAuth()); diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index 172a821b178..f49e6a26565 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import java.io.IOException; @@ -13,7 +14,7 @@ public class CmdModifierTest { // hostname { @Rule - public GenericContainer theCache = new GenericContainer<>("redis:3.0.2") + public GenericContainer theCache = new GenericContainer<>(DockerImageName.parse("redis:3.0.2")) .withCreateContainerCmdModifier(cmd -> cmd.withHostName("the-cache")); // } @@ -22,7 +23,7 @@ public class CmdModifierTest { private long memorySwapInBytes = 12 * 1024 * 1024; @Rule - public GenericContainer memoryLimitedRedis = new GenericContainer<>("redis:3.0.2") + public GenericContainer memoryLimitedRedis = new GenericContainer<>(DockerImageName.parse("redis:3.0.2")) .withCreateContainerCmdModifier(cmd -> cmd.getHostConfig() .withMemory(memoryInBytes) .withMemorySwap(memorySwapInBytes) diff --git a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java b/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java index 486464c7dda..23b265c26fa 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java @@ -3,13 +3,14 @@ import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import static org.junit.Assert.assertTrue; public class CommandsTest { @Rule // startupCommand { - public GenericContainer redisWithCustomPort = new GenericContainer("redis:5.0") + public GenericContainer redisWithCustomPort = new GenericContainer(DockerImageName.parse("redis:5.0")) .withCommand("redis-server --port 7777") // } .withExposedPorts(7777); diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java index 19a40a7c43a..b0e8c98a0e4 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java @@ -3,28 +3,35 @@ import org.junit.ClassRule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import static org.junit.Assert.assertTrue; public class ContainerCreationTest { + // simple { + public static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:3.0.2"); + // } + // simple { @ClassRule - public static GenericContainer redis = - new GenericContainer("redis:3.0.2") + public static GenericContainer redis = + new GenericContainer<>(REDIS_IMAGE) .withExposedPorts(6379); // } + public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.2"); + // withOptions { - // Set up a plain OS container and customize environment, - // command and exposed ports. This just listens on port 80 + // Set up a plain OS container and customize environment, + // command and exposed ports. This just listens on port 80 // and always returns '42' @ClassRule - public static GenericContainer alpine = - new GenericContainer("alpine:3.2") + public static GenericContainer alpine = + new GenericContainer<>(ALPINE_IMAGE) .withExposedPorts(80) .withEnv("MAGIC_NUMBER", "42") - .withCommand("/bin/sh", "-c", + .withCommand("/bin/sh", "-c", "while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"); // } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java index f8f26eaa5fe..ca0878e89d4 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java @@ -1,13 +1,14 @@ package generic; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import java.util.HashMap; import java.util.Map; public class ContainerLabelTest { // single_label { - public GenericContainer containerWithLabel = new GenericContainer("alpine:3.6") + public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.6")) .withLabel("key", "value"); // } @@ -16,7 +17,7 @@ public class ContainerLabelTest { private Map mapOfLabels = new HashMap<>(); // populate map, e.g. mapOfLabels.put("key1", "value1"); - public GenericContainer containerWithMultipleLabels = new GenericContainer("alpine:3.6") + public GenericContainer containerWithMultipleLabels = new GenericContainer(DockerImageName.parse("alpine:3.6")) .withLabels(mapOfLabels); // } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java index e160390c293..e35ae18af70 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import java.io.IOException; @@ -12,7 +13,7 @@ public class ExecTest { @Rule - public GenericContainer container = new GenericContainer("alpine:3.6") + public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.6")) .withCommand("top"); @Test diff --git a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java index f5a92423b6c..329fd8d8e19 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.utility.DockerImageName; import static org.slf4j.LoggerFactory.getLogger; @@ -14,7 +15,7 @@ public class MultiplePortsExposedTest { @Rule // rule { - public GenericContainer container = new GenericContainer("orientdb:3.0.13") + public GenericContainer container = new GenericContainer(DockerImageName.parse("orientdb:3.0.13")) .withExposedPorts(2424, 2480) .withLogConsumer(new Slf4jLogConsumer(log)); // } diff --git a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java b/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java index 0bb5eb40bc1..d45b1e28c47 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java @@ -6,6 +6,7 @@ import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.utility.DockerImageName; import static org.junit.Assert.assertTrue; @@ -13,20 +14,20 @@ public class WaitStrategiesTest { @Rule // waitForNetworkListening { - public GenericContainer nginx = new GenericContainer("nginx:1.9.4") + public GenericContainer nginx = new GenericContainer(DockerImageName.parse("nginx:1.9.4")) .withExposedPorts(80); // } @Rule // waitForSimpleHttp { - public GenericContainer nginxWithHttpWait = new GenericContainer("nginx:1.9.4") + public GenericContainer nginxWithHttpWait = new GenericContainer(DockerImageName.parse("nginx:1.9.4")) .withExposedPorts(80) .waitingFor(Wait.forHttp("/")); // } @Rule // logMessageWait { - public GenericContainer containerWithLogWait = new GenericContainer("redis:5.0.3") + public GenericContainer containerWithLogWait = new GenericContainer(DockerImageName.parse("redis:5.0.3")) .withExposedPorts(6379) .waitingFor( Wait.forLogMessage(".*Ready to accept connections.*\\n", 1) diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java index deef64bc59b..0e72efb5723 100644 --- a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java +++ b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java @@ -7,6 +7,7 @@ import org.junit.runners.Suite; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.WaitingConsumer; +import org.testcontainers.utility.DockerImageName; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -35,7 +36,7 @@ private static void waitForHello(GenericContainer container) throws TimeoutExcep public static class OneShotStrategyTest { @Rule // withOneShotStrategy { - public GenericContainer bboxWithOneShot = new GenericContainer("busybox:1.31.1") + public GenericContainer bboxWithOneShot = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) .withCommand(String.format("echo %s", HELLO_TESTCONTAINERS)) .withStartupCheckStrategy( new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(3)) @@ -54,7 +55,7 @@ public void testCommandIsExecuted() { public static class IndefiniteOneShotStrategyTest { @Rule // withIndefiniteOneShotStrategy { - public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer("busybox:1.31.1") + public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) .withStartupCheckStrategy( new IndefiniteWaitOneShotStartupCheckStrategy() @@ -73,7 +74,7 @@ public void testCommandIsExecuted() { public static class MinimumDurationStrategyTest { @Rule // withMinimumDurationStrategy { - public GenericContainer bboxWithMinimumDuration = new GenericContainer("busybox:1.31.1") + public GenericContainer bboxWithMinimumDuration = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) .withStartupCheckStrategy( new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(1)) diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index f2ef1ab0220..cbb49b5fdb3 100644 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -5,6 +5,7 @@ import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import static org.junit.Assert.assertEquals; @@ -14,7 +15,7 @@ public class RedisBackedCacheIntTest { // rule { @Rule - public GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") + public GenericContainer redis = new GenericContainer(DockerImageName.parse("redis:5.0.3-alpine")) .withExposedPorts(6379); // } diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index 0f4f98fb669..9a3855ba23c 100644 --- a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -6,6 +6,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -17,7 +18,7 @@ public class RedisBackedCacheIntTest { // container { @Container - public GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") + public GenericContainer redis = new GenericContainer(DockerImageName.parse("redis:5.0.3-alpine")) .withExposedPorts(6379); // } diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index e92f20e71cd..443e04f1a91 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -12,9 +12,23 @@ images as temporary test dependencies. For example, if you might use it to test With a generic container, you set the container image using a parameter to the rule constructor, e.g.: ```java -new GenericContainer("jboss/wildfly:9.0.1.Final") +new GenericContainer(DockerImageName.parse("jboss/wildfly:9.0.1.Final")) ``` +### Specifying an image + +Many Container classes in Testcontainers have historically supported: + +* a no-args constructor - for example `new GenericContainer()` and `new ElasticsearchContainer()`. With these constructors, Testcontainers has traditionally used a default image name (including a fixed image tag/version). This has caused a conflict between the need to keep the defaults sane (i.e. up to date) and the need to avoid silently upgrading these dependencies along with new versions of Testcontainers. +* a single string-argument constructor, which has taken either a version or an image name as a String. This has caused some ambiguity and confusion. + +Since v1.15.0, both of these constructor types have been deprecated, for the reasons given above. + +Instead, it is highly recommended that _all containers_ be constructed using a constructor that accepts a `DockerImageName` object. +The `DockerImageName` class is an unambiguous reference to a docker image. + +It is suggested that developers treat `DockerImageName`s as you would any other potentially-constant value - consider defining a constant in your test codebase that matches the production version of the dependency you are using. + ### Examples A generic container rule can be used with any public docker image; for example: diff --git a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java b/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java index 5c78b3fdbd0..add59fd15ba 100644 --- a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java +++ b/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java @@ -4,10 +4,17 @@ import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.context; +import static org.rnorth.visibleassertions.VisibleAssertions.info; /** * Created by rnorth on 03/01/2016. @@ -15,7 +22,7 @@ public class DisqueBackedMailSenderTest { @Rule - public GenericContainer container = new GenericContainer("richnorth/disque:1.0-rc1") + public GenericContainer container = new GenericContainer<>(DockerImageName.parse("richnorth/disque:1.0-rc1")) .withExposedPorts(7711); private DisqueClient disqueClient; diff --git a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java b/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java index 8137f8fae90..3fa115bea20 100644 --- a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java +++ b/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java @@ -7,10 +7,14 @@ import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import java.util.concurrent.TimeUnit; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; +import static org.rnorth.visibleassertions.VisibleAssertions.context; +import static org.rnorth.visibleassertions.VisibleAssertions.info; /** * Created by rnorth on 03/01/2016. @@ -18,7 +22,7 @@ public class SingleDisqueInstanceTest { @Rule - public GenericContainer container = new GenericContainer("richnorth/disque:1.0-rc1") + public GenericContainer container = new GenericContainer<>(DockerImageName.parse("richnorth/disque:1.0-rc1")) .withExposedPorts(7711); private DisqueCommands connection; private AddJobArgs retryAfter1Second; diff --git a/examples/gradle/wrapper/gradle-wrapper.jar b/examples/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a GIT binary patch literal 58910 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 literal 0 HcmV?d00001 diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..622ab64a3cb --- /dev/null +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/gradlew b/examples/gradlew index 56f7b0fc7bf..fbd7c515832 100755 --- a/examples/gradlew +++ b/examples/gradlew @@ -80,7 +80,8 @@ case "`uname`" in ;; esac -CLASSPATH=$APP_HOME/../gradle/wrapper/gradle-wrapper.jar +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/examples/gradlew.bat b/examples/gradlew.bat index f3a074d99d4..5093609d512 100644 --- a/examples/gradlew.bat +++ b/examples/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -79,7 +82,8 @@ set CMD_LINE_ARGS=%* :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\..\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/LinkedContainerTestImages.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/LinkedContainerTestImages.java new file mode 100644 index 00000000000..8bbbafd189f --- /dev/null +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/LinkedContainerTestImages.java @@ -0,0 +1,8 @@ +package com.example.linkedcontainer; + +import org.testcontainers.utility.DockerImageName; + +public interface LinkedContainerTestImages { + DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12"); + DockerImageName REDMINE_TEST_IMAGE = DockerImageName.parse("redmine:3.3.2"); +} diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java index 82275dcc71c..b84b2a9e2c9 100644 --- a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java @@ -15,11 +15,11 @@ public class RedmineClientTest { private static final String POSTGRES_USERNAME = "redmine"; private static final String POSTGRES_PASSWORD = "secret"; - private PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.2") + private PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer<>(LinkedContainerTestImages.POSTGRES_TEST_IMAGE) .withUsername(POSTGRES_USERNAME) .withPassword(POSTGRES_PASSWORD); - private RedmineContainer redmineContainer = new RedmineContainer("redmine:3.3.2") + private RedmineContainer redmineContainer = new RedmineContainer(LinkedContainerTestImages.REDMINE_TEST_IMAGE) .withLinkToContainer(postgreSQLContainer, "postgres") .withEnv("POSTGRES_ENV_POSTGRES_USER", POSTGRES_USERNAME) .withEnv("POSTGRES_ENV_POSTGRES_PASSWORD", POSTGRES_PASSWORD); diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java index 113d0a76ec0..a75867205ab 100644 --- a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java @@ -3,6 +3,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; /** * A Redmine container. @@ -11,7 +12,7 @@ public class RedmineContainer extends GenericContainer { private static final int REDMINE_PORT = 3000; - public RedmineContainer(String dockerImageName) { + public RedmineContainer(DockerImageName dockerImageName) { super(dockerImageName); } diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java index 00fd9c05b52..e44f2bb982e 100644 --- a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java +++ b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import org.jetbrains.annotations.NotNull; +import org.testcontainers.utility.DockerImageName; /** @@ -24,7 +25,9 @@ public class MongoDbContainer extends GenericContainer { /** * Creates a new {@link MongoDbContainer} with the {@value DEFAULT_IMAGE_AND_TAG} image. + * @deprecated use {@link MongoDbContainer(DockerImageName)} instead */ + @Deprecated public MongoDbContainer() { this(DEFAULT_IMAGE_AND_TAG); } @@ -33,9 +36,18 @@ public MongoDbContainer() { * Creates a new {@link MongoDbContainer} with the given {@code 'image'}. * * @param image the image (e.g. {@value DEFAULT_IMAGE_AND_TAG}) to use + * @deprecated use {@link MongoDbContainer(DockerImageName)} instead */ + @Deprecated public MongoDbContainer(@NotNull String image) { - super(image); + this(DockerImageName.parse(image)); + } + + /** + * Creates a new {@link MongoDbContainer} with the specified image. + */ + public MongoDbContainer(final DockerImageName dockerImageName) { + super(dockerImageName); addExposedPort(MONGODB_PORT); } diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java index 96096d51c1a..7c87e46bccd 100644 --- a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java +++ b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java @@ -1,16 +1,17 @@ package org.testcontainers.containers; +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + import java.io.IOException; import java.net.Socket; -import org.junit.Test; - public class MongoDbContainerTest { @Test public void containerStartsAndPublicPortIsAvailable() { - try (MongoDbContainer container = new MongoDbContainer()) { + try (MongoDbContainer container = new MongoDbContainer(DockerImageName.parse("mongo:4.0"))) { container.start(); assertThatPortIsAvailable(container); } diff --git a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java index ad2d62a2f04..5d204cf99c4 100644 --- a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java @@ -1,6 +1,7 @@ import com.mycompany.cache.Cache; import com.mycompany.cache.RedisBackedCache; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; @@ -9,14 +10,16 @@ import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** * Integration test for Redis-backed cache implementation. */ public class RedisBackedCacheTest { - private static GenericContainer redis = new GenericContainer("redis:3.0.6").withExposedPorts(6379); + private static GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3.0.6")).withExposedPorts(6379); private Cache cache; diff --git a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java index eaff293e518..d9d93b8255e 100644 --- a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java @@ -4,11 +4,14 @@ import org.junit.Rule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import redis.clients.jedis.Jedis; import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** * Integration test for Redis-backed cache implementation. @@ -16,7 +19,7 @@ public class RedisBackedCacheTest { @Rule - public GenericContainer redis = new GenericContainer("redis:3.0.6") + public GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3.0.6")) .withExposedPorts(6379); private Cache cache; diff --git a/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java b/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java index d779adc5630..d152540fb1c 100644 --- a/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java +++ b/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java @@ -1,10 +1,11 @@ package com.example; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; public abstract class AbstractIntegrationTest { - public static final GenericContainer redis = new GenericContainer("redis:3.0.6") + public static final GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3.0.6")) .withExposedPorts(6379); static { diff --git a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java index 413d7937853..63ac67ac1cd 100644 --- a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java +++ b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java @@ -1,13 +1,5 @@ package com.example; -import static com.example.SolrSearchEngine.COLLECTION_NAME; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.Http2SolrClient; @@ -16,10 +8,21 @@ import org.junit.BeforeClass; import org.junit.Test; import org.testcontainers.containers.SolrContainer; +import org.testcontainers.utility.DockerImageName; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.example.SolrSearchEngine.COLLECTION_NAME; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class SolrQueryTest { - public static final SolrContainer solrContainer = new SolrContainer() + private static final DockerImageName SOLR_IMAGE = DockerImageName.parse("solr:8.3.0"); + + public static final SolrContainer solrContainer = new SolrContainer(SOLR_IMAGE) .withCollection(COLLECTION_NAME); private static SolrClient solrClient; diff --git a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java index 79828923d7d..b6859563c69 100644 --- a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java +++ b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java @@ -8,6 +8,7 @@ import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT, properties = { @@ -16,7 +17,7 @@ @ActiveProfiles("test") public abstract class AbstractIntegrationTest { - static GenericContainer redis = new GenericContainer("redis:3-alpine") + static GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3-alpine")) .withExposedPorts(6379); @DynamicPropertySource diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index 27c2f182e9e..681c58f4efb 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -7,6 +7,7 @@ import org.testcontainers.delegate.DatabaseDelegate; import org.testcontainers.ext.ScriptUtils; import org.testcontainers.ext.ScriptUtils.ScriptLoadException; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; import javax.script.ScriptException; @@ -24,7 +25,9 @@ */ public class CassandraContainer> extends GenericContainer { + @Deprecated public static final String IMAGE = "cassandra"; + public static final Integer CQL_PORT = 9042; private static final String CONTAINER_CONFIG_LOCATION = "/etc/cassandra"; private static final String USERNAME = "cassandra"; @@ -34,11 +37,23 @@ public class CassandraContainer> extends G private String initScriptPath; private boolean enableJmxReporting; + /** + * @deprecated use {@link #CassandraContainer(DockerImageName)} instead + */ + @Deprecated public CassandraContainer() { - this(IMAGE + ":3.11.2"); + this("cassandra:3.11.2"); } + /** + * @deprecated use {@link #CassandraContainer(DockerImageName)} instead + */ + @Deprecated public CassandraContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public CassandraContainer(DockerImageName dockerImageName) { super(dockerImageName); addExposedPort(CQL_PORT); setStartupAttempts(3); diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java index 5bc68aa9972..76c8c8438d7 100644 --- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java @@ -7,8 +7,11 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.testcontainers.containers.wait.CassandraQueryWaitStrategy; +import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * @author Eugeny Karpov @@ -16,11 +19,13 @@ @Slf4j public class CassandraContainerTest { + private static final DockerImageName CASSANDRA_IMAGE = DockerImageName.parse("cassandra:3.11.2"); + private static final String TEST_CLUSTER_NAME_IN_CONF = "Test Cluster Integration Test"; @Test public void testSimple() { - try (CassandraContainer cassandraContainer = new CassandraContainer<>()) { + try (CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE)) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, "SELECT release_version FROM system.local"); assertTrue("Query was not applied", resultSet.wasApplied()); @@ -31,7 +36,7 @@ public void testSimple() { @Test public void testSpecificVersion() { String cassandraVersion = "3.0.15"; - try (CassandraContainer cassandraContainer = new CassandraContainer<>("cassandra:" + cassandraVersion)) { + try (CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE.withTag(cassandraVersion))) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, "SELECT release_version FROM system.local"); assertTrue("Query was not applied", resultSet.wasApplied()); @@ -42,7 +47,7 @@ public void testSpecificVersion() { @Test public void testConfigurationOverride() { try ( - CassandraContainer cassandraContainer = new CassandraContainer<>() + CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE) .withConfigurationOverride("cassandra-test-configuration-example") ) { cassandraContainer.start(); @@ -55,7 +60,7 @@ public void testConfigurationOverride() { @Test(expected = ContainerLaunchException.class) public void testEmptyConfigurationOverride() { try ( - CassandraContainer cassandraContainer = new CassandraContainer<>() + CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE) .withConfigurationOverride("cassandra-empty-configuration") ) { cassandraContainer.start(); @@ -65,7 +70,7 @@ public void testEmptyConfigurationOverride() { @Test public void testInitScript() { try ( - CassandraContainer cassandraContainer = new CassandraContainer<>() + CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE) .withInitScript("initial.cql") ) { cassandraContainer.start(); @@ -76,7 +81,7 @@ public void testInitScript() { @Test public void testInitScriptWithLegacyCassandra() { try ( - CassandraContainer cassandraContainer = new CassandraContainer<>("cassandra:2.2.11") + CassandraContainer cassandraContainer = new CassandraContainer<>(DockerImageName.parse("cassandra:2.2.11")) .withInitScript("initial.cql") ) { cassandraContainer.start(); @@ -84,10 +89,11 @@ public void testInitScriptWithLegacyCassandra() { } } + @SuppressWarnings("deprecation") // Using deprecated constructor for verification of backwards compatibility @Test public void testCassandraQueryWaitStrategy() { try ( - CassandraContainer cassandraContainer = new CassandraContainer<>() + CassandraContainer cassandraContainer = new CassandraContainer<>() .waitingFor(new CassandraQueryWaitStrategy()) ) { cassandraContainer.start(); @@ -96,9 +102,10 @@ public void testCassandraQueryWaitStrategy() { } } + @SuppressWarnings("deprecation") // Using deprecated constructor for verification of backwards compatibility @Test public void testCassandraGetCluster() { - try (CassandraContainer cassandraContainer = new CassandraContainer<>()) { + try (CassandraContainer cassandraContainer = new CassandraContainer<>()) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer.getCluster(), "SELECT release_version FROM system.local"); assertTrue("Query was not applied", resultSet.wasApplied()); @@ -106,7 +113,7 @@ public void testCassandraGetCluster() { } } - private void testInitScript(CassandraContainer cassandraContainer) { + private void testInitScript(CassandraContainer cassandraContainer) { ResultSet resultSet = performQuery(cassandraContainer, "SELECT * FROM keySpaceTest.catalog_category"); assertTrue("Query was not applied", resultSet.wasApplied()); Row row = resultSet.one(); @@ -114,7 +121,7 @@ private void testInitScript(CassandraContainer cassandraContainer) { assertEquals("Inserted row is not in expected state", "test_category", row.getString(1)); } - private ResultSet performQuery(CassandraContainer cassandraContainer, String cql) { + private ResultSet performQuery(CassandraContainer cassandraContainer, String cql) { Cluster explicitCluster = Cluster.builder() .addContactPoint(cassandraContainer.getHost()) .withPort(cassandraContainer.getMappedPort(CassandraContainer.CQL_PORT)) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index dd48f32bece..6bdcff7b3f2 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -1,12 +1,14 @@ package org.testcontainers.containers; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.utility.DockerImageName; import java.time.Duration; public class ClickHouseContainer extends JdbcDatabaseContainer { public static final String NAME = "clickhouse"; public static final String IMAGE = "yandex/clickhouse-server"; + @Deprecated public static final String DEFAULT_TAG = "18.10.3"; public static final Integer HTTP_PORT = 8123; @@ -20,11 +22,23 @@ public class ClickHouseContainer extends JdbcDatabaseContainer { private String username = "default"; private String password = ""; + /** + * @deprecated use {@link ClickHouseContainer(DockerImageName)} instead + */ + @Deprecated public ClickHouseContainer() { super(IMAGE + ":" + DEFAULT_TAG); } + /** + * @deprecated use {@link ClickHouseContainer(DockerImageName)} instead + */ + @Deprecated public ClickHouseContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public ClickHouseContainer(final DockerImageName dockerImageName) { super(dockerImageName); withExposedPorts(HTTP_PORT, NATIVE_PORT); diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java index be5a01657f0..cd2453b8349 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java @@ -1,5 +1,7 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; + public class ClickHouseProvider extends JdbcDatabaseContainerProvider { @Override public boolean supports(String databaseType) { @@ -8,6 +10,6 @@ public boolean supports(String databaseType) { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new ClickHouseContainer(ClickHouseContainer.IMAGE + ":" + tag); + return new ClickHouseContainer(DockerImageName.parse(ClickHouseContainer.IMAGE).withTag(tag)); } } diff --git a/modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java b/modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java new file mode 100644 index 00000000000..961df045bd1 --- /dev/null +++ b/modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface ClickhouseTestImages { + DockerImageName CLICKHOUSE_IMAGE = DockerImageName.parse("yandex/clickhouse-server:18.10.3"); +} diff --git a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java index 2dbce0b3593..8f3879673a0 100644 --- a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java +++ b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java @@ -8,12 +8,13 @@ import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.testcontainers.ClickhouseTestImages.CLICKHOUSE_IMAGE; public class SimpleClickhouseTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (ClickHouseContainer clickhouse = new ClickHouseContainer()) { + try (ClickHouseContainer clickhouse = new ClickHouseContainer(CLICKHOUSE_IMAGE)) { clickhouse.start(); ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index de64902c88a..54420155f05 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.utility.DockerImageName; import java.time.Duration; @@ -18,11 +19,23 @@ public class CockroachContainer extends JdbcDatabaseContainer { /** * Creates a new couchbase container with the default image and version. + * @deprecated use {@link CouchbaseContainer(DockerImageName)} instead */ + @Deprecated public CouchbaseContainer() { this(DOCKER_IMAGE_NAME + ":" + VERSION); } @@ -95,10 +98,20 @@ public CouchbaseContainer() { /** * Creates a new couchbase container with a custom image name. * - * @param imageName the image name that should be used. + * @param dockerImageName the image name that should be used. + * @deprecated use {@link CouchbaseContainer(DockerImageName)} instead */ - public CouchbaseContainer(final String imageName) { - super(imageName); + @Deprecated + public CouchbaseContainer(final String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + /** + * Create a new couchbase container with the specified image name. + * @param dockerImageName + */ + public CouchbaseContainer(final DockerImageName dockerImageName) { + super(dockerImageName); } /** diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index c5c9f18a58b..3a4438c1fc6 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -24,12 +24,15 @@ import com.couchbase.client.java.env.CouchbaseEnvironment; import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import org.junit.Test; +import org.testcontainers.utility.DockerImageName; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; public class CouchbaseContainerTest { + private static final DockerImageName COUCHBASE_IMAGE = DockerImageName.parse("couchbase/server:6.5.1"); + @Test public void testBasicContainerUsage() { // bucket_definition { @@ -38,7 +41,7 @@ public void testBasicContainerUsage() { try ( // container_definition { - CouchbaseContainer container = new CouchbaseContainer() + CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE) .withBucket(bucketDefinition) // } ) { diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index 05edcb2c3ed..aa6d136aaec 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.LicenseAcceptance; import java.time.Duration; @@ -19,12 +20,24 @@ public class Db2Container extends JdbcDatabaseContainer { private String username = "db2inst1"; private String password = "foobar1234"; + /** + * @deprecated use {@link Db2Container(DockerImageName)} instead + */ + @Deprecated public Db2Container() { this(DEFAULT_DB2_IMAGE_NAME + ":" + DEFAULT_TAG); } - public Db2Container(String imageName) { - super(imageName); + /** + * @deprecated use {@link Db2Container(DockerImageName)} instead + */ + @Deprecated + public Db2Container(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public Db2Container(final DockerImageName dockerImageName) { + super(dockerImageName); withPrivilegedMode(true); this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*Setup has completed\\..*") diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java index 5c78fdc0505..618b97c3ca6 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java @@ -1,5 +1,7 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; + public class Db2ContainerProvider extends JdbcDatabaseContainerProvider { @Override public boolean supports(String databaseType) { @@ -13,6 +15,6 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new Db2Container(Db2Container.DEFAULT_DB2_IMAGE_NAME + ":" + tag); + return new Db2Container(DockerImageName.parse(Db2Container.DEFAULT_DB2_IMAGE_NAME).withTag(tag)); } } diff --git a/modules/db2/src/test/java/org/testcontainers/Db2TestImages.java b/modules/db2/src/test/java/org/testcontainers/Db2TestImages.java new file mode 100644 index 00000000000..b0bfc869272 --- /dev/null +++ b/modules/db2/src/test/java/org/testcontainers/Db2TestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface Db2TestImages { + DockerImageName DB2_IMAGE = DockerImageName.parse("ibmcom/db2:11.5.0.0a"); +} diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java index 6cc7535f785..b7a1d5478e8 100644 --- a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -10,12 +10,13 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.testcontainers.Db2TestImages.DB2_IMAGE; public class SimpleDb2Test extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (Db2Container db2 = new Db2Container() + try (Db2Container db2 = new Db2Container(DB2_IMAGE) .acceptLicense()) { db2.start(); @@ -29,7 +30,7 @@ public void testSimple() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - try (Db2Container db2 = new Db2Container() + try (Db2Container db2 = new Db2Container(DB2_IMAGE) .withUrlParam("sslConnection", "false") .acceptLicense()) { diff --git a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java index 6280ddb9421..6063c1a5dbe 100644 --- a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java +++ b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java @@ -7,6 +7,7 @@ import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; /** * Container for Dynalite, a DynamoDB clone. @@ -16,15 +17,28 @@ public class DynaliteContainer extends GenericContainer { private static final String IMAGE_NAME = "quay.io/testcontainers/dynalite:v1.2.1-1"; private static final int MAPPED_PORT = 4567; + /** + * @deprecated use {@link DynaliteContainer(DockerImageName)} instead + */ + @Deprecated public DynaliteContainer() { this(IMAGE_NAME); withExposedPorts(MAPPED_PORT); } - public DynaliteContainer(String imageName) { - super(imageName); + /** + * @deprecated use {@link DynaliteContainer(DockerImageName)} instead + */ + @Deprecated + public DynaliteContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); } + public DynaliteContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + } + + /** * Gets a preconfigured {@link AmazonDynamoDB} client object for connecting to this * container. diff --git a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java index 524d3f6c34c..0b440939139 100644 --- a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java +++ b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java @@ -2,17 +2,26 @@ import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; -import com.amazonaws.services.dynamodbv2.model.*; +import com.amazonaws.services.dynamodbv2.model.AttributeDefinition; +import com.amazonaws.services.dynamodbv2.model.CreateTableRequest; +import com.amazonaws.services.dynamodbv2.model.KeySchemaElement; +import com.amazonaws.services.dynamodbv2.model.KeyType; +import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput; +import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType; +import com.amazonaws.services.dynamodbv2.model.TableDescription; import org.junit.Rule; import org.junit.Test; +import org.testcontainers.utility.DockerImageName; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; public class DynaliteContainerTest { + private static final DockerImageName DYNALITE_IMAGE = DockerImageName.parse("quay.io/testcontainers/dynalite:v1.2.1-1"); + @Rule - public DynaliteContainer dynamoDB = new DynaliteContainer(); + public DynaliteContainer dynamoDB = new DynaliteContainer(DYNALITE_IMAGE); @Test public void simpleTestWithManualClientCreation() { diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index e9a0b95d7ed..6ad0172269d 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -3,6 +3,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; import java.net.InetSocketAddress; import java.time.Duration; @@ -36,6 +37,10 @@ public class ElasticsearchContainer extends GenericContainer basic @@ -54,6 +59,7 @@ public void stopRestClient() throws IOException { } } + @SuppressWarnings("deprecation") // Using deprecated constructor for verification of backwards compatibility @Test public void elasticsearchDefaultTest() throws IOException { // Create the elasticsearch container. @@ -78,7 +84,7 @@ public void elasticsearchDefaultTest() throws IOException { @Test public void elasticsearchVersion() throws IOException { - try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)) { + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); assertThat(response.getStatusLine().getStatusCode(), is(200)); @@ -89,10 +95,14 @@ public void elasticsearchVersion() throws IOException { @Test public void elasticsearchOssImage() throws IOException { - try ( - // oosContainer { - ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:" + ELASTICSEARCH_VERSION) - // } + try (ElasticsearchContainer container = + // oosContainer { + new ElasticsearchContainer( + DockerImageName + .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") + .withTag(ELASTICSEARCH_VERSION) + ) + // } ) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); @@ -104,6 +114,7 @@ public void elasticsearchOssImage() throws IOException { } } + @SuppressWarnings("deprecation") // Using deprecated constructor for verification of backwards compatibility @Test public void restClientClusterHealth() throws IOException { // httpClientContainer { @@ -122,10 +133,10 @@ public void restClientClusterHealth() throws IOException { .build(); Response response = client.performRequest(new Request("GET", "/_cluster/health")); - // }} + // }} assertThat(response.getStatusLine().getStatusCode(), is(200)); assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); - // httpClientContainer {{ + // httpClientContainer {{ } // } } @@ -134,7 +145,11 @@ public void restClientClusterHealth() throws IOException { public void transportClientClusterHealth() { // transportClientContainer { // Create the elasticsearch container. - try (ElasticsearchContainer container = new ElasticsearchContainer()) { + try (ElasticsearchContainer container = new ElasticsearchContainer( + DockerImageName + .parse("docker.elastic.co/elasticsearch/elasticsearch") + .withTag("6.4.1") + )){ // Start the container. This step might take some time... container.start(); diff --git a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java index 68efc516504..5d883fea9a7 100644 --- a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java +++ b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java @@ -4,6 +4,7 @@ import org.influxdb.InfluxDBFactory; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; +import org.testcontainers.utility.DockerImageName; import java.util.Collections; import java.util.Set; @@ -26,13 +27,24 @@ public class InfluxDBContainer> extends Gen private String username = "any"; private String password = "any"; - + /** + * @deprecated use {@link InfluxDBContainer(DockerImageName)} instead + */ + @Deprecated public InfluxDBContainer() { this(VERSION); } + /** + * @deprecated use {@link InfluxDBContainer(DockerImageName)} instead + */ + @Deprecated public InfluxDBContainer(final String version) { - super(IMAGE_NAME + ":" + version); + this(DockerImageName.parse(IMAGE_NAME + ":" + version)); + } + + public InfluxDBContainer(final DockerImageName dockerImageName) { + super(dockerImageName); waitStrategy = new WaitAllStrategy() .withStrategy(Wait.forHttp("/ping").withBasicCredentials(username, password).forStatusCode(204)) .withStrategy(Wait.forListeningPort()); diff --git a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java index fa2e54fd0c9..7acf030b5e4 100644 --- a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java +++ b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java @@ -11,7 +11,7 @@ public class InfluxDBContainerTest { @ClassRule - public static InfluxDBContainer influxDBContainer = new InfluxDBContainer(); + public static InfluxDBContainer influxDBContainer = new InfluxDBContainer<>(InfluxDBTestImages.INFLUXDB_TEST_IMAGE); @Test public void getUrl() { diff --git a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java index 81ad62a7b47..b045ca297c1 100644 --- a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java +++ b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java @@ -17,13 +17,13 @@ public class InfluxDBContainerWithUserTest { - private static final String TEST_VERSION = "1.4.3"; + private static final String TEST_VERSION = InfluxDBTestImages.INFLUXDB_TEST_IMAGE.getVersionPart(); private static final String DATABASE = "test"; private static final String USER = "test-user"; private static final String PASSWORD = "test-password"; @Rule - public InfluxDBContainer influxDBContainer = new InfluxDBContainer(TEST_VERSION) + public InfluxDBContainer influxDBContainer = new InfluxDBContainer<>(InfluxDBTestImages.INFLUXDB_TEST_IMAGE) .withDatabase(DATABASE) .withUsername(USER) .withPassword(PASSWORD); diff --git a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBTestImages.java b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBTestImages.java new file mode 100644 index 00000000000..a0e2d31bbdf --- /dev/null +++ b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers.containers; + +import org.testcontainers.utility.DockerImageName; + +public interface InfluxDBTestImages { + DockerImageName INFLUXDB_TEST_IMAGE = DockerImageName.parse("influxdb:1.4.3"); +} diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 62fe43e7932..4d1c4ece67b 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -8,6 +8,7 @@ import org.testcontainers.delegate.DatabaseDelegate; import org.testcontainers.ext.ScriptUtils; import org.testcontainers.jdbc.JdbcDatabaseDelegate; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; import java.sql.Connection; @@ -38,14 +39,22 @@ public abstract class JdbcDatabaseContainer image) { super(image); } + public JdbcDatabaseContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + } + /** * @return the name of the actual JDBC driver to use */ diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java index 38ae38095eb..88398cebf85 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java @@ -3,6 +3,7 @@ import com.google.common.base.Throwables; import org.junit.Test; import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.utility.DockerImageName; import java.sql.Connection; import java.sql.SQLException; @@ -39,7 +40,7 @@ static class MissingDriverContainer extends JdbcDatabaseContainer { private final AtomicInteger connectionAttempts = new AtomicInteger(); MissingDriverContainer() { - super("mysql:5.7.22"); + super(DockerImageName.parse("mysql:5.7.22")); withEnv("MYSQL_ROOT_PASSWORD", "test"); withExposedPorts(3306); } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/JUnitJupiterTestImages.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/JUnitJupiterTestImages.java new file mode 100644 index 00000000000..e99d1ec720c --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/JUnitJupiterTestImages.java @@ -0,0 +1,8 @@ +package org.testcontainers.junit.jupiter; + +import org.testcontainers.utility.DockerImageName; + +public interface JUnitJupiterTestImages { + DockerImageName POSTGRES_IMAGE = DockerImageName.parse("postgres:9.6.12"); + DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine"); +} diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java index 765a9f6ff6b..4cbc331e64b 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java @@ -9,12 +9,13 @@ import java.sql.Statement; import static org.junit.Assert.assertEquals; +import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.POSTGRES_IMAGE; @Testcontainers class PostgresContainerTests { @Container - private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = new PostgreSQLContainer() + private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = new PostgreSQLContainer<>(POSTGRES_IMAGE) .withDatabaseName("foo") .withUsername("foo") .withPassword("secret"); diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java index fb753744425..6e02e31b774 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java @@ -4,16 +4,16 @@ import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; // testClass { @Testcontainers class TestcontainersNestedRestartedContainerTests { @Container - private final GenericContainer topLevelContainer = new GenericContainer("httpd:2.4-alpine") + private final GenericContainer topLevelContainer = new GenericContainer<>(HTTPD_IMAGE) .withExposedPorts(80); // }} @@ -34,7 +34,7 @@ void top_level_container_should_be_running() { class NestedTestCase { @Container - private final GenericContainer nestedContainer = new GenericContainer("httpd:2.4-alpine") + private final GenericContainer nestedContainer = new GenericContainer<>(HTTPD_IMAGE) .withExposedPorts(80); @Test diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java index 371a5bae178..cf59e0338a2 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java @@ -6,12 +6,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; @Testcontainers class TestcontainersNestedSharedContainerTests { @Container - private static final GenericContainer TOP_LEVEL_CONTAINER = new GenericContainer("httpd:2.4-alpine") + private static final GenericContainer TOP_LEVEL_CONTAINER = new GenericContainer<>(HTTPD_IMAGE) .withExposedPorts(80); private static String topLevelContainerId; diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java index 2d6959ae065..eeb63b72380 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java @@ -4,12 +4,13 @@ import org.testcontainers.containers.GenericContainer; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; @Testcontainers class TestcontainersRestartBetweenTests { @Container - private GenericContainer genericContainer = new GenericContainer("httpd:2.4-alpine") + private GenericContainer genericContainer = new GenericContainer<>(HTTPD_IMAGE) .withExposedPorts(80); private static String lastContainerId; diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java index 321c0d6282f..60094994f69 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java @@ -6,12 +6,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; @Testcontainers class TestcontainersSharedContainerTests { @Container - private static final GenericContainer GENERIC_CONTAINER = new GenericContainer("httpd:2.4-alpine") + private static final GenericContainer GENERIC_CONTAINER = new GenericContainer<>(HTTPD_IMAGE) .withExposedPorts(80); private static String lastContainerId; diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java index 177a48bb9d0..0a9ec62fca2 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/RedisContainer.java @@ -1,16 +1,13 @@ package org.testcontainers.junit.jupiter.inheritance; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; import redis.clients.jedis.Jedis; public class RedisContainer extends GenericContainer { public RedisContainer() { - this("redis:3.2.11"); - } - - public RedisContainer(String dockerImageName) { - super(dockerImageName); + super(DockerImageName.parse("redis:3.2.11")); withExposedPorts(6379); } diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 9746849be29..2451278b1c2 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -4,6 +4,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import lombok.SneakyThrows; import org.testcontainers.images.builder.Transferable; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.TestcontainersConfiguration; import java.nio.charset.StandardCharsets; @@ -29,12 +30,24 @@ public class KafkaContainer extends GenericContainer { private int port = PORT_NOT_ASSIGNED; + /** + * @deprecated use {@link KafkaContainer(DockerImageName)} instead + */ + @Deprecated public KafkaContainer() { this("5.2.1"); } + /** + * @deprecated use {@link KafkaContainer(DockerImageName)} instead + */ + @Deprecated public KafkaContainer(String confluentPlatformVersion) { - super(TestcontainersConfiguration.getInstance().getKafkaImage() + ":" + confluentPlatformVersion); + this(DockerImageName.parse(TestcontainersConfiguration.getInstance().getKafkaImage() + ":" + confluentPlatformVersion)); + } + + public KafkaContainer(final DockerImageName dockerImageName) { + super(dockerImageName); withExposedPorts(KAFKA_PORT); diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 25bc1b5022c..b8cd5c9be9c 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -13,6 +13,7 @@ import org.junit.Rule; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.utility.DockerImageName; import java.time.Duration; import java.util.Arrays; @@ -24,6 +25,9 @@ public class KafkaContainerTest { + private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:5.2.1"); + private static final DockerImageName ZOOKEEPER_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-zookeeper:4.0.0"); + // junitRule { @Rule public KafkaContainer kafka = new KafkaContainer(); @@ -31,7 +35,7 @@ public class KafkaContainerTest { @Test public void testUsage() throws Exception { - try (KafkaContainer kafka = new KafkaContainer()) { + try (KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE)) { kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); } @@ -42,7 +46,7 @@ public void testUsage() throws Exception { public void testUsageWithVersion() throws Exception { try ( // constructorWithVersion { - KafkaContainer kafka = new KafkaContainer("4.1.2") + KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE) // } ) { kafka.start(); @@ -60,12 +64,12 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { Network network = Network.newNetwork(); // withExternalZookeeper { - KafkaContainer kafka = new KafkaContainer() + KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE) .withNetwork(network) .withExternalZookeeper("zookeeper:2181"); // } - GenericContainer zookeeper = new GenericContainer("confluentinc/cp-zookeeper:4.0.0") + GenericContainer zookeeper = new GenericContainer<>(ZOOKEEPER_TEST_IMAGE) .withNetwork(network) .withNetworkAliases("zookeeper") .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 72eb320c729..0136d94e3b2 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -10,6 +10,7 @@ import org.rnorth.ducttape.Preconditions; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.TestcontainersConfiguration; import java.net.InetAddress; @@ -36,12 +37,24 @@ public class LocalStackContainer extends GenericContainer { private final List services = new ArrayList<>(); + /** + * @deprecated use {@link LocalStackContainer(DockerImageName)} instead + */ + @Deprecated public LocalStackContainer() { this(VERSION); } + /** + * @deprecated use {@link LocalStackContainer(DockerImageName)} instead + */ + @Deprecated public LocalStackContainer(String version) { - super(TestcontainersConfiguration.getInstance().getLocalStackImage() + ":" + version); + this(DockerImageName.parse(TestcontainersConfiguration.getInstance().getLocalStackImage() + ":" + version)); + } + + public LocalStackContainer(final DockerImageName dockerImageName) { + super(dockerImageName); withFileSystemBind("//var/run/docker.sock", "/var/run/docker.sock"); waitingFor(Wait.forLogMessage(".*Ready\\.\n", 1)); diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index d4e2f0c2864..63be9d66df7 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -29,6 +29,7 @@ import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.Network; +import org.testcontainers.utility.DockerImageName; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; @@ -43,7 +44,10 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.*; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCHLOGS; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.KMS; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; /** * Tests for Localstack Container, used both in bridge network (exposed to host) and docker network modes. @@ -56,11 +60,14 @@ @RunWith(Enclosed.class) public class LocalstackContainerTest { + private static final DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.10.8"); + private static final DockerImageName AWS_CLI_IMAGE = DockerImageName.parse("atlassian/pipelines-awscli:1.16.302"); + public static class WithoutNetwork { // without_network { @ClassRule - public static LocalStackContainer localstack = new LocalStackContainer() + public static LocalStackContainer localstack = new LocalStackContainer(LOCALSTACK_IMAGE) .withServices(S3, SQS, CLOUDWATCHLOGS, KMS); // } @@ -160,14 +167,14 @@ public static class WithNetwork { private static Network network = Network.newNetwork(); @ClassRule - public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer() + public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer(LOCALSTACK_IMAGE) .withNetwork(network) .withNetworkAliases("notthis", "localstack") // the last alias is used for HOSTNAME_EXTERNAL .withServices(S3, SQS, CLOUDWATCHLOGS); // } @ClassRule - public static GenericContainer awsCliInDockerNetwork = new GenericContainer<>("atlassian/pipelines-awscli") + public static GenericContainer awsCliInDockerNetwork = new GenericContainer<>(AWS_CLI_IMAGE) .withNetwork(network) .withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("top")) .withEnv("AWS_ACCESS_KEY_ID", "accesskey") diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index 04d745a9efe..e137c186209 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -1,5 +1,7 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; + /** * Container implementation for the MariaDB project. * @@ -22,11 +24,23 @@ public class MariaDBContainer> extends JdbcD private static final String MARIADB_ROOT_USER = "root"; private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF"; + /** + * @deprecated use {@link MariaDBContainer(DockerImageName)} instead + */ + @Deprecated public MariaDBContainer() { this(IMAGE + ":" + DEFAULT_TAG); } + /** + * @deprecated use {@link MariaDBContainer(DockerImageName)} instead + */ + @Deprecated public MariaDBContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public MariaDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); addExposedPort(MARIADB_PORT); } diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java index 86f30ee59e5..4330465a9c3 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java @@ -1,8 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.jdbc.ConnectionUrl; - -import java.util.Objects; +import org.testcontainers.utility.DockerImageName; /** * Factory for MariaDB org.testcontainers.containers. @@ -25,7 +24,7 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new MariaDBContainer(MariaDBContainer.IMAGE + ":" + tag); + return new MariaDBContainer(DockerImageName.parse(MariaDBContainer.IMAGE).withTag(tag)); } @Override diff --git a/modules/mariadb/src/test/java/org/testcontainers/MariaDBTestImages.java b/modules/mariadb/src/test/java/org/testcontainers/MariaDBTestImages.java new file mode 100644 index 00000000000..7d18f2f8365 --- /dev/null +++ b/modules/mariadb/src/test/java/org/testcontainers/MariaDBTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface MariaDBTestImages { + DockerImageName MARIADB_IMAGE = DockerImageName.parse("mariadb:10.3.6"); +} diff --git a/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java index 30e8cad9c32..b6fb4dd659e 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java @@ -2,6 +2,7 @@ import io.r2dbc.spi.ConnectionFactoryOptions; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; +import org.testcontainers.utility.DockerImageName; public class MariaDBR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { @@ -17,7 +18,7 @@ protected String createR2DBCUrl() { @Override protected MariaDBContainer createContainer() { - return new MariaDBContainer<>(); + return new MariaDBContainer<>(DockerImageName.parse("mariadb:10.3.6")); } } diff --git a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index af503ce424b..4ea98bbe1fe 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -13,13 +13,14 @@ import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.MariaDBTestImages.MARIADB_IMAGE; public class SimpleMariaDBTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (MariaDBContainer mariadb = new MariaDBContainer<>()) { + try (MariaDBContainer mariadb = new MariaDBContainer<>(MARIADB_IMAGE)) { mariadb.start(); @@ -32,7 +33,7 @@ public void testSimple() throws SQLException { @Test public void testSpecificVersion() throws SQLException { - try (MariaDBContainer mariadbOldVersion = new MariaDBContainer<>("mariadb:5.5.51")) { + try (MariaDBContainer mariadbOldVersion = new MariaDBContainer<>(MARIADB_IMAGE.withTag("5.5.51"))) { mariadbOldVersion.start(); @@ -47,7 +48,7 @@ public void testSpecificVersion() throws SQLException { public void testMariaDBWithCustomIniFile() throws SQLException { assumeFalse(SystemUtils.IS_OS_WINDOWS); - try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>("mariadb:10.1.16") + try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>(MARIADB_IMAGE.withTag("10.1.16")) .withConfigurationOverride("somepath/mariadb_conf_override")) { mariadbCustomConfig.start(); @@ -61,7 +62,7 @@ public void testMariaDBWithCustomIniFile() throws SQLException { @Test public void testMariaDBWithCommandOverride() throws SQLException { - try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>("mariadb:10.1.16") + try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>(MARIADB_IMAGE) .withCommand("mysqld --auto_increment_increment=10")) { mariadbCustomConfig.start(); ResultSet resultSet = performQuery(mariadbCustomConfig, "show variables like 'auto_increment_increment'"); @@ -73,7 +74,7 @@ public void testMariaDBWithCommandOverride() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - MariaDBContainer mariaDBContainer = (MariaDBContainer) new MariaDBContainer() + MariaDBContainer mariaDBContainer = new MariaDBContainer<>(MARIADB_IMAGE) .withUrlParam("connectTimeout", "40000") .withUrlParam("rewriteBatchedStatements", "true"); diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index e35370f4b27..2aa33931d07 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import lombok.extern.slf4j.Slf4j; +import org.testcontainers.utility.DockerImageName; @Slf4j public class MockServerContainer extends GenericContainer { @@ -9,12 +10,24 @@ public class MockServerContainer extends GenericContainer { public static final int PORT = 1080; + /** + * @deprecated use {@link MockServerContainer(DockerImageName)} instead + */ + @Deprecated public MockServerContainer() { this(VERSION); } + /** + * @deprecated use {@link MockServerContainer(DockerImageName)} instead + */ + @Deprecated public MockServerContainer(String version) { - super("jamesdbloom/mockserver:mockserver-" + version); + this(DockerImageName.parse("jamesdbloom/mockserver:mockserver-" + version)); + } + + public MockServerContainer(DockerImageName dockerImageName) { + super(dockerImageName); withCommand("-logLevel INFO -serverPort " + PORT); addExposedPorts(PORT); } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index 91f740b4bd8..e4d11ed3f39 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -4,6 +4,7 @@ import org.junit.Rule; import org.junit.Test; import org.mockserver.client.MockServerClient; +import org.testcontainers.utility.DockerImageName; import java.io.BufferedReader; import java.io.IOException; @@ -19,9 +20,11 @@ public class MockServerContainerTest { + public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse("jamesdbloom/mockserver:mockserver-5.5.4"); + // creatingProxy { @Rule - public MockServerContainer mockServer = new MockServerContainer(); + public MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE); // } private static String responseFromMockserver(MockServerContainer mockServer, String path) throws IOException { @@ -52,7 +55,7 @@ public void shouldReturnExpectation() throws Exception { @Test public void shouldCallActualMockserverVersion() throws Exception { String actualVersion = MockServerClient.class.getPackage().getImplementationVersion(); - try (MockServerContainer mockServer = new MockServerContainer(actualVersion)) { + try (MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE.withTag("mockserver-" + actualVersion))) { mockServer.start(); String expectedBody = "Hello World!"; diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index a7f57d310f2..1527b3924db 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -5,6 +5,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; import java.io.IOException; @@ -21,11 +22,23 @@ public class MongoDBContainer extends GenericContainer { private static final String MONGODB_VERSION_DEFAULT = "4.0.10"; private static final String MONGODB_DATABASE_NAME_DEFAULT = "test"; + /** + * @deprecated use {@link MongoDBContainer(DockerImageName)} instead + */ + @Deprecated public MongoDBContainer() { this("mongo:" + MONGODB_VERSION_DEFAULT); } + /** + * @deprecated use {@link MongoDBContainer(DockerImageName)} instead + */ + @Deprecated public MongoDBContainer(@NonNull final String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public MongoDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); withExposedPorts(MONGODB_INTERNAL_PORT); withCommand("--replSet", "docker-rs"); diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index 7c4f4c12408..d637cb07f2d 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -11,12 +11,14 @@ import com.mongodb.client.TransactionBody; import org.bson.Document; import org.junit.Test; +import org.testcontainers.utility.DockerImageName; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; public class MongoDBContainerTest { + /** * Taken from https://docs.mongodb.com */ @@ -24,7 +26,7 @@ public class MongoDBContainerTest { public void shouldExecuteTransactions() { try ( // creatingMongoDBContainer { - final MongoDBContainer mongoDBContainer = new MongoDBContainer() + final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")) // } ) { diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index 7550f820d51..0a6d8149e34 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -1,5 +1,6 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.LicenseAcceptance; import java.util.regex.Pattern; @@ -32,11 +33,23 @@ public class MSSQLServerContainer> exten Pattern.compile("[^a-zA-Z0-9]+", Pattern.CASE_INSENSITIVE) }; + /** + * @deprecated use {@link MSSQLServerContainer(DockerImageName)} instead + */ + @Deprecated public MSSQLServerContainer() { this(IMAGE + ":" + DEFAULT_TAG); } + /** + * @deprecated use {@link MSSQLServerContainer(DockerImageName)} instead + */ + @Deprecated public MSSQLServerContainer(final String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public MSSQLServerContainer(final DockerImageName dockerImageName) { super(dockerImageName); withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java index daaa82ee771..c3495c8a3a6 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java @@ -1,5 +1,7 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; + /** * Factory for MS SQL Server containers. */ @@ -16,6 +18,6 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new MSSQLServerContainer(MSSQLServerContainer.IMAGE + ":" + tag); + return new MSSQLServerContainer(DockerImageName.parse(MSSQLServerContainer.IMAGE).withTag(tag)); } } diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/MSSQLServerTestImages.java b/modules/mssqlserver/src/test/java/org/testcontainers/MSSQLServerTestImages.java new file mode 100644 index 00000000000..0cec042e19f --- /dev/null +++ b/modules/mssqlserver/src/test/java/org/testcontainers/MSSQLServerTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface MSSQLServerTestImages { + DockerImageName MSSQL_SERVER_IMAGE = DockerImageName.parse("mcr.microsoft.com/mssql/server:2017-CU12"); +} diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java index 1fcf2dd293b..8c0c9ab1c2b 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerTest.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.MSSQLServerTestImages; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; public class MSSQLR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { @@ -17,6 +18,6 @@ protected String createR2DBCUrl() { @Override protected MSSQLServerContainer createContainer() { - return new MSSQLServerContainer<>(); + return new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE); } } diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java index 0e1ea05b31d..3df8ff0fa3d 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.testcontainers.MSSQLServerTestImages; import org.testcontainers.containers.MSSQLServerContainer; import java.util.Arrays; @@ -66,7 +67,7 @@ public static Collection data() { @Test public void runPasswordTests() { try { - new MSSQLServerContainer<>().withPassword(this.password); + new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE).withPassword(this.password); if (!valid) fail("Password " + this.password + " is not valid. Expected exception"); } catch (IllegalArgumentException e) { diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java index ecbc4e31714..d3c387e7b4a 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java @@ -3,6 +3,7 @@ import org.junit.Test; import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; +import org.testcontainers.utility.DockerImageName; import java.sql.ResultSet; import java.sql.SQLException; @@ -15,7 +16,7 @@ public class CustomizableMSSQLServerTest extends AbstractContainerDatabaseTest { @Test public void testSqlServerConnection() throws SQLException { - try (MSSQLServerContainer mssqlServerContainer = new MSSQLServerContainer<>() + try (MSSQLServerContainer mssqlServerContainer = new MSSQLServerContainer<>(DockerImageName.parse("mcr.microsoft.com/mssql/server:2017-CU12")) .withPassword(STRONG_PASSWORD)) { mssqlServerContainer.start(); diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index 71e12a6d864..100b29b34f7 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -1,6 +1,7 @@ package org.testcontainers.junit.mssqlserver; import org.junit.Test; +import org.testcontainers.MSSQLServerTestImages; import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -12,12 +13,13 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.testcontainers.MSSQLServerTestImages.MSSQL_SERVER_IMAGE; public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>()) { + try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQL_SERVER_IMAGE)) { mssqlServer.start(); ResultSet resultSet = performQuery(mssqlServer, "SELECT 1"); @@ -28,7 +30,7 @@ public void testSimple() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>() + try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQL_SERVER_IMAGE) .withUrlParam("integratedSecurity", "false") .withUrlParam("applicationName", "MyApp")) { @@ -42,7 +44,7 @@ public void testWithAdditionalUrlParamInJdbcUrl() { @Test public void testSetupDatabase() throws SQLException { - try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>()) { + try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQL_SERVER_IMAGE)) { mssqlServer.start(); DataSource ds = getDataSource(mssqlServer); Statement statement = ds.getConnection().createStatement(); diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 1ef574cbd5e..35321db5d72 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -1,12 +1,11 @@ package org.testcontainers.containers; import org.jetbrains.annotations.NotNull; +import org.testcontainers.utility.DockerImageName; import java.util.HashSet; import java.util.Set; -import static java.util.stream.Collectors.joining; - /** * @author richardnorth */ @@ -27,15 +26,28 @@ public class MySQLContainer> extends JdbcDatab private String password = DEFAULT_PASSWORD; private static final String MYSQL_ROOT_USER = "root"; + /** + * @deprecated use {@link MySQLContainer(DockerImageName)} instead + */ + @Deprecated public MySQLContainer() { this(IMAGE + ":" + DEFAULT_TAG); } + /** + * @deprecated use {@link MySQLContainer(DockerImageName)} instead + */ + @Deprecated public MySQLContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public MySQLContainer(final DockerImageName dockerImageName) { super(dockerImageName); addExposedPort(MYSQL_PORT); } + @NotNull @Override protected Set getLivenessCheckPorts() { diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java index 7d4919f4b26..18d126635b1 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java @@ -1,8 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.jdbc.ConnectionUrl; - -import java.util.Objects; +import org.testcontainers.utility.DockerImageName; /** * Factory for MySQL containers. @@ -26,7 +25,7 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { if (tag != null) { - return new MySQLContainer(MySQLContainer.IMAGE + ":" + tag); + return new MySQLContainer(DockerImageName.parse(MySQLContainer.IMAGE).withTag(tag)); } else { return newInstance(); } diff --git a/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java b/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java new file mode 100644 index 00000000000..6c8c6690d1f --- /dev/null +++ b/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java @@ -0,0 +1,9 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public class MySQLTestImages { + public static final DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.22"); + public static final DockerImageName MYSQL_55_IMAGE = DockerImageName.parse("mysql:5.5"); + public static final DockerImageName MYSQL_56_IMAGE = DockerImageName.parse("mysql:5.6"); +} diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java index 19edc3dbca4..38abf637c3a 100644 --- a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.MySQLTestImages; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; public class MySQLR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { @@ -17,7 +18,7 @@ protected String createR2DBCUrl() { @Override protected MySQLContainer createContainer() { - return new MySQLContainer<>(); + return new MySQLContainer<>(MySQLTestImages.MYSQL_IMAGE); } } diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java index 590d288e3fe..708b2b987cd 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java @@ -1,6 +1,7 @@ package org.testcontainers.junit.mysql; import org.junit.Test; +import org.testcontainers.MySQLTestImages; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -17,7 +18,7 @@ public class CustomizableMysqlTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - try (MySQLContainer mysql = new MySQLContainer<>("mysql:5.5") + try (MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_IMAGE) .withDatabaseName(DB_NAME) .withUsername(USER) .withPassword(PWD) diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java index 3c0c86ffafa..b8f1a136d9a 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java @@ -3,8 +3,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.testcontainers.MySQLTestImages; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; +import org.testcontainers.utility.DockerImageName; import java.sql.ResultSet; import java.sql.SQLException; @@ -27,7 +29,10 @@ public MultiVersionMySQLTest(String version) { @Test public void versionCheckTest() throws SQLException { - try (MySQLContainer mysql = new MySQLContainer<>("mysql:" + version)) { + + final DockerImageName dockerImageName = MySQLTestImages.MYSQL_IMAGE.withTag(version); + + try (MySQLContainer mysql = new MySQLContainer<>(dockerImageName)) { mysql.start(); final ResultSet resultSet = performQuery(mysql, "SELECT VERSION()"); final String resultSetString = resultSet.getString(1); diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index 6d6f8d26453..f0ceeb92a48 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -20,10 +20,13 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.rnorth.visibleassertions.VisibleAssertions.fail; +import static org.testcontainers.MySQLTestImages.MYSQL_55_IMAGE; +import static org.testcontainers.MySQLTestImages.MYSQL_56_IMAGE; +import static org.testcontainers.MySQLTestImages.MYSQL_IMAGE; public class SimpleMySQLTest extends AbstractContainerDatabaseTest { @@ -37,19 +40,19 @@ public class SimpleMySQLTest extends AbstractContainerDatabaseTest { */ /* @ClassRule - public static MySQLContainer mysql = new MySQLContainer<>(); + public static MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE); @ClassRule - public static MySQLContainer mysqlOldVersion = new MySQLContainer<>("mysql:5.5"); + public static MySQLContainer mysqlOldVersion = new MySQLContainer<>(DockerImageName.parse("mysql:5.5");) @ClassRule - public static MySQLContainer mysqlCustomConfig = new MySQLContainer<>("mysql:5.6") + public static MySQLContainer mysqlCustomConfig = new MySQLContainer<>(DockerImageName.parse("mysql:5.6")) .withConfigurationOverride("somepath/mysql_conf_override"); */ @Test public void testSimple() throws SQLException { - try (MySQLContainer mysql = new MySQLContainer<>() + try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) .withConfigurationOverride("somepath/mysql_conf_override") .withLogConsumer(new Slf4jLogConsumer(logger))) { @@ -64,7 +67,7 @@ public void testSimple() throws SQLException { @Test public void testSpecificVersion() throws SQLException { - try (MySQLContainer mysqlOldVersion = new MySQLContainer<>("mysql:5.5") + try (MySQLContainer mysqlOldVersion = new MySQLContainer<>(MYSQL_55_IMAGE) .withConfigurationOverride("somepath/mysql_conf_override") .withLogConsumer(new Slf4jLogConsumer(logger))) { @@ -81,7 +84,7 @@ public void testSpecificVersion() throws SQLException { public void testMySQLWithCustomIniFile() throws SQLException { assumeFalse(SystemUtils.IS_OS_WINDOWS); - try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>("mysql:5.6") + try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MYSQL_56_IMAGE) .withConfigurationOverride("somepath/mysql_conf_override")) { mysqlCustomConfig.start(); @@ -95,7 +98,7 @@ public void testMySQLWithCustomIniFile() throws SQLException { @Test public void testCommandOverride() throws SQLException { - try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>() + try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MYSQL_IMAGE) .withCommand("mysqld --auto_increment_increment=42")) { mysqlCustomConfig.start(); @@ -109,7 +112,7 @@ public void testCommandOverride() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (MySQLContainer container = new MySQLContainer<>() + try (MySQLContainer container = new MySQLContainer<>(MYSQL_IMAGE) .withInitScript("somepath/init_mysql.sql") .withLogConsumer(new Slf4jLogConsumer(logger))) { container.start(); @@ -123,7 +126,7 @@ public void testExplicitInitScript() throws SQLException { @Test(expected = ContainerLaunchException.class) public void testEmptyPasswordWithNonRootUser() { - try (MySQLContainer container = new MySQLContainer<>("mysql:5.5") + try (MySQLContainer container = new MySQLContainer<>(MYSQL_55_IMAGE) .withDatabaseName("TEST") .withUsername("test") .withPassword("") @@ -136,7 +139,7 @@ public void testEmptyPasswordWithNonRootUser() { @Test public void testEmptyPasswordWithRootUser() throws SQLException { // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - try (MySQLContainer mysql = new MySQLContainer<>("mysql:5.5") + try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_55_IMAGE) .withDatabaseName("foo") .withUsername("root") .withPassword("") @@ -153,7 +156,7 @@ public void testEmptyPasswordWithRootUser() throws SQLException { @Test public void testWithAdditionalUrlParamTimeZone() throws SQLException { - MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) .withUrlParam("serverTimezone", "Europe/Zurich") .withEnv("TZ", "Europe/Zurich") .withLogConsumer(new Slf4jLogConsumer(logger)); @@ -183,7 +186,7 @@ public void testWithAdditionalUrlParamTimeZone() throws SQLException { @Test public void testWithAdditionalUrlParamMultiQueries() throws SQLException { - MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) .withUrlParam("allowMultiQueries", "true") .withLogConsumer(new Slf4jLogConsumer(logger)); mysql.start(); @@ -207,7 +210,7 @@ public void testWithAdditionalUrlParamMultiQueries() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - MySQLContainer mysql = (MySQLContainer) new MySQLContainer() + MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) .withUrlParam("allowMultiQueries", "true") .withUrlParam("rewriteBatchedStatements", "true") .withLogConsumer(new Slf4jLogConsumer(logger)); diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index 10545da43d6..5d4212ccacd 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -1,19 +1,20 @@ package org.testcontainers.containers; -import static java.net.HttpURLConnection.*; -import static java.util.stream.Collectors.*; - -import java.time.Duration; -import java.util.Set; -import java.util.stream.Stream; - import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.LicenseAcceptance; import org.testcontainers.utility.MountableFile; +import java.time.Duration; +import java.util.Set; +import java.util.stream.Stream; + +import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.stream.Collectors.toSet; + /** * Testcontainer for Neo4j. * @@ -58,23 +59,29 @@ public class Neo4jContainer> extends GenericContaine private String adminPassword = DEFAULT_ADMIN_PASSWORD; - private boolean defaultImage = false; + private boolean standardImage = false; /** * Creates a Testcontainer using the official Neo4j docker image. + * @deprecated use {@link Neo4jContainer(DockerImageName)} instead */ + @Deprecated public Neo4jContainer() { this(DOCKER_IMAGE_NAME); - - this.defaultImage = true; } /** * Creates a Testcontainer using a specific docker image. * * @param dockerImageName The docker image to use. + * @deprecated use {@link Neo4jContainer(DockerImageName)} instead */ + @Deprecated public Neo4jContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public Neo4jContainer(final DockerImageName dockerImageName) { super(dockerImageName); WaitStrategy waitForBolt = new LogMessageWaitStrategy() @@ -89,6 +96,10 @@ public Neo4jContainer(String dockerImageName) { .withStartupTimeout(Duration.ofMinutes(2)); addExposedPorts(DEFAULT_BOLT_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); + + if (dockerImageName.getUnversionedPart().equals(DEFAULT_IMAGE_NAME)) { + this.standardImage = true; + } } @Override @@ -139,7 +150,7 @@ public String getHttpsUrl() { */ public S withEnterpriseEdition() { - if (!defaultImage) { + if (!standardImage) { throw new IllegalStateException( String.format("Cannot use enterprise version with alternative image %s.", getDockerImageName())); } diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java index 96b7a48b96f..5a67674cbe8 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java @@ -1,9 +1,5 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.*; - -import java.util.Collections; - import org.junit.ClassRule; import org.junit.Test; import org.neo4j.driver.v1.AuthTokens; @@ -11,6 +7,11 @@ import org.neo4j.driver.v1.GraphDatabase; import org.neo4j.driver.v1.Session; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + /** * Test for basic functionality when used as a @ClassRule. * @@ -19,7 +20,7 @@ public class Neo4jContainerJUnitIntegrationTest { @ClassRule - public static Neo4jContainer neo4jContainer = new Neo4jContainer(); + public static Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE); @Test public void shouldStart() { diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java index cbbe5cb5729..6a32dac0af0 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java @@ -1,10 +1,5 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.Assumptions.*; - -import java.util.Collections; - import org.junit.Test; import org.neo4j.driver.v1.AuthToken; import org.neo4j.driver.v1.AuthTokens; @@ -15,6 +10,12 @@ import org.neo4j.driver.v1.StatementResult; import org.testcontainers.utility.MountableFile; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assumptions.assumeThat; + /** * Tests of functionality special to the Neo4jContainer. * @@ -29,7 +30,7 @@ public class Neo4jContainerTest { public void shouldDisableAuthentication() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer().withoutAuthentication(); + Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE).withoutAuthentication() ) { neo4jContainer.start(); try (Driver driver = getDriver(neo4jContainer); @@ -44,8 +45,8 @@ public void shouldDisableAuthentication() { @Test public void shouldCopyDatabase() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withDatabase(MountableFile.forClasspathResource("/test-graph.db")); + Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + .withDatabase(MountableFile.forClasspathResource("/test-graph.db")) ) { neo4jContainer.start(); try ( @@ -62,8 +63,8 @@ public void shouldCopyDatabase() { @Test public void shouldCopyPlugins() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withPlugins(MountableFile.forClasspathResource("/custom-plugins")); + Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + .withPlugins(MountableFile.forClasspathResource("/custom-plugins")) ) { neo4jContainer.start(); try ( @@ -78,8 +79,8 @@ public void shouldCopyPlugins() { @Test public void shouldCopyPlugin() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withPlugins(MountableFile.forClasspathResource("/custom-plugins/hello-world.jar")); + Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + .withPlugins(MountableFile.forClasspathResource("/custom-plugins/hello-world.jar")) ) { neo4jContainer.start(); try ( @@ -105,7 +106,7 @@ public void shouldCheckEnterpriseLicense() { String expectedImageName = "neo4j:3.5.0-enterprise"; assertThatExceptionOfType(IllegalStateException.class) - .isThrownBy(() -> new Neo4jContainer().withEnterpriseEdition()) + .isThrownBy(() -> new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE).withEnterpriseEdition()) .withMessageContaining("The image " + expectedImageName + " requires you to accept a license agreement."); } @@ -114,7 +115,7 @@ public void shouldRunEnterprise() { assumeThat(Neo4jContainerTest.class.getResource(ACCEPTANCE_FILE_LOCATION)).isNotNull(); try ( - Neo4jContainer neo4jContainer = new Neo4jContainer() + Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) .withEnterpriseEdition() .withAdminPassword("Picard123") ) { @@ -134,7 +135,7 @@ public void shouldRunEnterprise() { @Test public void shouldAddConfigToEnvironment() { - Neo4jContainer neo4jContainer = new Neo4jContainer() + Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) .withNeo4jConfig("dbms.security.procedures.unrestricted", "apoc.*,algo.*") .withNeo4jConfig("dbms.tx_log.rotation.size", "42M"); @@ -144,7 +145,7 @@ public void shouldAddConfigToEnvironment() { .containsEntry("NEO4J_dbms_tx__log_rotation_size", "42M"); } - private static Driver getDriver(Neo4jContainer container) { + private static Driver getDriver(Neo4jContainer container) { AuthToken authToken = AuthTokens.none(); if (container.getAdminPassword() != null) { diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java new file mode 100644 index 00000000000..2cab24baf2b --- /dev/null +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers.containers; + +import org.testcontainers.utility.DockerImageName; + +public interface Neo4jTestImages { + DockerImageName NEO4J_TEST_IMAGE = DockerImageName.parse("neo4j:3.5.0"); +} diff --git a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java index fb931bce409..75a4571b68e 100644 --- a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java +++ b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.traits.LinkableContainer; +import org.testcontainers.utility.DockerImageName; import java.net.MalformedURLException; import java.net.URL; @@ -15,17 +16,29 @@ public class NginxContainer> extends GenericCo private static final int NGINX_DEFAULT_PORT = 80; + /** + * @deprecated use {@link NginxContainer(DockerImageName)} instead + */ + @Deprecated public NginxContainer() { this("nginx:1.9.4"); } + /** + * @deprecated use {@link NginxContainer(DockerImageName)} instead + */ + @Deprecated public NginxContainer(String dockerImageName) { - super(dockerImageName); + this(DockerImageName.parse(dockerImageName)); addExposedPort(NGINX_DEFAULT_PORT); setCommand("nginx", "-g", "daemon off;"); } + public NginxContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + } + @NotNull @Override protected Set getLivenessCheckPorts() { diff --git a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java index b41a0d8361e..e322804bf75 100644 --- a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java +++ b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java @@ -6,6 +6,7 @@ import org.junit.Test; import org.testcontainers.containers.NginxContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.utility.DockerImageName; import java.io.*; import java.net.URL; @@ -19,11 +20,13 @@ */ public class SimpleNginxTest { + private static final DockerImageName NGINX_IMAGE = DockerImageName.parse("nginx:1.9.4"); + private static String tmpDirectory = System.getProperty("user.home") + "/.tmp-test-container"; // creatingContainer { @Rule - public NginxContainer nginx = new NginxContainer<>() + public NginxContainer nginx = new NginxContainer<>(NGINX_IMAGE) .withCustomContent(tmpDirectory) .waitingFor(new HttpWaitStrategy()); // } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index d263a141d4f..8406d8275fb 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -1,5 +1,6 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.TestcontainersConfiguration; import java.util.concurrent.Future; @@ -32,11 +33,23 @@ private static String resolveImageName() { return image; } + /** + * @deprecated use {@link OracleContainer(DockerImageName)} instead + */ + @Deprecated public OracleContainer() { this(resolveImageName()); } + /** + * @deprecated use {@link OracleContainer(DockerImageName)} instead + */ + @Deprecated public OracleContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public OracleContainer(final DockerImageName dockerImageName) { super(dockerImageName); preconfigure(); } diff --git a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java index b7fcc85573a..797f73f7159 100644 --- a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java +++ b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java @@ -13,6 +13,7 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.utility.DockerImageName; import java.io.IOException; import java.net.URL; @@ -48,11 +49,23 @@ public class OrientDBContainer extends GenericContainer { private OrientDB orientDB; private ODatabaseSession session; + /** + * @deprecated use {@link OrientDBContainer(DockerImageName)} instead + */ + @Deprecated public OrientDBContainer() { this(DOCKER_IMAGE_NAME); } + /** + * @deprecated use {@link OrientDBContainer(DockerImageName)} instead + */ + @Deprecated public OrientDBContainer(@NonNull String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public OrientDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); serverPassword = DEFAULT_SERVER_PASSWORD; diff --git a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java index 54b0661cae2..60d7b172436 100644 --- a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java +++ b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java @@ -2,6 +2,7 @@ import com.orientechnologies.orient.core.db.ODatabaseSession; import org.junit.Test; +import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.*; @@ -10,9 +11,11 @@ */ public class OrientDBContainerTest { + private static final DockerImageName ORIENTDB_IMAGE = DockerImageName.parse("orientdb:3.0.24-tp3"); + @Test public void shouldReturnTheSameSession() { - try (OrientDBContainer container = new OrientDBContainer()) { + try (OrientDBContainer container = new OrientDBContainer(ORIENTDB_IMAGE)) { container.start(); final ODatabaseSession session = container.getSession(); @@ -24,7 +27,7 @@ public void shouldReturnTheSameSession() { @Test public void shouldInitializeWithCommands() { - try (OrientDBContainer container = new OrientDBContainer()) { + try (OrientDBContainer container = new OrientDBContainer(ORIENTDB_IMAGE)) { container.start(); final ODatabaseSession session = container.getSession(); @@ -40,7 +43,7 @@ public void shouldInitializeWithCommands() { @Test public void shouldQueryWithGremlin() { - try (OrientDBContainer container = new OrientDBContainer()) { + try (OrientDBContainer container = new OrientDBContainer(ORIENTDB_IMAGE)) { container.start(); final ODatabaseSession session = container.getSession("admin", "admin"); @@ -56,7 +59,7 @@ public void shouldQueryWithGremlin() { @Test public void shouldInitializeDatabaseFromScript() { - try (OrientDBContainer container = new OrientDBContainer() + try (OrientDBContainer container = new OrientDBContainer(ORIENTDB_IMAGE) .withScriptPath("initscript.osql") .withDatabaseName("persons")) { diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java index 54c87a84648..9e59787837b 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java @@ -1,8 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.jdbc.ConnectionUrl; - -import java.util.Objects; +import org.testcontainers.utility.DockerImageName; /** * Factory for PostGIS containers, which are a special flavour of PostgreSQL. @@ -28,7 +27,7 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new PostgreSQLContainer(DEFAULT_IMAGE + ":" + tag); + return new PostgreSQLContainer(DockerImageName.parse(DEFAULT_IMAGE).withTag(DEFAULT_TAG)); } @Override diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 1c814044023..b1ddb2a26ee 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; import java.time.Duration; import java.util.HashSet; @@ -31,11 +32,23 @@ public class PostgreSQLContainer> extends private static final String QUERY_PARAM_SEPARATOR = "&"; + /** + * @deprecated use {@link PostgreSQLContainer(DockerImageName)} instead + */ + @Deprecated public PostgreSQLContainer() { this(IMAGE + ":" + DEFAULT_TAG); } + /** + * @deprecated use {@link PostgreSQLContainer(DockerImageName)} instead + */ + @Deprecated public PostgreSQLContainer(final String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public PostgreSQLContainer(final DockerImageName dockerImageName) { super(dockerImageName); this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*database system is ready to accept connections.*\\s") diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java index 77a0329c22c..5e7580c75eb 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java @@ -1,8 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.jdbc.ConnectionUrl; - -import java.util.Objects; +import org.testcontainers.utility.DockerImageName; /** * Factory for PostgreSQL containers. @@ -24,7 +23,7 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new PostgreSQLContainer(PostgreSQLContainer.IMAGE + ":" + tag); + return new PostgreSQLContainer(DockerImageName.parse(PostgreSQLContainer.IMAGE).withTag(tag)); } @Override diff --git a/modules/postgresql/src/test/java/org/testcontainers/PostgreSQLTestImages.java b/modules/postgresql/src/test/java/org/testcontainers/PostgreSQLTestImages.java new file mode 100644 index 00000000000..8be01053570 --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/PostgreSQLTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface PostgreSQLTestImages { + DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12"); +} diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index c0ba7e40d44..c18f19a109e 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import org.junit.Test; +import org.testcontainers.PostgreSQLTestImages; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; @@ -46,6 +47,9 @@ public void shouldRejectInvalidQueryString() { } static class FixedJdbcUrlPostgreSQLContainer extends PostgreSQLContainer { + public FixedJdbcUrlPostgreSQLContainer() { + super(PostgreSQLTestImages.POSTGRES_TEST_IMAGE); + } @Override public String getHost() { @@ -59,6 +63,9 @@ public Integer getMappedPort(int originalPort) { } static class NoParamsUrlPostgreSQLContainer extends PostgreSQLContainer { + public NoParamsUrlPostgreSQLContainer() { + super(PostgreSQLTestImages.POSTGRES_TEST_IMAGE); + } @Override public String getJdbcUrl() { diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java index 505b37859ba..46e439aaf66 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java @@ -1,13 +1,14 @@ package org.testcontainers.containers; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.PostgreSQLTestImages; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; public class PostgreSQLR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest> { @Override protected PostgreSQLContainer createContainer() { - return new PostgreSQLContainer<>(); + return new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE); } @Override diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java index 8446440059e..8fd523434dd 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java @@ -1,6 +1,7 @@ package org.testcontainers.junit.postgresql; import org.junit.Test; +import org.testcontainers.PostgreSQLTestImages; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -19,7 +20,7 @@ public class CustomizablePostgreSQLTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:9.6.8") + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) .withDatabaseName(DB_NAME) .withUsername(USER) .withPassword(PWD)) { diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 36ece03b604..95e1fdf10fd 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; +import static org.testcontainers.PostgreSQLTestImages.POSTGRES_TEST_IMAGE; public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { @@ -23,7 +24,7 @@ public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>()) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE)) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT 1"); @@ -34,7 +35,7 @@ public void testSimple() throws SQLException { @Test public void testCommandOverride() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42")) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE).withCommand("postgres -c max_connections=42")) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); @@ -45,7 +46,7 @@ public void testCommandOverride() throws SQLException { @Test public void testUnsetCommand() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withCommand("postgres -c max_connections=42").withCommand()) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE).withCommand("postgres -c max_connections=42").withCommand()) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); @@ -56,7 +57,7 @@ public void testUnsetCommand() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>().withInitScript("somepath/init_postgresql.sql")) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE).withInitScript("somepath/init_postgresql.sql")) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); @@ -68,7 +69,7 @@ public void testExplicitInitScript() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>() + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE) .withUrlParam("charSet", "UNICODE")) { postgres.start(); diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index c3f25c40ac8..1c8c03ce4de 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; import java.sql.Connection; import java.sql.SQLException; @@ -23,11 +24,23 @@ public class PrestoContainer> extends JdbcDat private String username = "test"; private String catalog = null; + /** + * @deprecated use {@link PrestoContainer(DockerImageName)} instead + */ + @Deprecated public PrestoContainer() { this(IMAGE + ":" + DEFAULT_TAG); } + /** + * @deprecated use {@link PrestoContainer(DockerImageName)} instead + */ + @Deprecated public PrestoContainer(final String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public PrestoContainer(final DockerImageName dockerImageName) { super(dockerImageName); this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*======== SERVER STARTED ========.*") diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java index 663cf9be4a9..8408aab4517 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java @@ -1,8 +1,7 @@ package org.testcontainers.containers; import org.testcontainers.jdbc.ConnectionUrl; - -import java.util.Objects; +import org.testcontainers.utility.DockerImageName; /** * Factory for Presto containers. @@ -24,7 +23,7 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new PrestoContainer(PrestoContainer.IMAGE + ":" + tag); + return new PrestoContainer(DockerImageName.parse(PrestoContainer.IMAGE).withTag(tag)); } @Override diff --git a/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java b/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java new file mode 100644 index 00000000000..1b4e449c99f --- /dev/null +++ b/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java @@ -0,0 +1,8 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface PrestoTestImages { + DockerImageName PRESTO_TEST_IMAGE = DockerImageName.parse("prestosql/presto:329"); + DockerImageName PRESTO_PREVIOUS_VERSION_TEST_IMAGE = DockerImageName.parse("prestosql/presto:328"); +} diff --git a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java index 07fb6fa30ed..d5a4d9587a6 100644 --- a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java +++ b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java @@ -2,6 +2,8 @@ import org.junit.Assert; import org.junit.Test; +import org.testcontainers.PrestoTestImages; +import org.testcontainers.utility.DockerImageName; import java.sql.Connection; import java.sql.DriverManager; @@ -22,9 +24,10 @@ * @author findepi */ public class PrestoContainerTest { + @Test public void testSimple() throws Exception { - try (PrestoContainer prestoSql = new PrestoContainer<>()) { + try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_TEST_IMAGE)) { prestoSql.start(); try (Connection connection = prestoSql.createConnection(); Statement statement = connection.createStatement(); @@ -37,21 +40,20 @@ public void testSimple() throws Exception { @Test public void testSpecificVersion() throws Exception { - String prestoVersion = Integer.toString(parseInt(PrestoContainer.DEFAULT_TAG) - 1); - try (PrestoContainer prestoSql = new PrestoContainer<>("prestosql/presto:" + prestoVersion)) { + try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE)) { prestoSql.start(); try (Connection connection = prestoSql.createConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { assertTrue("No result", resultSet.next()); - assertEquals("Presto version", prestoVersion, resultSet.getString("node_version")); + assertEquals("Presto version", PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), resultSet.getString("node_version")); } } } @Test public void testQueryMemoryAndTpch() throws SQLException { - try (PrestoContainer prestoSql = new PrestoContainer<>()) { + try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_TEST_IMAGE)) { prestoSql.start(); try (Connection connection = prestoSql.createConnection(); Statement statement = connection.createStatement()) { @@ -77,7 +79,7 @@ public void testQueryMemoryAndTpch() throws SQLException { @Test public void testInitScript() throws Exception { - try (PrestoContainer prestoSql = new PrestoContainer<>()) { + try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_TEST_IMAGE)) { prestoSql.withInitScript("initial.sql"); prestoSql.start(); try (Connection connection = prestoSql.createConnection(); diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 936759efb1a..4d30d947113 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -2,6 +2,7 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.TestcontainersConfiguration; /** @@ -13,16 +14,29 @@ public class PulsarContainer extends GenericContainer { public static final int BROKER_HTTP_PORT = 8080; public static final String METRICS_ENDPOINT = "/metrics"; - private static final String PULSAR_VERSION = "2.2.0"; + @Deprecated + private static final String DEFAULT_PULSAR_VERSION = "2.2.0"; private boolean functionsWorkerEnabled = false; + /** + * @deprecated use {@link PulsarContainer(DockerImageName)} instead + */ + @Deprecated public PulsarContainer() { - this(PULSAR_VERSION); + this(DEFAULT_PULSAR_VERSION); } + /** + * @deprecated use {@link PulsarContainer(DockerImageName)} instead + */ + @Deprecated public PulsarContainer(String pulsarVersion) { - super(TestcontainersConfiguration.getInstance().getPulsarImage() + ":" + pulsarVersion); + this(TestcontainersConfiguration.getInstance().getPulsarDockerImageName().withTag(pulsarVersion)); + } + + public PulsarContainer(final DockerImageName dockerImageName) { + super(dockerImageName); withExposedPorts(BROKER_PORT, BROKER_HTTP_PORT); withCommand("/pulsar/bin/pulsar", "standalone", "--no-functions-worker", "-nss"); waitingFor(Wait.forHttp(METRICS_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index e9d41516670..f2354d98ef7 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -7,6 +7,7 @@ import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.PulsarClient; import org.junit.Test; +import org.testcontainers.utility.DockerImageName; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -17,10 +18,11 @@ public class PulsarContainerTest { public static final String TEST_TOPIC = "test_topic"; + private static final DockerImageName PULSAR_IMAGE = DockerImageName.parse("apachepulsar/pulsar:2.2.0"); @Test public void testUsage() throws Exception { - try (PulsarContainer pulsar = new PulsarContainer()) { + try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE)) { pulsar.start(); testPulsarFunctionality(pulsar.getPulsarBrokerUrl()); } diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index d8d46f51b1c..a3b6134b29c 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -5,6 +5,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; import java.io.IOException; @@ -41,7 +42,9 @@ public class RabbitMQContainer extends GenericContainer { /** * Creates a Testcontainer using the official RabbitMQ docker image. + * @deprecated use {@link RabbitMQContainer(DockerImageName)} instead */ + @Deprecated public RabbitMQContainer() { this(DEFAULT_IMAGE_NAME + ":" + DEFAULT_TAG); } @@ -49,10 +52,16 @@ public RabbitMQContainer() { /** * Creates a Testcontainer using a specific docker image. * - * @param image The docker image to use. + * @param dockerImageName The docker image to use. + * @deprecated use {@link RabbitMQContainer(DockerImageName)} instead */ - public RabbitMQContainer(String image) { - super(image); + @Deprecated + public RabbitMQContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public RabbitMQContainer(final DockerImageName dockerImageName) { + super(dockerImageName); addExposedPorts(DEFAULT_AMQP_PORT, DEFAULT_AMQPS_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java index ff71db44348..7473f470f6f 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerJUnitIntegrationTest.java @@ -13,7 +13,7 @@ public class RabbitMQContainerJUnitIntegrationTest { @ClassRule - public static RabbitMQContainer rabbitMQContainer = new RabbitMQContainer(); + public static RabbitMQContainer rabbitMQContainer = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE); @Test public void shouldStart() { diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index 4c2787bf5ab..8be97deb710 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -1,15 +1,16 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER; -import static org.testcontainers.utility.MountableFile.forClasspathResource; - import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import org.junit.Test; +import org.testcontainers.utility.MountableFile; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -20,18 +21,17 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Collections; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; -import org.junit.Test; -import org.testcontainers.utility.MountableFile; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER; +import static org.testcontainers.utility.MountableFile.forClasspathResource; /** * @author Martin Greber */ public class RabbitMQContainerTest { - public static final String DEFAULT_IMAGE = "rabbitmq:3.7.25-management-alpine"; public static final int DEFAULT_AMQPS_PORT = 5671; public static final int DEFAULT_AMQP_PORT = 5672; public static final int DEFAULT_HTTPS_PORT = 15671; @@ -40,9 +40,8 @@ public class RabbitMQContainerTest { @Test public void shouldCreateRabbitMQContainer() { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { - assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE); assertThat(container.getAdminPassword()).isEqualTo("guest"); assertThat(container.getAdminUsername()).isEqualTo("guest"); @@ -71,18 +70,10 @@ public void shouldCreateRabbitMQContainer() } } - @Test - public void shouldCreateRabbitMQContainerWithTag() - { - try (RabbitMQContainer container = new RabbitMQContainer(DEFAULT_IMAGE)) { - assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE); - } - } - @Test public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withExchange("test-exchange", "direct"); container.start(); @@ -95,7 +86,7 @@ public void shouldCreateRabbitMQContainerWithExchange() throws IOException, Inte @Test public void shouldCreateRabbitMQContainerWithExchangeInVhost() throws IOException, InterruptedException { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withVhost("test-vhost"); container.withExchange("test-vhost", "test-exchange", "direct", false, false, false, Collections.emptyMap()); @@ -109,7 +100,7 @@ public void shouldCreateRabbitMQContainerWithExchangeInVhost() throws IOExceptio @Test public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withQueue("queue-one") .withQueue("queue-two", false, true, ImmutableMap.of("x-message-ttl", 1000)); @@ -126,7 +117,7 @@ public void shouldCreateRabbitMQContainerWithQueues() throws IOException, Interr @Test public void shouldMountConfigurationFile() { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); container.start(); @@ -140,7 +131,7 @@ public void shouldMountConfigurationFile() @Test public void shouldMountConfigurationFileErlang() { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withRabbitMQConfigErlang(MountableFile.forClasspathResource("/rabbitmq-custom.config")); container.start(); @@ -154,7 +145,7 @@ public void shouldMountConfigurationFileErlang() @Test public void shouldMountConfigurationFileSysctl() { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withRabbitMQConfigSysctl(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); container.start(); @@ -167,7 +158,7 @@ public void shouldMountConfigurationFileSysctl() @Test public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container .withVhost("vhost1") .withVhostLimit("vhost1", "max-connections", 1) @@ -229,7 +220,7 @@ public void shouldStartTheWholeEnchilada() throws IOException, InterruptedExcept @Test public void shouldThrowExceptionForDodgyJson() { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { assertThatCode(() -> container.withQueue( @@ -245,7 +236,7 @@ public void shouldThrowExceptionForDodgyJson() @Test public void shouldWorkWithSSL() { - try (RabbitMQContainer container = new RabbitMQContainer()) { + try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withSSL( forClasspathResource("/certs/server_key.pem", 0644), forClasspathResource("/certs/server_certificate.pem", 0644), diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQTestImages.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQTestImages.java new file mode 100644 index 00000000000..0898cbdb350 --- /dev/null +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers.containers; + +import org.testcontainers.utility.DockerImageName; + +public interface RabbitMQTestImages { + DockerImageName RABBITMQ_IMAGE = DockerImageName.parse("rabbitmq:3.7.25-management-alpine"); +} diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 16127171c59..f1cedab76ad 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -1,12 +1,10 @@ package org.testcontainers.containers; +import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.AccessMode; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Volume; import com.google.common.collect.ImmutableSet; - -import com.github.dockerjava.api.command.InspectContainerResponse; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.openqa.selenium.Capabilities; @@ -25,6 +23,7 @@ import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.lifecycle.TestDescription; import org.testcontainers.lifecycle.TestLifecycleAware; +import org.testcontainers.utility.DockerImageName; import java.io.File; import java.io.IOException; @@ -70,8 +69,10 @@ public class BrowserWebDriverContainer() + public NginxContainer nginx = new NginxContainer<>(SeleniumTestImages.NGINX_TEST_IMAGE) .withNetwork(network) .withNetworkAliases("nginx") .withCustomContent(contentFolder.toString()); @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() + public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withNetwork(network) .withCapabilities(new ChromeOptions()); diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/Selenium3xTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/Selenium3xTest.java index f7415471bc8..bbcd8c15166 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/Selenium3xTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/Selenium3xTest.java @@ -5,6 +5,7 @@ import org.junit.runners.Parameterized; import org.openqa.selenium.chrome.ChromeOptions; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.utility.DockerImageName; /** * Simple test to check that readiness detection works correctly across major versions of the containers. @@ -22,7 +23,8 @@ public static String[] data() { @Test public void testAdditionalStartupString() { - try (BrowserWebDriverContainer chrome = new BrowserWebDriverContainer("selenium/standalone-chrome-debug:" + tag) + final DockerImageName imageName = DockerImageName.parse("selenium/standalone-chrome-debug").withTag(tag); + try (BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>(imageName) .withCapabilities(new ChromeOptions())) { chrome.start(); } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java index 01edd70c102..6ecf0899ede 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java @@ -4,14 +4,14 @@ import org.junit.Test; import org.openqa.selenium.firefox.FirefoxOptions; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.utility.DockerImageName; -/** - * - */ public class SpecificImageNameWebDriverContainerTest extends BaseWebDriverContainerTest { + private static final DockerImageName FIREFOX_IMAGE = DockerImageName.parse("selenium/standalone-firefox:2.53.1-beryllium"); + @Rule - public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer("selenium/standalone-firefox:2.53.1-beryllium") + public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer<>(FIREFOX_IMAGE) .withCapabilities(new FirefoxOptions()); @Test diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java index 90fd674dfda..aeadb664089 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java @@ -1,18 +1,17 @@ package org.testcontainers.containers; -import static java.time.temporal.ChronoUnit.SECONDS; +import com.github.dockerjava.api.command.InspectContainerResponse; +import lombok.SneakyThrows; +import org.apache.commons.lang.StringUtils; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; import java.net.URL; import java.time.Duration; import java.util.HashSet; import java.util.Set; -import com.github.dockerjava.api.command.InspectContainerResponse; - -import lombok.SneakyThrows; - -import org.apache.commons.lang.StringUtils; -import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import static java.time.temporal.ChronoUnit.SECONDS; /** * SolrContainer allows a solr container to be launched and controlled. @@ -27,11 +26,23 @@ public class SolrContainer extends GenericContainer { private SolrContainerConfiguration configuration; + /** + * @deprecated use {@link SolrContainer(DockerImageName)} instead + */ + @Deprecated public SolrContainer() { this(IMAGE + ":" + DEFAULT_TAG); } + /** + * @deprecated use {@link SolrContainer(DockerImageName)} instead + */ + @Deprecated public SolrContainer(final String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public SolrContainer(final DockerImageName dockerImageName) { super(dockerImageName); this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*o\\.e\\.j\\.s\\.Server Started.*") diff --git a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java index 48cb04b7053..c2d19a3e61c 100644 --- a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java +++ b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java @@ -1,23 +1,25 @@ package org.testcontainers.containers; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.io.IOException; - import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.response.SolrPingResponse; import org.junit.After; import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + +import java.io.IOException; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; /** * @author Simon Schneider */ public class SolrContainerTest { + private static final DockerImageName SOLR_IMAGE = DockerImageName.parse("solr:8.3.0"); private SolrClient client = null; @After @@ -30,7 +32,7 @@ public void stopRestClient() throws IOException { @Test public void solrCloudTest() throws IOException, SolrServerException { - try (SolrContainer container = new SolrContainer()) { + try (SolrContainer container = new SolrContainer(SOLR_IMAGE)) { container.start(); SolrPingResponse response = getClient(container).ping("dummy"); assertThat(response.getStatus(), is(0)); @@ -40,7 +42,7 @@ public void solrCloudTest() throws IOException, SolrServerException { @Test public void solrStandaloneTest() throws IOException, SolrServerException { - try (SolrContainer container = new SolrContainer().withZookeeper(false)) { + try (SolrContainer container = new SolrContainer(SOLR_IMAGE).withZookeeper(false)) { container.start(); SolrPingResponse response = getClient(container).ping("dummy"); assertThat(response.getStatus(), is(0)); @@ -52,7 +54,7 @@ public void solrStandaloneTest() throws IOException, SolrServerException { public void solrCloudPingTest() throws IOException, SolrServerException { // solrContainerUsage { // Create the solr container. - SolrContainer container = new SolrContainer(); + SolrContainer container = new SolrContainer(SOLR_IMAGE); // Start the container. This step might take some time... container.start(); diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy index 7a68302289f..639b46f5886 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy @@ -15,7 +15,7 @@ import spock.lang.Specification class MySqlContainerIT extends Specification { @Shared - MySQLContainer mySQLContainer = new MySQLContainer() + MySQLContainer mySQLContainer = new MySQLContainer(SpockTestImages.MYSQL_IMAGE) def "dummy test"() { expect: diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy index 4ac095bed6f..a886d552732 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy @@ -14,7 +14,7 @@ import java.sql.Statement class PostgresContainerIT extends Specification { @Shared - PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer() + PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(SpockTestImages.POSTGRES_TEST_IMAGE) .withDatabaseName("foo") .withUsername("foo") .withPassword("secret") diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy new file mode 100644 index 00000000000..526c1fe5c42 --- /dev/null +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy @@ -0,0 +1,11 @@ +package org.testcontainers.spock; + +import org.testcontainers.utility.DockerImageName +import org.testcontainers.utility.TestcontainersConfiguration; + +interface SpockTestImages { + DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.22") + DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") + DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") + DockerImageName TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyDockerImageName() +} diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy index 123828327bc..7fb37446ca5 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy @@ -10,7 +10,7 @@ import spock.lang.Shared class TestHierarchyIT extends MySqlContainerIT { @Shared - PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer() + PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(SpockTestImages.POSTGRES_TEST_IMAGE) .withDatabaseName("foo") .withUsername("foo") .withPassword("secret") diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java index 43be6d32ca4..eb628fd2f33 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java @@ -8,6 +8,8 @@ import java.util.List; import java.util.Optional; +import static org.testcontainers.spock.SpockTestImages.TINY_IMAGE; + public class TestLifecycleAwareContainerMock extends GenericContainer implements TestLifecycleAware { static final String BEFORE_TEST = "beforeTest"; @@ -18,6 +20,10 @@ public class TestLifecycleAwareContainerMock extends GenericContainer { private final Map proxies = new HashMap<>(); private final AtomicInteger nextPort = new AtomicInteger(FIRST_PROXIED_PORT); + /** + * @deprecated use {@link ToxiproxyContainer(DockerImageName)} instead + */ + @Deprecated public ToxiproxyContainer() { this(IMAGE_NAME); } - public ToxiproxyContainer(String imageName) { - super(imageName); + /** + * @deprecated use {@link ToxiproxyContainer(DockerImageName)} instead + */ + @Deprecated + public ToxiproxyContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public ToxiproxyContainer(final DockerImageName dockerImageName) { + super(dockerImageName); addExposedPorts(TOXIPROXY_CONTROL_PORT); setWaitStrategy(new HttpWaitStrategy().forPath("/version").forPort(TOXIPROXY_CONTROL_PORT)); diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index d76851f57b5..87f9758ebf1 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -1,16 +1,19 @@ package org.testcontainers.containers; import eu.rekawek.toxiproxy.model.ToxicDirection; -import java.time.Duration; import org.junit.Rule; import org.junit.Test; +import org.testcontainers.utility.DockerImageName; import redis.clients.jedis.Jedis; import redis.clients.jedis.exceptions.JedisConnectionException; import java.io.IOException; +import java.time.Duration; import static java.lang.String.format; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class ToxiproxyTest { @@ -25,15 +28,17 @@ public class ToxiproxyTest { @Rule public Network network = Network.newNetwork(); + private static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:5.0.4"); // The target container - this could be anything @Rule - public GenericContainer redis = new GenericContainer("redis:5.0.4") + public GenericContainer redis = new GenericContainer<>(REDIS_IMAGE) .withExposedPorts(6379) .withNetwork(network); + private static final DockerImageName TOXIPROXY_IMAGE = DockerImageName.parse("shopify/toxiproxy:2.1.0"); // Toxiproxy container, which will be used as a TCP proxy @Rule - public ToxiproxyContainer toxiproxy = new ToxiproxyContainer() + public ToxiproxyContainer toxiproxy = new ToxiproxyContainer(TOXIPROXY_IMAGE) .withNetwork(network) .withNetworkAliases(TOXIPROXY_NETWORK_ALIAS); // } @@ -99,7 +104,7 @@ public void testConnectionCut() { @Test public void testMultipleProxiesCanBeCreated() { - try (GenericContainer secondRedis = new GenericContainer("redis:5.0.4") + try (GenericContainer secondRedis = new GenericContainer<>(REDIS_IMAGE) .withExposedPorts(6379) .withNetwork(network)) { diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java index ac4e730adb3..1532f463f37 100644 --- a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java +++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; import java.io.IOException; import java.util.ArrayList; @@ -28,11 +29,23 @@ public class VaultContainer> extends GenericCo private int port = VAULT_PORT; + /** + * @deprecated use {@link VaultContainer(DockerImageName)} instead + */ + @Deprecated public VaultContainer() { this("vault:1.1.3"); } + /** + * @deprecated use {@link VaultContainer(DockerImageName)} instead + */ + @Deprecated public VaultContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public VaultContainer(final DockerImageName dockerImageName) { super(dockerImageName); // Use the vault healthcheck endpoint to check for readiness, per https://www.vaultproject.io/api/system/health.html diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java index dfe73cae4b9..4a1a800da17 100644 --- a/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java @@ -10,6 +10,7 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.vault.VaultTestImages.VAULT_IMAGE; public class VaultClientTest { @@ -18,7 +19,7 @@ public class VaultClientTest { @Test public void writeAndReadMultipleValues() throws VaultException { try ( - VaultContainer vaultContainer = new VaultContainer<>() + VaultContainer vaultContainer = new VaultContainer<>(VAULT_IMAGE) .withVaultToken(VAULT_TOKEN) ) { diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java index d7ac5ca8686..b3dd788f053 100644 --- a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java @@ -19,7 +19,7 @@ public class VaultContainerTest { private static final String VAULT_TOKEN = "my-root-token"; @ClassRule - public static VaultContainer vaultContainer = new VaultContainer<>() + public static VaultContainer vaultContainer = new VaultContainer<>(VaultTestImages.VAULT_IMAGE) .withVaultToken(VAULT_TOKEN) .withSecretInVault("secret/testing1", "top_secret=password123") .withSecretInVault("secret/testing2", diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultTestImages.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultTestImages.java new file mode 100644 index 00000000000..9afecdcffb9 --- /dev/null +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers.vault; + +import org.testcontainers.utility.DockerImageName; + +public interface VaultTestImages { + DockerImageName VAULT_IMAGE = DockerImageName.parse("vault:1.1.3"); +} From 39c4208ed4edfede2e8721b7aef4d1cb79a9073c Mon Sep 17 00:00:00 2001 From: Kirill Artamonov Date: Sun, 19 Jul 2020 20:35:48 +0200 Subject: [PATCH 0872/4969] Update to latest LocalStack container and support unified port mode (#2825) Co-authored-by: Richard North --- .../utility/ComparableVersion.java | 4 + .../localstack/LocalStackContainer.java | 91 +++++++++++-- .../containers/localstack/LegacyModeTest.java | 128 ++++++++++++++++++ .../localstack/LocalstackContainerTest.java | 80 ++++++----- .../localstack/LocalstackTestImages.java | 8 ++ 5 files changed, 263 insertions(+), 48 deletions(-) create mode 100644 modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java create mode 100644 modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java diff --git a/core/src/main/java/org/testcontainers/utility/ComparableVersion.java b/core/src/main/java/org/testcontainers/utility/ComparableVersion.java index 1ffa1642568..d3e3d9eb958 100644 --- a/core/src/main/java/org/testcontainers/utility/ComparableVersion.java +++ b/core/src/main/java/org/testcontainers/utility/ComparableVersion.java @@ -32,6 +32,10 @@ public int compareTo(@NotNull ComparableVersion other) { return 0; } + public boolean isSemanticVersion() { + return parts.length > 0; + } + public boolean isLessThan(String other) { return this.compareTo(new ComparableVersion(other)) < 0; } diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 0136d94e3b2..3a9fab26ae4 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -4,15 +4,6 @@ import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.FieldDefaults; -import org.rnorth.ducttape.Preconditions; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.TestcontainersConfiguration; - import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; @@ -21,6 +12,16 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import lombok.extern.slf4j.Slf4j; +import org.rnorth.ducttape.Preconditions; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.ComparableVersion; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.TestcontainersConfiguration; /** *

Container for Atlassian Labs Localstack, 'A fully functional local AWS cloud stack'.

@@ -30,13 +31,28 @@ * {@link LocalStackContainer#getDefaultCredentialsProvider()} * be used to obtain compatible endpoint configuration and credentials, respectively.

*/ +@Slf4j public class LocalStackContainer extends GenericContainer { - public static final String VERSION = "0.10.8"; + public static final String VERSION = "0.11.2"; + static final int PORT = 4566; private static final String HOSTNAME_EXTERNAL_ENV_VAR = "HOSTNAME_EXTERNAL"; - private final List services = new ArrayList<>(); + /** + * Whether or to assume that all APIs run on different ports (when true) or are + * exposed on a single port (false). From the Localstack README: + * + *
Note: Starting with version 0.11.0, all APIs are exposed via a single edge + * service [...] The API-specific endpoints below are still left for backward-compatibility but + * may get removed in a future release - please reconfigure your client SDKs to start using the + * single edge endpoint URL!
+ *

+ * Testcontainers will use the tag of the docker image to infer whether or not the used version + * of Localstack supports this feature. + */ + private final boolean legacyMode; + /** * @deprecated use {@link LocalStackContainer(DockerImageName)} instead */ @@ -53,13 +69,41 @@ public LocalStackContainer(String version) { this(DockerImageName.parse(TestcontainersConfiguration.getInstance().getLocalStackImage() + ":" + version)); } + /** + * @param dockerImageName image name to use for Localstack + */ public LocalStackContainer(final DockerImageName dockerImageName) { + this(dockerImageName, shouldRunInLegacyMode(dockerImageName.getVersionPart())); + } + + /** + * @param dockerImageName image name to use for Localstack + * @param useLegacyMode if true, each AWS service is exposed on a different port + */ + public LocalStackContainer(final DockerImageName dockerImageName, boolean useLegacyMode) { super(dockerImageName); + this.legacyMode = useLegacyMode; withFileSystemBind("//var/run/docker.sock", "/var/run/docker.sock"); waitingFor(Wait.forLogMessage(".*Ready\\.\n", 1)); } + private static boolean shouldRunInLegacyMode(String version) { + if (version.equals("latest")) { + return false; + } + + ComparableVersion comparableVersion = new ComparableVersion(version); + if (comparableVersion.isSemanticVersion()) { + boolean versionRequiresLegacyMode = comparableVersion.isLessThan("0.11"); + return versionRequiresLegacyMode; + } + + log.warn("Version {} is not a semantic version, LocalStack will run in legacy mode.", version); + log.warn("Consider using \"LocalStackContainer(DockerImageName dockerImageName, boolean legacyMode)\" constructor if you want to disable legacy mode."); + return true; + } + @Override protected void configure() { super.configure(); @@ -81,9 +125,14 @@ protected void configure() { } logger().info("{} environment variable set to {} ({})", HOSTNAME_EXTERNAL_ENV_VAR, getEnvMap().get(HOSTNAME_EXTERNAL_ENV_VAR), hostnameExternalReason); - for (Service service : services) { - addExposedPort(service.getPort()); - } + exposePorts(); + } + + private void exposePorts() { + services.stream() + .map(this::getServicePort) + .distinct() + .forEach(this::addExposedPort); } /** @@ -154,12 +203,16 @@ public URI getEndpointOverride(Service service) { return new URI("http://" + ipAddress + ":" + - getMappedPort(service.getPort())); + getMappedPort(getServicePort(service))); } catch (UnknownHostException | URISyntaxException e) { throw new IllegalStateException("Cannot obtain endpoint URL", e); } } + private int getServicePort(Service service) { + return legacyMode ? service.port : PORT; + } + /** * Provides a {@link AWSCredentialsProvider} that is preconfigured to communicate with a given simulated service. * The credentials provider should be set in the AWS Java SDK when building a client, e.g.: @@ -271,5 +324,13 @@ public enum Service { String localStackName; int port; + + @Deprecated + /* + Since version 0.11, LocalStack exposes all services on a single (4566) port. + */ + public int getPort() { + return port; + } } } diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java new file mode 100644 index 00000000000..f50846b091f --- /dev/null +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java @@ -0,0 +1,128 @@ +package org.testcontainers.containers.localstack; + +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.function.Consumer; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; +import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_IMAGE; + +@RunWith(Enclosed.class) +public class LegacyModeTest { + + @RunWith(Parameterized.class) + @AllArgsConstructor + public static class Off { + private final String description; + private final LocalStackContainer localstack; + + @Parameterized.Parameters(name = "{0}") + public static Iterable constructors() { + return Arrays.asList(new Object[][]{ + {"default constructor", new LocalStackContainer(LOCALSTACK_IMAGE)}, + {"latest", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("latest"))}, + {"0.11.1", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.11.1"))}, + {"0.7.0 with legacy = off", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.7.0"), false)} + }); + } + + @Test + public void samePortIsExposedForAllServices() { + localstack.withServices(S3, SQS); + localstack.start(); + + assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); + assertEquals( + "Endpoint overrides are different", + localstack.getEndpointOverride(S3).toString(), + localstack.getEndpointOverride(SQS).toString()); + assertEquals( + "Endpoint configuration have different endpoints", + localstack.getEndpointConfiguration(S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + } + + @After + public void cleanup() { + if (localstack != null) localstack.stop(); + } + } + + @RunWith(Parameterized.class) + @AllArgsConstructor + public static class On { + private final String description; + private final LocalStackContainer localstack; + + @BeforeClass + public static void createCustomTag() { + run("docker pull localstack/localstack:latest"); + run("docker tag localstack/localstack:latest localstack/localstack:custom"); + } + + @Parameterized.Parameters(name = "{0}") + public static Iterable constructors() { + return Arrays.asList(new Object[][]{ + {"0.10.7", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.10.7"))}, + {"custom", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("custom"))}, + {"0.11.1 with legacy = on", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.11.1"), true)} + }); + } + + @Test + public void differentPortsAreExposed() { + localstack.withServices(S3, SQS); + localstack.start(); + + assertTrue("Multiple ports are exposed", localstack.getExposedPorts().size() > 1); + assertNotEquals( + "Endpoint overrides are different", + localstack.getEndpointOverride(S3).toString(), + localstack.getEndpointOverride(SQS).toString()); + assertNotEquals( + "Endpoint configuration have different endpoints", + localstack.getEndpointConfiguration(S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + } + + @After + public void cleanup() { + if (localstack != null) localstack.stop(); + } + } + + @SneakyThrows + private static void run(String command) { + Process process = Runtime.getRuntime().exec(command); + join(process.getInputStream(), System.out::println); + join(process.getErrorStream(), System.err::println); + process.waitFor(); + if (process.exitValue() != 0) + throw new RuntimeException("Failed to execute " + command); + } + + private static void join(InputStream stream, Consumer logger) throws IOException { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream)); + String line; + while ((line = bufferedReader.readLine()) != null) { + logger.accept(line); + } + } + +} diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index 63be9d66df7..fad4060341c 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -1,6 +1,16 @@ package org.testcontainers.containers.localstack; +import static org.hamcrest.CoreMatchers.containsString; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.containers.localstack.LocalStackContainer.PORT; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCHLOGS; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.KMS; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; +import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; + import com.amazonaws.services.kms.AWSKMS; import com.amazonaws.services.kms.AWSKMSClientBuilder; import com.amazonaws.services.kms.model.CreateKeyRequest; @@ -18,6 +28,10 @@ import com.amazonaws.services.sqs.AmazonSQS; import com.amazonaws.services.sqs.AmazonSQSClientBuilder; import com.amazonaws.services.sqs.model.CreateQueueResult; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.junit.Assert; @@ -35,20 +49,6 @@ import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.List; -import java.util.Optional; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCHLOGS; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.KMS; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; - /** * Tests for Localstack Container, used both in bridge network (exposed to host) and docker network modes. *

@@ -60,14 +60,13 @@ @RunWith(Enclosed.class) public class LocalstackContainerTest { - private static final DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.10.8"); - private static final DockerImageName AWS_CLI_IMAGE = DockerImageName.parse("atlassian/pipelines-awscli:1.16.302"); - public static class WithoutNetwork { // without_network { @ClassRule - public static LocalStackContainer localstack = new LocalStackContainer(LOCALSTACK_IMAGE) + public static LocalStackContainer localstack = new LocalStackContainer( + DockerImageName.parse("localstack/localstack:0.11.0") + ) .withServices(S3, SQS, CLOUDWATCHLOGS, KMS); // } @@ -124,7 +123,7 @@ public void sqsTestOverBridgeNetwork() { CreateQueueResult queueResult = sqs.createQueue("baz"); String fooQueueUrl = queueResult.getQueueUrl(); assertThat("Created queue has external hostname URL", fooQueueUrl, - containsString("http://" + DockerClientFactory.instance().dockerHostIpAddress() + ":" + localstack.getMappedPort(SQS.getPort()))); + containsString("http://" + DockerClientFactory.instance().dockerHostIpAddress() + ":" + localstack.getMappedPort(PORT))); sqs.sendMessage(fooQueueUrl, "test"); final long messageCount = sqs.receiveMessage(fooQueueUrl).getMessages().stream() @@ -136,8 +135,8 @@ public void sqsTestOverBridgeNetwork() { @Test public void cloudWatchLogsTestOverBridgeNetwork() { AWSLogs logs = AWSLogsClientBuilder.standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(CLOUDWATCHLOGS)) - .withCredentials(localstack.getDefaultCredentialsProvider()).build(); + .withEndpointConfiguration(localstack.getEndpointConfiguration(CLOUDWATCHLOGS)) + .withCredentials(localstack.getDefaultCredentialsProvider()).build(); logs.createLogGroup(new CreateLogGroupRequest("foo")); @@ -160,6 +159,19 @@ public void kmsKeyCreationTest() { assertEquals("AWS KMS Customer Managed Key should be created ", key.getKeyMetadata().getDescription(), desc); } + + @Test + public void samePortIsExposedForAllServices() { + assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); + assertEquals( + "Endpoint overrides are different", + localstack.getEndpointOverride(S3).toString(), + localstack.getEndpointOverride(SQS).toString()); + assertEquals( + "Endpoint configuration have different endpoints", + localstack.getEndpointConfiguration(S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + } } public static class WithNetwork { @@ -167,14 +179,16 @@ public static class WithNetwork { private static Network network = Network.newNetwork(); @ClassRule - public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer(LOCALSTACK_IMAGE) + public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer( + DockerImageName.parse("localstack/localstack:0.11.0") + ) .withNetwork(network) .withNetworkAliases("notthis", "localstack") // the last alias is used for HOSTNAME_EXTERNAL .withServices(S3, SQS, CLOUDWATCHLOGS); // } @ClassRule - public static GenericContainer awsCliInDockerNetwork = new GenericContainer<>(AWS_CLI_IMAGE) + public static GenericContainer awsCliInDockerNetwork = new GenericContainer<>(LocalstackTestImages.AWS_CLI_IMAGE) .withNetwork(network) .withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("top")) .withEnv("AWS_ACCESS_KEY_ID", "accesskey") @@ -184,33 +198,33 @@ public static class WithNetwork { @Test public void s3TestOverDockerNetwork() throws Exception { - runAwsCliAgainstDockerNetworkContainer("s3api create-bucket --bucket foo", S3.getPort()); - runAwsCliAgainstDockerNetworkContainer("s3api list-buckets", S3.getPort()); - runAwsCliAgainstDockerNetworkContainer("s3 ls s3://foo", S3.getPort()); + runAwsCliAgainstDockerNetworkContainer("s3api create-bucket --bucket foo"); + runAwsCliAgainstDockerNetworkContainer("s3api list-buckets"); + runAwsCliAgainstDockerNetworkContainer("s3 ls s3://foo"); } @Test public void sqsTestOverDockerNetwork() throws Exception { - final String queueCreationResponse = runAwsCliAgainstDockerNetworkContainer("sqs create-queue --queue-name baz", SQS.getPort()); + final String queueCreationResponse = runAwsCliAgainstDockerNetworkContainer("sqs create-queue --queue-name baz"); assertThat("Created queue has external hostname URL", queueCreationResponse, - containsString("http://localstack:" + SQS.getPort())); + containsString("http://localstack:" + PORT)); runAwsCliAgainstDockerNetworkContainer( - String.format("sqs send-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz --message-body test", SQS.getPort(), SQS.getPort()), SQS.getPort()); + String.format("sqs send-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz --message-body test", PORT, PORT)); final String message = runAwsCliAgainstDockerNetworkContainer( - String.format("sqs receive-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz", SQS.getPort(), SQS.getPort()), SQS.getPort()); + String.format("sqs receive-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz", PORT, PORT)); assertTrue("the sent message can be received", message.contains("\"Body\": \"test\"")); } @Test public void cloudWatchLogsTestOverDockerNetwork() throws Exception { - runAwsCliAgainstDockerNetworkContainer("logs create-log-group --log-group-name foo", CLOUDWATCHLOGS.getPort()); + runAwsCliAgainstDockerNetworkContainer("logs create-log-group --log-group-name foo"); } - private String runAwsCliAgainstDockerNetworkContainer(String command, final int port) throws Exception { - final String[] commandParts = String.format("/usr/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", command, port).split(" "); + private String runAwsCliAgainstDockerNetworkContainer(String command) throws Exception { + final String[] commandParts = String.format("/usr/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", command, PORT).split(" "); final Container.ExecResult execResult = awsCliInDockerNetwork.execInContainer(commandParts); Assert.assertEquals(0, execResult.getExitCode()); diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java new file mode 100644 index 00000000000..60e5498daf3 --- /dev/null +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java @@ -0,0 +1,8 @@ +package org.testcontainers.containers.localstack; + +import org.testcontainers.utility.DockerImageName; + +public interface LocalstackTestImages { + DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.11.0"); + DockerImageName AWS_CLI_IMAGE = DockerImageName.parse("atlassian/pipelines-awscli:1.16.302"); +} From dd0d21837e7062762969dac3c25207f445b70e0d Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 19 Jul 2020 19:43:10 +0100 Subject: [PATCH 0873/4969] Add latest backers --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 4894297f034..131a9074bfd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -137,6 +137,8 @@ A huge thank you to our backers: * [Lukas Eder (@lukaseder)](https://github.com/lukaseder) * [Fedor Korotkov (@fkorotkov)](https://github.com/fkorotkov) * [Christoph Dreis (@dreis2211)](https://github.com/dreis2211) +* [Pascal Zwick (@pas2al)](https://github.com/pas2al) +* [Nikita Zhevnitskiy (@zhenik)](https://github.com/zhenik) ## License From 706a6697408ef3c9ca98e5d7ab559e4ccfdf8cff Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 27 Jul 2020 18:30:22 +0200 Subject: [PATCH 0874/4969] Fix the Rootless Docker CI job (#3050) --- .github/workflows/ci-rootless.yml | 23 ++++++-- .../RootlessDockerClientProviderStrategy.java | 54 +++++++++++++++++-- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index e752747b804..7dacc2767a5 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -7,6 +7,14 @@ on: jobs: test: runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + include: + - { XDG_RUNTIME_DIR: "" } + - { XDG_RUNTIME_DIR: "/tmp/docker-testcontainers/" } + env: + XDG_RUNTIME_DIR: ${{ matrix.XDG_RUNTIME_DIR }} steps: - uses: actions/checkout@v2 - name: debug @@ -14,17 +22,22 @@ jobs: - name: uninstall rootful Docker run: sudo apt-get -q -y --purge remove moby-engine moby-buildx && sudo rm -rf /var/run/docker.sock - name: install rootless Docker - run: curl -fsSL https://get.docker.com/rootless | sh - - name: start rootless Docker - run: PATH=$HOME/bin:$PATH XDG_RUNTIME_DIR=/tmp/docker-$(id -u) dockerd-rootless.sh --experimental --storage-driver vfs & + run: | + mkdir -p $XDG_RUNTIME_DIR || true + curl -fsSL https://get.docker.com/rootless | sh > init.sh + cat init.sh + source <(grep '^export' init.sh) + PATH=$HOME/bin:$PATH dockerd-rootless.sh --experimental --storage-driver vfs & + sleep 1 + DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock docker info || ls -la $XDG_RUNTIME_DIR - name: Build with Gradle - run: XDG_RUNTIME_DIR=/tmp/docker-$(id -u) ./gradlew --no-daemon --scan testcontainers:test + run: ./gradlew --no-daemon --scan testcontainers:test - name: aggregate test reports with ciMate if: always() continue-on-error: true env: CIMATE_PROJECT_ID: 2348n4vl - CIMATE_CI_KEY: "CI / rootless Docker" + CIMATE_CI_KEY: "CI / rootless Docker (${{ matrix.XDG_RUNTIME_DIR }})" run: | wget -q https://get.cimate.io/release/linux/cimate chmod +x cimate diff --git a/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java index cc6b23e506d..3ee58f4910a 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java @@ -2,28 +2,72 @@ import com.sun.jna.Library; import com.sun.jna.Native; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; +import org.jetbrains.annotations.Nullable; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; /** * * @deprecated this class is used by the SPI and should not be used directly */ @Deprecated +@Slf4j public final class RootlessDockerClientProviderStrategy extends DockerClientProviderStrategy { public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY + 1; - private Path getSocketPath() { + @Getter(lazy = true) + @Nullable + private final Path socketPath = resolveSocketPath(); + + private Path resolveSocketPath() { + return tryEnv().orElseGet(() -> { + Path homePath = Paths.get(System.getProperty("user.home")).resolve(".docker").resolve("run"); + return tryFolder(homePath).orElseGet(() -> { + Path implicitPath = Paths.get("/run/user/" + LibC.INSTANCE.getuid()); + return tryFolder(implicitPath).orElse(null); + }); + }); + } + + private Optional tryEnv() { String xdgRuntimeDir = System.getenv("XDG_RUNTIME_DIR"); - if (xdgRuntimeDir == null) { - xdgRuntimeDir = "/run/user/" + LibC.INSTANCE.getuid(); + if (StringUtils.isBlank(xdgRuntimeDir)) { + log.debug("$XDG_RUNTIME_DIR is not set."); + return Optional.empty(); + } + Path path = Paths.get(xdgRuntimeDir); + if (!Files.exists(path)) { + log.debug("$XDG_RUNTIME_DIR is set to '{}' but the folder does not exist.", path); + return Optional.empty(); + } + Path socketPath = path.resolve("docker.sock"); + if (!Files.exists(socketPath)) { + log.debug("$XDG_RUNTIME_DIR is set but '{}' does not exist.", socketPath); + return Optional.empty(); + } + return Optional.of(socketPath); + } + + private Optional tryFolder(Path path) { + if (!Files.exists(path)) { + log.debug("'{}' does not exist.", path); + return Optional.empty(); + } + Path socketPath = path.resolve("docker.sock"); + if (!Files.exists(socketPath)) { + log.debug("'{}' does not exist.", socketPath); + return Optional.empty(); } - return Paths.get(xdgRuntimeDir).resolve("docker.sock"); + return Optional.of(socketPath); } @Override @@ -35,7 +79,7 @@ public TransportConfig getTransportConfig() throws InvalidConfigurationException @Override protected boolean isApplicable() { - return SystemUtils.IS_OS_LINUX && Files.exists(getSocketPath()); + return SystemUtils.IS_OS_LINUX && getSocketPath() != null && Files.exists(getSocketPath()); } @Override From 32c05bd88f120d1b9225f01ed683febd82df0b50 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 28 Jul 2020 13:44:05 +0200 Subject: [PATCH 0875/4969] limit to a subset of rootless tests --- .github/workflows/ci-rootless.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index 7dacc2767a5..bf1fe08bbd2 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -31,7 +31,7 @@ jobs: sleep 1 DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock docker info || ls -la $XDG_RUNTIME_DIR - name: Build with Gradle - run: ./gradlew --no-daemon --scan testcontainers:test + run: ./gradlew --no-daemon --scan testcontainers:test --tests '*GenericContainerRuleTest' - name: aggregate test reports with ciMate if: always() continue-on-error: true From d50d01bd3a86c5540ea44515b0b1e2722e1283c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2020 20:25:10 +0100 Subject: [PATCH 0876/4969] Bump cucumber-java from 6.1.1 to 6.2.2 in /examples (#3040) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index d17837f1518..0ea976800a6 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:6.1.1' + testImplementation 'io.cucumber:cucumber-java:6.2.2' testImplementation 'io.cucumber:cucumber-junit:6.1.1' testImplementation 'org.testcontainers:selenium' } From 23f310c0aa41f2f5d836d44f4dab892c9e1508d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:05:06 +0100 Subject: [PATCH 0877/4969] Bump cucumber-junit from 6.1.1 to 6.2.2 in /examples (#3041) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 6.1.1 to 6.2.2. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.1.1...v6.2.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 0ea976800a6..ae211cedc04 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.2.2' - testImplementation 'io.cucumber:cucumber-junit:6.1.1' + testImplementation 'io.cucumber:cucumber-junit:6.2.2' testImplementation 'org.testcontainers:selenium' } From 6aa2c567229c05ffaeedb478e13019442cbd8c55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:06:38 +0100 Subject: [PATCH 0878/4969] Bump commons-lang3 from 3.10 to 3.11 in /modules/jdbc-test (#3043) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 0c06ad083e0..f19970c9380 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -3,7 +3,7 @@ dependencies { compile project(':test-support') compile 'com.google.guava:guava:29.0-jre' - compile 'org.apache.commons:commons-lang3:3.10' + compile 'org.apache.commons:commons-lang3:3.11' compile 'com.zaxxer:HikariCP-java6:2.3.13' compile 'commons-dbutils:commons-dbutils:1.7' From 95ac56c15524c17c4103ceee44b4b23849d08366 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:07:19 +0100 Subject: [PATCH 0879/4969] Bump s3 from 2.13.50 to 2.13.61 in /modules/localstack (#3028) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 6e9e44af320..3ce019b0549 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.816' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.812' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.13.50' + testCompile 'software.amazon.awssdk:s3:2.13.61' } From a0ac5449efaeed0bc62143d0a52ef472e2c6b0ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:13:00 +0100 Subject: [PATCH 0880/4969] Bump okhttp from 4.7.2 to 4.8.0 in /examples (#3042) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index f56b8bc46d8..75bc7f3b0e8 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:4.7.2' + implementation 'com.squareup.okhttp3:okhttp:4.8.0' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.14' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 10dbdd98bed6c67989de277e4093eb219396169a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:38:56 +0100 Subject: [PATCH 0881/4969] Bump r2dbc-mssql from 0.8.3.RELEASE to 0.8.4.RELEASE in /modules/mssqlserver (#3033) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index d9e01fe3a57..508de84a2f9 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-mssql:0.8.3.RELEASE' + compileOnly 'io.r2dbc:r2dbc-mssql:0.8.4.RELEASE' testCompile project(':jdbc-test') testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.1.jre8-preview' From 2056268178db93a66e16449f2afd62e4e0cd104b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:46:18 +0100 Subject: [PATCH 0882/4969] Bump mysql-connector-java from 8.0.20 to 8.0.21 in /modules/spock (#3032) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index ee4ac56053f..1a9eddf4ffc 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.12' testRuntime 'org.postgresql:postgresql:42.2.14' - testRuntime 'mysql:mysql-connector-java:8.0.20' + testRuntime 'mysql:mysql-connector-java:8.0.21' } sourceJar { From ed6b1175e0c3780ed4acaccc22bf7f71800a735c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:46:34 +0100 Subject: [PATCH 0883/4969] Bump r2dbc-postgresql from 0.8.3.RELEASE to 0.8.4.RELEASE in /modules/postgresql (#3035) Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.3.RELEASE to 0.8.4.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.4.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.3.RELEASE...v0.8.4.RELEASE) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 7e6adea9cf1..8f30490eeb8 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.4.RELEASE' testCompile project(':jdbc-test') testCompile project(':test-support') From d12d337e64e4dc4a76da5d04a0fe94547837155b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:46:46 +0100 Subject: [PATCH 0884/4969] Bump mariadb-java-client from 2.6.1 to 2.6.2 in /modules/mariadb (#3034) Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.6.1 to 2.6.2. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.6.1...2.6.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index a4f2f951233..775854748dc 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:0.8.2-alpha2' testCompile project(':jdbc-test') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.1' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.2' testCompile testFixtures(project(':r2dbc')) testCompile 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' From 0f0eaee72b5ae6971e441549bbdb117f91be9d3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:47:04 +0100 Subject: [PATCH 0885/4969] Bump r2dbc-mariadb from 0.8.2-alpha2 to 0.8.3-beta1 in /modules/mariadb (#3036) Bumps [r2dbc-mariadb](https://github.com/mariadb-corporation/mariadb-connector-r2dbc) from 0.8.2-alpha2 to 0.8.3-beta1. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/mariadb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 775854748dc..94164468855 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,11 +7,11 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'org.mariadb:r2dbc-mariadb:0.8.2-alpha2' + compileOnly 'org.mariadb:r2dbc-mariadb:0.8.3-beta1' testCompile project(':jdbc-test') testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.2' testCompile testFixtures(project(':r2dbc')) - testCompile 'org.mariadb:r2dbc-mariadb:0.8.1-alpha1' + testCompile 'org.mariadb:r2dbc-mariadb:0.8.3-beta1' } From 495a7309ba2f20d76e3265176dfe9d6696238558 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:47:16 +0100 Subject: [PATCH 0886/4969] Bump mysql-connector-java from 8.0.20 to 8.0.21 in /modules/junit-jupiter (#3037) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.20 to 8.0.21. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.20...8.0.21) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ffc060d8b01..aedffacfc58 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' testRuntime 'org.postgresql:postgresql:42.2.14' - testRuntime 'mysql:mysql-connector-java:8.0.20' + testRuntime 'mysql:mysql-connector-java:8.0.21' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' } From b87f9930d83738880eda5674237ae88d44ffbf5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:47:46 +0100 Subject: [PATCH 0887/4969] Bump org.springframework.boot from 2.3.1.RELEASE to 2.3.2.RELEASE in /examples (#3039) Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.3.1.RELEASE to 2.3.2.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.1.RELEASE...v2.3.2.RELEASE) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index dc59ca877ab..e8a7861a7d9 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.1.RELEASE' + id 'org.springframework.boot' version '2.3.2.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 060a7f48357..4821f0921e3 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.1.RELEASE' + id 'org.springframework.boot' version '2.3.2.RELEASE' } apply plugin: 'io.spring.dependency-management' From eb7d15e2ff665f062333e28d839d6ce412f0c735 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:47:55 +0100 Subject: [PATCH 0888/4969] Bump mockito-core from 3.3.3 to 3.4.4 in /modules/junit-jupiter (#3038) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index aedffacfc58..05ad7d34930 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testCompile ('org.mockito:mockito-core:3.3.3') { + testCompile ('org.mockito:mockito-core:3.4.4') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.16.1' From 97f738ee3b85b43f7d3d3639140df9f18e9f0cdb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:48:14 +0100 Subject: [PATCH 0889/4969] Bump mysql-connector-java from 8.0.20 to 8.0.21 in /modules/mysql (#3045) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.20 to 8.0.21. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.20...8.0.21) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index c9c165cc874..bf96ab89536 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' testCompile project(':jdbc-test') - testCompile 'mysql:mysql-connector-java:8.0.20' + testCompile 'mysql:mysql-connector-java:8.0.21' testCompile testFixtures(project(':r2dbc')) testCompile 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' From e37b63278b3f62f33104849ce2b5e19d9197772f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 20:55:36 +0100 Subject: [PATCH 0890/4969] Bump mysql-connector-java from 8.0.20 to 8.0.21 in /modules/jdbc-test (#3044) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.20 to 8.0.21. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.20...8.0.21) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index f19970c9380..d8df69b094f 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -17,5 +17,5 @@ dependencies { compile 'commons-dbutils:commons-dbutils:1.7' compile 'org.apache.tomcat:tomcat-jdbc:9.0.37' compile 'org.vibur:vibur-dbcp:25.0' - compile 'mysql:mysql-connector-java:8.0.20' + compile 'mysql:mysql-connector-java:8.0.21' } From b20eca8e2cc65d7aa98fe58d55a6af3d2893fd16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 21:18:47 +0100 Subject: [PATCH 0891/4969] Bump aws-java-sdk-sqs from 1.11.812 to 1.11.831 in /modules/localstack (#3063) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.812 to 1.11.831. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.812...1.11.831) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3ce019b0549..3deb07dd139 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.816' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.816' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.812' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.831' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.13.61' } From 2b37cab5cfd7f9949fdc0eb64060cc4d8cfd250e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 21:34:00 +0100 Subject: [PATCH 0892/4969] Bump aws-java-sdk-s3 from 1.11.816 to 1.11.831 in /modules/localstack (#3064) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.816 to 1.11.831. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.816...1.11.831) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3deb07dd139..ad5808a97b2 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.816' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.831' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.816' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.831' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From 65d35cea4bcb49736c3476d709f434a731c0a0de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 21:44:25 +0100 Subject: [PATCH 0893/4969] Bump r2dbc-mysql from 0.8.1.RELEASE to 0.8.2.RELEASE in /modules/mysql (#3046) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index bf96ab89536..3badd2e18e1 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' + compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testCompile project(':jdbc-test') testCompile 'mysql:mysql-connector-java:8.0.21' From aebc512d5659e98035290ba14df1f18ca4d94350 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2020 21:44:44 +0100 Subject: [PATCH 0894/4969] Bump mockito-core from 3.3.3 to 3.4.6 in /core (#3065) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.3.3 to 3.4.6. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.3.3...v3.4.6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 98452944bd0..07cee319f5a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -204,7 +204,7 @@ dependencies { testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.5' - testCompile ('org.mockito:mockito-core:3.3.3') { + testCompile ('org.mockito:mockito-core:3.4.6') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 003c741e40da037f1b9247ab7e37cbac87e6f371 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2020 09:15:04 +0100 Subject: [PATCH 0895/4969] Bump mongo-java-driver from 3.12.5 to 3.12.6 in /core (#3024) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.5 to 3.12.6. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.5...r3.12.6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 07cee319f5a..894990fe9a0 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -202,7 +202,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.3.0' testCompile 'com.rabbitmq:amqp-client:5.9.0' - testCompile 'org.mongodb:mongo-java-driver:3.12.5' + testCompile 'org.mongodb:mongo-java-driver:3.12.6' testCompile ('org.mockito:mockito-core:3.4.6') { exclude(module: 'hamcrest-core') From 082b094d7edd0733c536f23208e55346d53abfb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2020 09:16:05 +0100 Subject: [PATCH 0896/4969] Bump aws-java-sdk-dynamodb from 1.11.816 to 1.11.827 in /modules/dynalite (#3027) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.816 to 1.11.827. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.816...1.11.827) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index b3919a3eaf3..d04705cb4d4 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.816' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.812' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.827' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.827' } From 0c69b448252ebd34e354289bcfb938767c7f7dd1 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Sat, 1 Aug 2020 16:44:34 +0200 Subject: [PATCH 0897/4969] Add some more logs to bash script used for DockerHealthcheckWaitStratgyTest (#2988) Co-authored-by: Sergei Egorov Co-authored-by: Richard North --- .../health-wait-strategy-dockerfile/write_file_and_loop.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/resources/health-wait-strategy-dockerfile/write_file_and_loop.sh b/core/src/test/resources/health-wait-strategy-dockerfile/write_file_and_loop.sh index a102129394b..3a688ee3f4f 100755 --- a/core/src/test/resources/health-wait-strategy-dockerfile/write_file_and_loop.sh +++ b/core/src/test/resources/health-wait-strategy-dockerfile/write_file_and_loop.sh @@ -1,8 +1,8 @@ #!/bin/ash -echo sleeping +set -ex + sleep 2 -echo writing file touch /testfile while true; do sleep 1; done From 135a61eb2b1fc5b36c1e0eea57bbe6efca641930 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 16:45:27 +0100 Subject: [PATCH 0898/4969] Bump kafka-clients from 2.5.0 to 2.6.0 in /modules/kafka (#3085) Bumps kafka-clients from 2.5.0 to 2.6.0. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 06090c5b35e..3d8a663a0e9 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.5.0' + testCompile 'org.apache.kafka:kafka-clients:2.6.0' testCompile 'org.assertj:assertj-core:3.16.1' testCompile 'com.google.guava:guava:23.0' } From 22eb3f6e126d71e402ae47b5cad980780f8137e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 16:45:47 +0100 Subject: [PATCH 0899/4969] Bump aws-java-sdk-s3 from 1.11.831 to 1.11.837 in /modules/localstack (#3088) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.831 to 1.11.837. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.831...1.11.837) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ad5808a97b2..372407baa41 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.831' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.816' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.837' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.837' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.831' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.13.61' From c8adfb5ad6829196fea3c8fd9eff148c23b83b98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:17:22 +0100 Subject: [PATCH 0900/4969] Bump mongo-java-driver from 3.12.6 to 3.12.7 in /core (#3104) Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.6 to 3.12.7. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.6...r3.12.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 894990fe9a0..81c0c20608c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -202,7 +202,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.9' testCompile 'redis.clients:jedis:3.3.0' testCompile 'com.rabbitmq:amqp-client:5.9.0' - testCompile 'org.mongodb:mongo-java-driver:3.12.6' + testCompile 'org.mongodb:mongo-java-driver:3.12.7' testCompile ('org.mockito:mockito-core:3.4.6') { exclude(module: 'hamcrest-core') From e99822c1b18bbde6c5aeeabab1477e8a3fc8d18b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:17:38 +0100 Subject: [PATCH 0901/4969] Bump mockito-core from 3.4.6 to 3.5.0 in /core (#3105) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.4.6 to 3.5.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.4.6...v3.5.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 81c0c20608c..4c1a47255ce 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -204,7 +204,7 @@ dependencies { testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' - testCompile ('org.mockito:mockito-core:3.4.6') { + testCompile ('org.mockito:mockito-core:3.5.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 36f9e2be29641391df373566e904010522d41213 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:17:54 +0100 Subject: [PATCH 0902/4969] Bump postgresql from 42.2.14 to 42.2.15 in /examples (#3108) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.14 to 42.2.15. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.14...REL42.2.15) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 75bc7f3b0e8..9af26701f34 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.8.0' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.14' + testImplementation 'org.postgresql:postgresql:42.2.15' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From 91c718d7951435f35e541fb54ba709591783e5c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:18:19 +0100 Subject: [PATCH 0903/4969] Bump cucumber-junit from 6.2.2 to 6.4.0 in /examples (#3109) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 6.2.2 to 6.4.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.2.2...v6.4.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index ae211cedc04..6d56e68473e 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.2.2' - testImplementation 'io.cucumber:cucumber-junit:6.2.2' + testImplementation 'io.cucumber:cucumber-junit:6.4.0' testImplementation 'org.testcontainers:selenium' } From 5653f0e80d0ed9e943a73ebdbd94ad005ea43c83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:18:48 +0100 Subject: [PATCH 0904/4969] Bump okhttp from 4.8.0 to 4.8.1 in /examples (#3106) Bumps [okhttp](https://github.com/square/okhttp) from 4.8.0 to 4.8.1. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.8.0...parent-4.8.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 9af26701f34..a62854e9b35 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:4.8.0' + implementation 'com.squareup.okhttp3:okhttp:4.8.1' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.15' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 82bc1658c55ff3828687cd2e9aa1e3d48e395535 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:19:12 +0100 Subject: [PATCH 0905/4969] Bump aws-java-sdk-dynamodb from 1.11.827 to 1.11.837 in /modules/dynalite (#3090) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index d04705cb4d4..fce2e17bd88 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.827' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.837' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.827' } From 36f31d6a759eda6b4177d2c0695b65d090702a4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:21:33 +0100 Subject: [PATCH 0906/4969] Bump solr-solrj from 8.5.2 to 8.6.1 in /examples (#3107) Bumps solr-solrj from 8.5.2 to 8.6.1. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 5845753cb08..89444aeb378 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.10" annotationProcessor "org.projectlombok:lombok:1.18.10" - implementation 'org.apache.solr:solr-solrj:8.5.2' + implementation 'org.apache.solr:solr-solrj:8.6.1' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From 8de8a0a2e323a5962410194ad3b49ecf10cc2521 Mon Sep 17 00:00:00 2001 From: Artjom Kalita Date: Thu, 20 Aug 2020 10:23:42 +0300 Subject: [PATCH 0907/4969] Whitespace configuration fix (#3127, fixes #3053) Co-authored-by: artjom.kalita --- .../utility/TestcontainersConfiguration.java | 24 ++++++++++--------- .../TestcontainersConfigurationTest.java | 4 ++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 1939e8e21b3..9f283ba2685 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -37,7 +37,7 @@ public class TestcontainersConfiguration { private static File ENVIRONMENT_CONFIG_FILE = new File(System.getProperty("user.home"), "." + PROPERTIES_FILE_NAME); @Getter(lazy = true) - private static final TestcontainersConfiguration instance = loadConfiguration();; + private static final TestcontainersConfiguration instance = loadConfiguration(); @SuppressWarnings({"ConstantConditions", "unchecked", "rawtypes"}) @VisibleForTesting @@ -56,16 +56,18 @@ static AtomicReference getInstanceField() { this.properties.putAll(classpathProperties); this.properties.putAll(environmentProperties); + properties.keySet() + .forEach(key -> properties.replace(key, properties.getProperty(String.valueOf(key)).trim())); } @Deprecated public String getAmbassadorContainerImage() { - return (String) properties.getOrDefault("ambassador.container.image", "richnorth/ambassador:latest"); + return String.valueOf(properties.getOrDefault("ambassador.container.image", "richnorth/ambassador:latest")); } @Deprecated public String getSocatContainerImage() { - return (String) properties.getOrDefault("socat.container.image", "alpine/socat:latest"); + return String.valueOf(properties.getOrDefault("socat.container.image", "alpine/socat:latest")); } public DockerImageName getSocatDockerImageName() { @@ -74,7 +76,7 @@ public DockerImageName getSocatDockerImageName() { @Deprecated public String getVncRecordedContainerImage() { - return (String) properties.getOrDefault("vncrecorder.container.image", "testcontainers/vnc-recorder:1.1.0"); + return String.valueOf(properties.getOrDefault("vncrecorder.container.image", "testcontainers/vnc-recorder:1.1.0")); } public DockerImageName getVncDockerImageName() { @@ -83,7 +85,7 @@ public DockerImageName getVncDockerImageName() { @Deprecated public String getDockerComposeContainerImage() { - return (String) properties.getOrDefault("compose.container.image", "docker/compose:1.24.1"); + return String.valueOf(properties.getOrDefault("compose.container.image", "docker/compose:1.24.1")); } public DockerImageName getDockerComposeDockerImageName() { @@ -92,7 +94,7 @@ public DockerImageName getDockerComposeDockerImageName() { @Deprecated public String getTinyImage() { - return (String) properties.getOrDefault("tinyimage.container.image", "alpine:3.5"); + return String.valueOf(properties.getOrDefault("tinyimage.container.image", "alpine:3.5")); } public DockerImageName getTinyDockerImageName() { @@ -105,7 +107,7 @@ public boolean isRyukPrivileged() { @Deprecated public String getRyukImage() { - return (String) properties.getOrDefault("ryuk.container.image", "testcontainers/ryuk:0.3.0"); + return String.valueOf(properties.getOrDefault("ryuk.container.image", "testcontainers/ryuk:0.3.0")); } public DockerImageName getRyukDockerImageName() { @@ -114,7 +116,7 @@ public DockerImageName getRyukDockerImageName() { @Deprecated public String getSSHdImage() { - return (String) properties.getOrDefault("sshd.container.image", "testcontainers/sshd:1.0.0"); + return String.valueOf(properties.getOrDefault("sshd.container.image", "testcontainers/sshd:1.0.0")); } public DockerImageName getSSHdDockerImageName() { @@ -127,7 +129,7 @@ public Integer getRyukTimeout() { @Deprecated public String getKafkaImage() { - return (String) properties.getOrDefault("kafka.container.image", "confluentinc/cp-kafka"); + return String.valueOf(properties.getOrDefault("kafka.container.image", "confluentinc/cp-kafka")); } public DockerImageName getKafkaDockerImageName() { @@ -136,7 +138,7 @@ public DockerImageName getKafkaDockerImageName() { @Deprecated public String getPulsarImage() { - return (String) properties.getOrDefault("pulsar.container.image", "apachepulsar/pulsar"); + return String.valueOf(properties.getOrDefault("pulsar.container.image", "apachepulsar/pulsar")); } public DockerImageName getPulsarDockerImageName() { @@ -145,7 +147,7 @@ public DockerImageName getPulsarDockerImageName() { @Deprecated public String getLocalStackImage() { - return (String) properties.getOrDefault("localstack.container.image", "localstack/localstack"); + return String.valueOf(properties.getOrDefault("localstack.container.image", "localstack/localstack")); } public DockerImageName getLocalstackDockerImageName() { diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index 49a378554f1..f0b8fb36a37 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -46,6 +46,10 @@ public void shouldReadReuseFromEnvironmentOnly() { environmentProperties.setProperty("testcontainers.reuse.enable", "true"); assertTrue("reuse enabled", newConfig().environmentSupportsReuse()); + + environmentProperties.setProperty("ryuk.container.image", " testcontainersofficial/ryuk:0.3.0 "); + assertEquals("trailing whitespace was not removed from image name property", "testcontainersofficial/ryuk:0.3.0",newConfig().getRyukImage()); + } private TestcontainersConfiguration newConfig() { From 14a6a09eb7893e8e356ffa4ced29a9d098b523e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:52:41 +0100 Subject: [PATCH 0908/4969] Bump s3 from 2.13.61 to 2.13.76 in /modules/localstack (#3114) Bumps s3 from 2.13.61 to 2.13.76. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 372407baa41..f77d286bfca 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.837' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.831' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.13.61' + testCompile 'software.amazon.awssdk:s3:2.13.76' } From 37df788493c470d7994aea463d777a5de9559027 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 20 Aug 2020 09:05:53 +0100 Subject: [PATCH 0909/4969] Add continue-on-error for cache step, and upgrade GH cache action (#3133) --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 668dde2b28c..2b5a37a3405 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,8 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v1 + uses: actions/cache@v2 + continue-on-error: true with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} From 2543ea885427d61cec16ae1e0c72a964a928f691 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:06:19 +0100 Subject: [PATCH 0910/4969] Bump aws-java-sdk-s3 from 1.11.837 to 1.11.846 in /modules/localstack (#3131) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index f77d286bfca..d018846c1aa 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.837' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.846' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.837' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.831' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From d9dd5a7692ffcbbf0ce1d3eccb175c5b1dead2ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:06:38 +0100 Subject: [PATCH 0911/4969] Bump aws-java-sdk-sqs from 1.11.831 to 1.11.846 in /modules/localstack (#3132) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.831 to 1.11.846. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.831...1.11.846) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d018846c1aa..9891879fc1a 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.846' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.837' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.831' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.846' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.13.76' } From 09479d1df577c408f61bdea40c6808f30db02348 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:06:54 +0100 Subject: [PATCH 0912/4969] Bump cucumber-java from 6.2.2 to 6.4.0 in /examples (#3112) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 6.2.2 to 6.4.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.2.2...v6.4.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 6d56e68473e..90cc99e7627 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:6.2.2' + testImplementation 'io.cucumber:cucumber-java:6.4.0' testImplementation 'io.cucumber:cucumber-junit:6.4.0' testImplementation 'org.testcontainers:selenium' } From 58c4cf2d6e8b33046c3ca0ec206acef8f4070065 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:07:10 +0100 Subject: [PATCH 0913/4969] Bump postgresql from 42.2.14 to 42.2.15 in /modules/postgresql (#3113) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.14 to 42.2.15. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.14...REL42.2.15) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 8f30490eeb8..894930bc258 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':jdbc-test') testCompile project(':test-support') - testCompile 'org.postgresql:postgresql:42.2.14' + testCompile 'org.postgresql:postgresql:42.2.15' testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' From 9790538a45f8104dc8e24f26fc5ad5028dd0a498 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:07:25 +0100 Subject: [PATCH 0914/4969] Bump postgresql from 42.2.14 to 42.2.15 in /modules/junit-jupiter (#3115) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.14 to 42.2.15. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.14...REL42.2.15) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 05ad7d34930..ebc03695d0d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'org.assertj:assertj-core:3.16.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' - testRuntime 'org.postgresql:postgresql:42.2.14' + testRuntime 'org.postgresql:postgresql:42.2.15' testRuntime 'mysql:mysql-connector-java:8.0.21' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' } From 47f3fb71833fc388796ec9fa287908192045b29a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:09:12 +0100 Subject: [PATCH 0915/4969] Bump mockito-core from 3.4.4 to 3.5.2 in /modules/junit-jupiter (#3130) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.4.4 to 3.5.2. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.4.4...v3.5.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ebc03695d0d..6e37336545d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testCompile ('org.mockito:mockito-core:3.4.4') { + testCompile ('org.mockito:mockito-core:3.5.2') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.16.1' From 0b6007956ca3f794aad0cfe43be4dfaca6b0c111 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:09:23 +0100 Subject: [PATCH 0916/4969] Bump org.springframework.boot from 2.3.2.RELEASE to 2.3.3.RELEASE in /examples (#3111) Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.3.2.RELEASE to 2.3.3.RELEASE. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.2.RELEASE...v2.3.3.RELEASE) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index e8a7861a7d9..eb9c2d9ce3a 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.2.RELEASE' + id 'org.springframework.boot' version '2.3.3.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 4821f0921e3..d74851d8eac 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.2.RELEASE' + id 'org.springframework.boot' version '2.3.3.RELEASE' } apply plugin: 'io.spring.dependency-management' From b1a1dd1c422b2c1f445df81283bf0d1364a72cdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 10:04:27 +0100 Subject: [PATCH 0917/4969] Bump influxdb-java from 2.19 to 2.20 in /modules/influxdb (#3120) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/influxdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index 2deacd3a149..40fa6e456ce 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { compile project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.19' + compileOnly 'org.influxdb:influxdb-java:2.20' testCompile 'org.influxdb:influxdb-java:2.19' } From 6bdbc8ffe257fc879791eb7fddcf3b5ecccdd52d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 10:04:35 +0100 Subject: [PATCH 0918/4969] Bump postgresql from 42.2.14 to 42.2.15 in /modules/spock (#3119) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.14 to 42.2.15. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.14...REL42.2.15) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 1a9eddf4ffc..eb2914ae3ac 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testRuntime 'org.postgresql:postgresql:42.2.14' + testRuntime 'org.postgresql:postgresql:42.2.15' testRuntime 'mysql:mysql-connector-java:8.0.21' } From 93504a5ca04f5d86c604242124fe5e96ae553bf8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 11:57:58 +0100 Subject: [PATCH 0919/4969] Bump assertj-core from 3.16.1 to 3.17.0 in /modules/pulsar (#3153) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.16.1 to 3.17.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index a8f55696a65..493c5fa4c32 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.0' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.16.1' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.0' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.0' } From 2459cab02a914db9a1f554104a13b5180d441dc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 11:58:27 +0100 Subject: [PATCH 0920/4969] Bump aws-java-sdk-dynamodb from 1.11.837 to 1.11.847 in /modules/dynalite (#3150) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.837 to 1.11.847. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.837...1.11.847) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index fce2e17bd88..762e189173b 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.837' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.827' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.847' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.847' } From 4f056827712a475e0db0d45380f1d0d10e45870a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 11:58:39 +0100 Subject: [PATCH 0921/4969] Bump aws-java-sdk-s3 from 1.11.846 to 1.11.847 in /modules/localstack (#3148) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.846 to 1.11.847. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.846...1.11.847) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9891879fc1a..acf42539c88 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.846' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.837' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.847' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.847' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.846' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.13.76' From b236eacd54f6362a138f2582f04501cdb8bab5e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:00:11 +0100 Subject: [PATCH 0922/4969] Bump postgresql from 42.2.15 to 42.2.16 in /modules/junit-jupiter (#3142) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.15 to 42.2.16. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.15...REL42.2.16) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 6e37336545d..28f48cf94bb 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'org.assertj:assertj-core:3.16.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' - testRuntime 'org.postgresql:postgresql:42.2.15' + testRuntime 'org.postgresql:postgresql:42.2.16' testRuntime 'mysql:mysql-connector-java:8.0.21' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' } From c42c8eebad51206be675ad330d5c8aefe07f230d Mon Sep 17 00:00:00 2001 From: Waldemar Panas <8766331+wpanas@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:01:35 +0200 Subject: [PATCH 0923/4969] #3129 Fix dead link for CircleCI configuration (#3156) Co-authored-by: wpanas --- docs/supported_docker_environment/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/index.md b/docs/supported_docker_environment/index.md index 7622a5051cd..04cc0c9ee2b 100644 --- a/docs/supported_docker_environment/index.md +++ b/docs/supported_docker_environment/index.md @@ -6,7 +6,7 @@ |-------------------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Linux - general | Docker v1.10 | | | Linux - Travis CI | Docker v1.10 | See [example .travis.yml](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/.travis.yml) for baseline Travis CI configuration | -| Linux - Circle CI (LXC driver) | Docker v1.9.1 | The `exec` feature is not compatible with Circle CI. See [example circle.yml](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/circle.yml) for baseline CircleCI configuration | +| Linux - CircleCI (LXC driver) | Docker v1.9.1 | The `exec` feature is not compatible with CircleCI. See CircleCI configuration [example](./continuous_integration/circle_ci.md) | | Linux - within a Docker container | Docker v1.12 | See [Running inside Docker](continuous_integration/dind_patterns.md) for Docker-in-Docker and Docker wormhole patterns | | Mac OS X - Docker Toolbox | Docker Machine v0.8.0 | | | Mac OS X - Docker for Mac | 1.12.0 | *Support is best-efforts at present*. `getTestHostIpAddress()` is [not currently supported](https://github.com/testcontainers/testcontainers-java/issues/166) due to limitations in Docker for Mac. | From 21af1b9045f2998588375a90d975ac8aca95535c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:01:54 +0100 Subject: [PATCH 0924/4969] Bump elasticsearch-rest-client from 7.8.0 to 7.9.0 in /modules/elasticsearch (#3152) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.8.0 to 7.9.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.8.0...v7.9.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 591760d7b0e..20097bd19b4 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.8.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.9.0" testCompile "org.elasticsearch.client:transport:6.7.1" } From 1c442c9063474f1c4b722a768dec1f4f2a737346 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:24:52 +0100 Subject: [PATCH 0925/4969] Bump pulsar-client-admin from 2.6.0 to 2.6.1 in /modules/pulsar (#3154) Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.6.0...v2.6.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 493c5fa4c32..9aaed8e23fd 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.0' - testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.1' } From 698738cacf662ef2f626f8e59b78b559ef5a14ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:25:04 +0100 Subject: [PATCH 0926/4969] Bump assertj-core from 3.16.1 to 3.17.0 in /modules/vault (#3146) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.16.1 to 3.17.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 0d094905198..5c83cbbb56f 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.1' - testCompile 'org.assertj:assertj-core:3.16.1' + testCompile 'org.assertj:assertj-core:3.17.0' } From b5bf40cc58a13ea18c02a36764e40b1528869609 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:25:11 +0100 Subject: [PATCH 0927/4969] Bump postgresql from 42.2.15 to 42.2.16 in /modules/postgresql (#3145) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.15 to 42.2.16. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.15...REL42.2.16) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 894930bc258..720c1d493a5 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':jdbc-test') testCompile project(':test-support') - testCompile 'org.postgresql:postgresql:42.2.15' + testCompile 'org.postgresql:postgresql:42.2.16' testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' From a0521e8e8e9a61d63e0fea81fd9dfabdc0df64fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:25:20 +0100 Subject: [PATCH 0928/4969] Bump assertj-core from 3.16.1 to 3.17.0 in /modules/junit-jupiter (#3144) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.16.1 to 3.17.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 28f48cf94bb..3aa19ddbfce 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.5.2') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.16.1' + testCompile 'org.assertj:assertj-core:3.17.0' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' testRuntime 'org.postgresql:postgresql:42.2.16' From 41cfc6ef1c6695065d1e84a90b873361ae0c99e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:25:34 +0100 Subject: [PATCH 0929/4969] Bump mockito-core from 3.5.2 to 3.5.5 in /modules/junit-jupiter (#3143) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.2 to 3.5.5. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.2...v3.5.5) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 3aa19ddbfce..d0c53a63f39 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testCompile ('org.mockito:mockito-core:3.5.2') { + testCompile ('org.mockito:mockito-core:3.5.5') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.17.0' From 6bca821edffef1680e045982bcf74e40560b3631 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 12:25:42 +0100 Subject: [PATCH 0930/4969] Bump pulsar-client from 2.6.0 to 2.6.1 in /modules/pulsar (#3155) Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.6.0...v2.6.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 9aaed8e23fd..a8f0d9f48ed 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.1' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.0' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.1' } From 86fa31b815717d98a1e7eda7cfd1b5a6e05a2a86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:27:35 +0100 Subject: [PATCH 0931/4969] Bump mockito-core from 3.5.0 to 3.5.7 in /core (#3164) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.0 to 3.5.7. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.0...v3.5.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4c1a47255ce..68bc339593a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -204,7 +204,7 @@ dependencies { testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' - testCompile ('org.mockito:mockito-core:3.5.0') { + testCompile ('org.mockito:mockito-core:3.5.7') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From fbc2b4ddd9521661981d98d9f88c317978dffd7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:27:44 +0100 Subject: [PATCH 0932/4969] Bump postgresql from 42.2.15 to 42.2.16 in /modules/spock (#3138) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.15 to 42.2.16. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.15...REL42.2.16) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index eb2914ae3ac..04a6682ee2f 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testRuntime 'org.postgresql:postgresql:42.2.15' + testRuntime 'org.postgresql:postgresql:42.2.16' testRuntime 'mysql:mysql-connector-java:8.0.21' } From 7bcfc6feb0c3741def110118a11974a69ba4a932 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:27:56 +0100 Subject: [PATCH 0933/4969] Bump mockito-core from 3.5.5 to 3.5.7 in /modules/junit-jupiter (#3163) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.5 to 3.5.7. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.5...v3.5.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index d0c53a63f39..d1368c2389a 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testCompile ('org.mockito:mockito-core:3.5.5') { + testCompile ('org.mockito:mockito-core:3.5.7') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.17.0' From 0f9ca21f11ddce2ff75a88b973dd0f71da632e00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:28:04 +0100 Subject: [PATCH 0934/4969] Bump assertj-core from 3.16.1 to 3.17.0 in /modules/kafka (#3139) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.16.1 to 3.17.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 3d8a663a0e9..a2b73ff4281 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.6.0' - testCompile 'org.assertj:assertj-core:3.16.1' + testCompile 'org.assertj:assertj-core:3.17.0' testCompile 'com.google.guava:guava:23.0' } From f42d3df752ba67e5f8a21438291286023f9abc65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:28:20 +0100 Subject: [PATCH 0935/4969] Bump s3 from 2.13.76 to 2.14.6 in /modules/localstack (#3162) Bumps s3 from 2.13.76 to 2.14.6. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index acf42539c88..e28117319f5 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.847' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.846' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.13.76' + testCompile 'software.amazon.awssdk:s3:2.14.6' } From 5397ddb51e3fcf3930910ba7f9adbbc4c97e6bb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:28:30 +0100 Subject: [PATCH 0936/4969] Bump assertj-core from 3.16.1 to 3.17.0 in /modules/neo4j (#3137) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.16.1 to 3.17.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 4bc92e49cda..2f5e6b05d9f 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.16.1' + testCompile 'org.assertj:assertj-core:3.17.0' } From 87571b6ad844705e9c622144595917faebe82bf3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 15:13:09 +0100 Subject: [PATCH 0937/4969] Bump assertj-core from 3.16.1 to 3.17.0 in /modules/database-commons (#3141) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.16.1 to 3.17.0. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 82e318e5017..1ab8d67cf02 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.16.1' + testCompile 'org.assertj:assertj-core:3.17.0' } From 8bc3bf89e0551b0d5ef602433a76b5fd76d83f91 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sat, 29 Aug 2020 09:52:14 +0200 Subject: [PATCH 0938/4969] Fix bind mounts for ResourceReaper/ryuk and ContainerisedDockerCompose on macOS (#3159) Relates to #545 Relates to #2998 --- .../main/java/org/testcontainers/DockerClientFactory.java | 6 +++++- .../testcontainers/containers/DockerComposeContainer.java | 2 +- .../java/org/testcontainers/utility/ResourceReaper.java | 2 +- .../containers/localstack/LocalStackContainer.java | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 1905fc7c098..571b18fbcce 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -19,6 +19,7 @@ import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.SystemUtils; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; import org.testcontainers.dockerclient.TransportConfig; @@ -145,9 +146,12 @@ public String getRemoteDockerUnixSocketPath() { } URI dockerHost = getTransportConfig().getDockerHost(); - return "unix".equals(dockerHost.getScheme()) + String path = "unix".equals(dockerHost.getScheme()) ? dockerHost.getRawPath() : "/var/run/docker.sock"; + return SystemUtils.IS_OS_WINDOWS + ? "/" + path + : path; } /** diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index af1da29442f..d2702b3db5b 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -608,7 +608,7 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { // as the docker daemon, just mapping the docker control socket is OK. // As there seems to be a problem with mapping to the /var/run directory in certain environments (e.g. CircleCI) // we map the socket file outside of /var/run, as just /docker.sock - addFileSystemBind("/" + DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), "/docker.sock", READ_WRITE); + addFileSystemBind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), "/docker.sock", READ_WRITE); addEnv("DOCKER_HOST", "unix:///docker.sock"); setStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy()); setWorkingDirectory(containerPwd); diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 3448e73dce3..c37e6660654 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -76,7 +76,7 @@ public static String start(String hostIpAddress, DockerClient client) { DockerClientFactory.instance().checkAndPullImage(client, ryukImage); List binds = new ArrayList<>(); - binds.add(new Bind("/" + DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); + binds.add(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); String ryukContainerId = client.createContainerCmd(ryukImage) .withHostConfig(new HostConfig().withAutoRemove(true)) diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 3a9fab26ae4..a9547eec94d 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -17,6 +17,7 @@ import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.rnorth.ducttape.Preconditions; +import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.ComparableVersion; @@ -84,7 +85,7 @@ public LocalStackContainer(final DockerImageName dockerImageName, boolean useLeg super(dockerImageName); this.legacyMode = useLegacyMode; - withFileSystemBind("//var/run/docker.sock", "/var/run/docker.sock"); + withFileSystemBind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), "/var/run/docker.sock"); waitingFor(Wait.forLogMessage(".*Ready\\.\n", 1)); } From 6fff500b1618759f64dd4d0882e52932ef06652b Mon Sep 17 00:00:00 2001 From: Waldemar Panas <8766331+wpanas@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:51:16 +0200 Subject: [PATCH 0939/4969] #3057 Fix jetbrains annotations configuration scope (#3157) Co-authored-by: wpanas --- core/build.gradle | 3 ++- examples/mongodb-container/build.gradle | 1 + modules/jdbc/build.gradle | 1 + modules/mysql/build.gradle | 2 ++ modules/nginx/build.gradle | 1 + modules/postgresql/build.gradle | 2 ++ modules/presto/build.gradle | 1 + modules/rabbitmq/build.gradle | 3 ++- modules/selenium/build.gradle | 3 +++ modules/spock/build.gradle | 2 ++ 10 files changed, 17 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 68bc339593a..bb27f4378e4 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -164,7 +164,8 @@ dependencies { compile 'junit:junit:4.12' compile 'org.slf4j:slf4j-api:1.7.30' - compile 'org.jetbrains:annotations:19.0.0' + compileOnly 'org.jetbrains:annotations:20.0.0' + testCompileOnly 'org.jetbrains:annotations:20.0.0' compile 'org.apache.commons:commons-compress:1.20' compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index d3b85856b8a..2c6b0bbcc13 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -9,4 +9,5 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13' + testCompileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index cd10c7a98c3..33ff3e8339f 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -4,6 +4,7 @@ dependencies { compile project(':database-commons') testCompile project(':test-support') + compileOnly 'org.jetbrains:annotations:20.0.0' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.37' diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 3badd2e18e1..545037d2dff 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -14,4 +14,6 @@ dependencies { testCompile testFixtures(project(':r2dbc')) testCompile 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' + + compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index e5003b4e103..b56d7f2b4e8 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -2,4 +2,5 @@ description = "Testcontainers :: Nginx" dependencies { compile project(':testcontainers') + compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 720c1d493a5..6437bd9c2f8 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -15,4 +15,6 @@ dependencies { testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' + + compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/presto/build.gradle b/modules/presto/build.gradle index 51c5bf4345e..4130fb74891 100644 --- a/modules/presto/build.gradle +++ b/modules/presto/build.gradle @@ -5,4 +5,5 @@ dependencies { testCompile project(':jdbc-test') testCompile 'io.prestosql:presto-jdbc:331' + compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 7b9a5274a7e..73524c2da18 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -2,6 +2,7 @@ description = "TestContainers :: RabbitMQ" dependencies { compile project(":testcontainers") - testCompile "com.rabbitmq:amqp-client:5.7.0" + testCompile 'com.rabbitmq:amqp-client:5.7.0' testCompile 'org.assertj:assertj-core:3.12.2' + compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index f7fcb75107d..a51735ae78a 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -10,4 +10,7 @@ dependencies { testCompile 'org.mortbay.jetty:jetty:6.1.26' testCompile project(':nginx') + + compileOnly 'org.jetbrains:annotations:20.0.0' + testCompileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 04a6682ee2f..c559b623b55 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -17,6 +17,8 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.16' testRuntime 'mysql:mysql-connector-java:8.0.21' + + testCompileOnly 'org.jetbrains:annotations:20.0.0' } sourceJar { From fb4edf618c6e9a4de32a24446d5eff330d226846 Mon Sep 17 00:00:00 2001 From: iaintatchbbc Date: Tue, 1 Sep 2020 11:52:13 +0100 Subject: [PATCH 0940/4969] Remove use of implicit network for multi-container Kafka (#3128) --- docs/modules/kafka.md | 2 ++ .../java/org/testcontainers/containers/KafkaContainerTest.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index 35ac37b6906..83bb8af0628 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -53,6 +53,8 @@ If your test needs to run some other Docker container which needs access to the * Use `kafka.getNetworkAliases().get(0)+":9092"` as bootstrap server location. Or just give your Kafka container a network alias of your liking. +You will need to explicitly create a network and set it on the Kafka container as well as on your other containers that need to communicate with Kafka. + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index b8cd5c9be9c..71702ce8e62 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -75,7 +75,7 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); // withKafkaNetwork { - GenericContainer application = new GenericContainer("alpine").withNetwork(kafka.getNetwork()) + GenericContainer application = new GenericContainer("alpine").withNetwork(network) // } .withNetworkAliases("dummy") .withCommand("sleep 10000") From c9f756831008ae145a7e7f54e00f9e59e77e1642 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:30:24 +0100 Subject: [PATCH 0941/4969] Bump mssql-jdbc from 8.3.1.jre8-preview to 8.4.1.jre8 in /modules/mssqlserver (#3174) Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 8.3.1.jre8-preview to 8.4.1.jre8. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/dev/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 508de84a2f9..f0170500e7d 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,12 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.4.RELEASE' testCompile project(':jdbc-test') - testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.1.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.4.1.jre8' testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.3.RELEASE' // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) - testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.3.1.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.4.1.jre8' } From 2ad9fb37458092cf2aeb7a8ba2eb383a9a4626c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:31:08 +0100 Subject: [PATCH 0942/4969] Bump aws-java-sdk-dynamodb from 1.11.847 to 1.11.851 in /modules/dynalite (#3172) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.847 to 1.11.851. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.847...1.11.851) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 762e189173b..7ebe948ee66 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.847' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.851' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.847' } From 6402f14156981ef09b4a195567040af9c7d2b43d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:32:07 +0100 Subject: [PATCH 0943/4969] Bump aws-java-sdk-sqs from 1.11.846 to 1.11.851 in /modules/localstack (#3171) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.846 to 1.11.851. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.846...1.11.851) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index e28117319f5..37f505374e6 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.847' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.847' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.846' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.851' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.14.6' } From 38587306998d79b8e6625c77e3baad5f570cf8e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:36:46 +0100 Subject: [PATCH 0944/4969] Bump assertj-core from 3.17.0 to 3.17.1 in /modules/neo4j (#3167) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.0 to 3.17.1. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.0...assertj-core-3.17.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 2f5e6b05d9f..6a5bab19284 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.17.0' + testCompile 'org.assertj:assertj-core:3.17.1' } From 77528c9c5fe46ba9618497cdbeb4e5e14f00ee25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:36:56 +0100 Subject: [PATCH 0945/4969] Bump assertj-core from 3.17.0 to 3.17.1 in /modules/database-commons (#3168) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.0 to 3.17.1. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.0...assertj-core-3.17.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 1ab8d67cf02..ac27b84a662 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.17.0' + testCompile 'org.assertj:assertj-core:3.17.1' } From b7892600f39e9e089b4560f3fa8312d60cc42e8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:37:11 +0100 Subject: [PATCH 0946/4969] Bump assertj-core from 3.17.0 to 3.17.1 in /modules/vault (#3173) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.0 to 3.17.1. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.0...assertj-core-3.17.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 5c83cbbb56f..7c8cac68d05 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.1' - testCompile 'org.assertj:assertj-core:3.17.0' + testCompile 'org.assertj:assertj-core:3.17.1' } From 28125c1aa47dcb98d4f93557cda8f429b435962c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:37:21 +0100 Subject: [PATCH 0947/4969] Bump assertj-core from 3.17.0 to 3.17.1 in /modules/junit-jupiter (#3177) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.0 to 3.17.1. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.0...assertj-core-3.17.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index d1368c2389a..7b4d924c9f9 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.5.7') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.17.0' + testCompile 'org.assertj:assertj-core:3.17.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' testRuntime 'org.postgresql:postgresql:42.2.16' From 0286de04a8843305969633cca5c03bcc2e3dba1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:37:29 +0100 Subject: [PATCH 0948/4969] Bump assertj-core from 3.17.0 to 3.17.1 in /modules/pulsar (#3176) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.0 to 3.17.1. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.0...assertj-core-3.17.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index a8f0d9f48ed..5dbbb0d6489 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.1' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.0' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.1' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.1' } From 5f02839ce55c81bd538e83ecb28e7c9f8d6fdc12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:37:40 +0100 Subject: [PATCH 0949/4969] Bump assertj-core from 3.17.0 to 3.17.1 in /modules/kafka (#3175) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.0 to 3.17.1. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.0...assertj-core-3.17.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index a2b73ff4281..64c0ee4ce1a 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.6.0' - testCompile 'org.assertj:assertj-core:3.17.0' + testCompile 'org.assertj:assertj-core:3.17.1' testCompile 'com.google.guava:guava:23.0' } From a2146f35b834e112cc5572b5bca757d3c53c7657 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 13:02:33 +0100 Subject: [PATCH 0950/4969] Bump s3 from 2.14.6 to 2.14.8 in /modules/localstack (#3181) Bumps s3 from 2.14.6 to 2.14.8. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 37f505374e6..fc9ebe3064b 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.847' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.851' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.14.6' + testCompile 'software.amazon.awssdk:s3:2.14.8' } From 63692d3d84d2c5e46788d0dea28acc33f4dc1d92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 13:02:43 +0100 Subject: [PATCH 0951/4969] Bump aws-java-sdk-s3 from 1.11.847 to 1.11.852 in /modules/localstack (#3182) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.847 to 1.11.852. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.847...1.11.852) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index fc9ebe3064b..eec730235ef 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.847' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.852' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.847' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.851' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From d796707df2f9a3ced54f34924e0dbfbf0cf181f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Coll?= Date: Sat, 12 Sep 2020 15:18:28 -0300 Subject: [PATCH 0952/4969] Use testCompileClasspath instead of testCompileOnly (#3219) --- core/build.gradle | 2 +- examples/mongodb-container/build.gradle | 2 +- modules/selenium/build.gradle | 2 +- modules/spock/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index bb27f4378e4..65bb8477ed9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -165,7 +165,7 @@ dependencies { compile 'junit:junit:4.12' compile 'org.slf4j:slf4j-api:1.7.30' compileOnly 'org.jetbrains:annotations:20.0.0' - testCompileOnly 'org.jetbrains:annotations:20.0.0' + testCompileClasspath 'org.jetbrains:annotations:20.0.0' compile 'org.apache.commons:commons-compress:1.20' compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 2c6b0bbcc13..285c0f96315 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -9,5 +9,5 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13' - testCompileOnly 'org.jetbrains:annotations:20.0.0' + testCompileClasspath 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index a51735ae78a..d745baefa75 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -12,5 +12,5 @@ dependencies { testCompile project(':nginx') compileOnly 'org.jetbrains:annotations:20.0.0' - testCompileOnly 'org.jetbrains:annotations:20.0.0' + testCompileClasspath 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index c559b623b55..7640188fa54 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -18,7 +18,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.16' testRuntime 'mysql:mysql-connector-java:8.0.21' - testCompileOnly 'org.jetbrains:annotations:20.0.0' + testCompileClasspath 'org.jetbrains:annotations:20.0.0' } sourceJar { From 03304804c7fa87c05efcf0250a53011c01196120 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:25:45 +0100 Subject: [PATCH 0953/4969] Bump assertj-core from 3.17.1 to 3.17.2 in /modules/neo4j (#3208) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.1 to 3.17.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.1...assertj-core-3.17.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 6a5bab19284..da90a493a01 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.17.1' + testCompile 'org.assertj:assertj-core:3.17.2' } From 29ff3423261ec8e4942678daed6091e2bad509d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:25:56 +0100 Subject: [PATCH 0954/4969] Bump elasticsearch-rest-client from 7.9.0 to 7.9.1 in /modules/elasticsearch (#3212) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.9.0 to 7.9.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.9.0...v7.9.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 20097bd19b4..44a5cca5963 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.9.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.9.1" testCompile "org.elasticsearch.client:transport:6.7.1" } From 95455f2d06c30da0406c58d94551a8e9447e3a37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:26:39 +0100 Subject: [PATCH 0955/4969] Bump assertj-core from 3.16.1 to 3.17.1 in /core (#3210) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.16.1 to 3.17.1. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.17.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 65bb8477ed9..b7a029cf5ef 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -211,12 +211,12 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.16.1' + testCompile 'org.assertj:assertj-core:3.17.1' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' - jarFileTestCompile 'org.assertj:assertj-core:3.16.0' + jarFileTestCompile 'org.assertj:assertj-core:3.17.1' jarFileTestCompile 'org.ow2.asm:asm-debug-all:5.2' } From 8cdec4434fd4c0c526e1330498047c08982a958c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:27:37 +0100 Subject: [PATCH 0956/4969] Bump annotations from 20.0.0 to 20.1.0 in /core (#3214) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b7a029cf5ef..e233ef7b159 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -164,7 +164,7 @@ dependencies { compile 'junit:junit:4.12' compile 'org.slf4j:slf4j-api:1.7.30' - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:20.1.0' testCompileClasspath 'org.jetbrains:annotations:20.0.0' compile 'org.apache.commons:commons-compress:1.20' compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { From 842863441bd4f0c21f8deafa9da466f59188fe2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:27:46 +0100 Subject: [PATCH 0957/4969] Bump annotations from 20.0.0 to 20.1.0 in /modules/spock (#3204) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 7640188fa54..3d0948e9e83 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -18,7 +18,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.16' testRuntime 'mysql:mysql-connector-java:8.0.21' - testCompileClasspath 'org.jetbrains:annotations:20.0.0' + testCompileClasspath 'org.jetbrains:annotations:20.1.0' } sourceJar { From 8c7cd3823bc29a3e8ec204982923865b75c10a05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:27:55 +0100 Subject: [PATCH 0958/4969] Bump annotations from 20.0.0 to 20.1.0 in /modules/nginx (#3206) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/nginx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index b56d7f2b4e8..6c4b97876c4 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -2,5 +2,5 @@ description = "Testcontainers :: Nginx" dependencies { compile project(':testcontainers') - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:20.1.0' } From 273b22d484bea0a94aec08cc8bbcfce50e1c22cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:28:21 +0100 Subject: [PATCH 0959/4969] Bump annotations from 20.0.0 to 20.1.0 in /modules/postgresql (#3207) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 6437bd9c2f8..793cf89406e 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -16,5 +16,5 @@ dependencies { testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:20.1.0' } From e14eb8e3055e8db3de0489fed11a735aa69488b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:28:33 +0100 Subject: [PATCH 0960/4969] Bump annotations from 20.0.0 to 20.1.0 in /examples (#3217) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/mongodb-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 285c0f96315..c09cb033489 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -9,5 +9,5 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13' - testCompileClasspath 'org.jetbrains:annotations:20.0.0' + testCompileClasspath 'org.jetbrains:annotations:20.1.0' } From aa5c2dc58282586721b574b76c3ceed02862463d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:28:55 +0100 Subject: [PATCH 0961/4969] Bump annotations from 20.0.0 to 20.1.0 in /modules/jdbc (#3196) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 33ff3e8339f..6453b49b052 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -4,7 +4,7 @@ dependencies { compile project(':database-commons') testCompile project(':test-support') - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:20.1.0' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.37' From 07f035f8ba0b54729de754a35b1f16cd9c565f9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:29:10 +0100 Subject: [PATCH 0962/4969] Bump annotations from 20.0.0 to 20.1.0 in /modules/selenium (#3195) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/selenium/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index d745baefa75..7c6d81ca1bf 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -11,6 +11,6 @@ dependencies { testCompile 'org.mortbay.jetty:jetty:6.1.26' testCompile project(':nginx') - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:20.1.0' testCompileClasspath 'org.jetbrains:annotations:20.0.0' } From 7e1d1b9982334d52e684188378a4c379818824d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:29:44 +0100 Subject: [PATCH 0963/4969] Bump annotations from 20.0.0 to 20.1.0 in /modules/mysql (#3198) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 20.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...20.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 545037d2dff..9df2e177d3f 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -15,5 +15,5 @@ dependencies { testCompile testFixtures(project(':r2dbc')) testCompile 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:20.1.0' } From 4331b63acd7bc034fabacb7494ac1fb1414505ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:30:15 +0100 Subject: [PATCH 0964/4969] Bump aws-java-sdk-dynamodb from 1.11.851 to 1.11.856 in /modules/dynalite (#3194) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.851 to 1.11.856. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.851...1.11.856) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 7ebe948ee66..e850b616f2f 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.851' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.847' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.856' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.856' } From 1f62cad8d86712d8b2253d536dfcedb1aa90b1e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:30:29 +0100 Subject: [PATCH 0965/4969] Bump s3 from 2.14.8 to 2.14.12 in /modules/localstack (#3202) Bumps s3 from 2.14.8 to 2.14.12. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index eec730235ef..1f9816ae2d8 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.847' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.851' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.14.8' + testCompile 'software.amazon.awssdk:s3:2.14.12' } From 2279aa2df0814592066860d933ea0ab0e63eb27f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:30:35 +0100 Subject: [PATCH 0966/4969] Bump aws-java-sdk-s3 from 1.11.852 to 1.11.856 in /modules/localstack (#3203) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.852 to 1.11.856. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.852...1.11.856) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 1f9816ae2d8..3aea0db0acd 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.852' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.847' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.856' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.856' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.851' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.14.12' From d84db2dc76e64d1213b5652927a9062795c53c10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:30:50 +0100 Subject: [PATCH 0967/4969] Bump mockito-core from 3.5.7 to 3.5.10 in /modules/junit-jupiter (#3201) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.7 to 3.5.10. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.7...v3.5.10) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7b4d924c9f9..d649278349b 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testCompile ('org.mockito:mockito-core:3.5.7') { + testCompile ('org.mockito:mockito-core:3.5.10') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.17.1' From 37ff402daa646ab676082b92a10e726abc4efc8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:32:07 +0100 Subject: [PATCH 0968/4969] Bump assertj-core from 3.17.1 to 3.17.2 in /modules/vault (#3193) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.1 to 3.17.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.1...assertj-core-3.17.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 7c8cac68d05..6d862eeba2c 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.1' - testCompile 'org.assertj:assertj-core:3.17.1' + testCompile 'org.assertj:assertj-core:3.17.2' } From 84024b1ca0cb6cd1d570b35675f25238e9f3f05f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:32:29 +0100 Subject: [PATCH 0969/4969] Bump aws-java-sdk-sqs from 1.11.851 to 1.11.860 in /modules/localstack (#3227) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.851 to 1.11.860. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.851...1.11.860) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3aea0db0acd..6de26e324b4 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.856' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.856' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.851' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.14.12' } From 9b3c87eb2f350c6211dfa5eadea61f8eb00e2097 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 19:57:40 +0100 Subject: [PATCH 0970/4969] Bump cucumber-junit from 6.4.0 to 6.6.0 in /examples (#3215) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 90cc99e7627..fc4e4aaf3b1 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.4.0' - testImplementation 'io.cucumber:cucumber-junit:6.4.0' + testImplementation 'io.cucumber:cucumber-junit:6.6.0' testImplementation 'org.testcontainers:selenium' } From 2be4c2a927abbed84e2a6cfcea974f821bfe3628 Mon Sep 17 00:00:00 2001 From: Quincy Bowers Date: Mon, 14 Sep 2020 02:58:28 -0600 Subject: [PATCH 0971/4969] Exclude id from NetworkImpl.NetworkImplBuilder (testcontainers#8125) (#2807) * Exclude id from NetworkImpl.NetworkImplBuilder (testcontainers#8125) * Deprecate Network.id field The field is deprecated in order to mark the NetworkBuildImpl#id method deprecated so that the method can later be removed. We'll undeprecate the field at that time. Co-authored-by: Richard North --- core/src/main/java/org/testcontainers/containers/Network.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/testcontainers/containers/Network.java b/core/src/main/java/org/testcontainers/containers/Network.java index 1c00fa00fac..2fda5ad1a8d 100644 --- a/core/src/main/java/org/testcontainers/containers/Network.java +++ b/core/src/main/java/org/testcontainers/containers/Network.java @@ -52,6 +52,7 @@ class NetworkImpl extends ExternalResource implements Network { @Singular private Set> createNetworkCmdModifiers; + @Deprecated private String id; private final AtomicBoolean initialized = new AtomicBoolean(); From ec16e7a347242a22aa604005667142f867637a7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:18:57 +0100 Subject: [PATCH 0972/4969] Bump junit-jupiter-engine from 5.6.2 to 5.7.0 in /modules/junit-jupiter (#3234) Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.6.2 to 5.7.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.6.2...r5.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index d649278349b..d57835f4cfc 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.16' testRuntime 'mysql:mysql-connector-java:8.0.21' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.6.2' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } test { From 2854194424504af8ada973b2c623da066bf8559f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:31:06 +0100 Subject: [PATCH 0973/4969] Bump postgresql from 42.2.15 to 42.2.16 in /examples (#3216) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.15 to 42.2.16. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.15...REL42.2.16) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index a62854e9b35..6877a35fec5 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.8.1' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.15' + testImplementation 'org.postgresql:postgresql:42.2.16' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From fb66c0cabd1ed5e7d01b6cf9fc895880a9d7e3e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:31:19 +0100 Subject: [PATCH 0974/4969] Bump aws-java-sdk-dynamodb from 1.11.856 to 1.11.860 in /modules/dynalite (#3235) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index e850b616f2f..7d9fa4d9ea5 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.856' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.856' } From 9327bba287a2e8ebe5be41ae07cb1c85038c6766 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:31:37 +0100 Subject: [PATCH 0975/4969] Bump junit-jupiter-params from 5.6.2 to 5.7.0 in /modules/junit-jupiter (#3232) Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.6.2 to 5.7.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.6.2...r5.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index d57835f4cfc..56f9fc3070e 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.17.1' - testCompile 'org.junit.jupiter:junit-jupiter-params:5.6.2' + testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' testRuntime 'org.postgresql:postgresql:42.2.16' testRuntime 'mysql:mysql-connector-java:8.0.21' From 730e98e570ab4ba695db60bf5e967daac9ed6696 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:31:50 +0100 Subject: [PATCH 0976/4969] Bump junit-jupiter-api from 5.6.2 to 5.7.0 in /modules/junit-jupiter (#3233) Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.6.2 to 5.7.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.6.2...r5.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 56f9fc3070e..303d4b20d56 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.6.2' + compile 'org.junit.jupiter:junit-jupiter-api:5.7.0' testCompile project(':mysql') testCompile project(':postgresql') From a011235b0e2152601387f16a32a6e0b03fb8a7aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:32:01 +0100 Subject: [PATCH 0977/4969] Bump s3 from 2.14.12 to 2.14.16 in /modules/localstack (#3231) Bumps s3 from 2.14.12 to 2.14.16. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 6de26e324b4..5c069167eb1 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.856' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.14.12' + testCompile 'software.amazon.awssdk:s3:2.14.16' } From a4f7880ada6597a67631b5eb8b9f48422cc8b286 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:32:11 +0100 Subject: [PATCH 0978/4969] Bump r2dbc-postgresql from 0.8.4.RELEASE to 0.8.5.RELEASE in /modules/postgresql (#3230) Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.4.RELEASE to 0.8.5.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.5.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.4.RELEASE...v0.8.5.RELEASE) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 793cf89406e..ea6e4a87226 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -7,14 +7,14 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.4.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' testCompile project(':jdbc-test') testCompile project(':test-support') testCompile 'org.postgresql:postgresql:42.2.16' testCompile testFixtures(project(':r2dbc')) - testCompile 'io.r2dbc:r2dbc-postgresql:0.8.3.RELEASE' + testCompile 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' compileOnly 'org.jetbrains:annotations:20.1.0' } From 0af261eb363b75b5e6ee1d9ff2f3d9145a9fd81f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:32:20 +0100 Subject: [PATCH 0979/4969] Bump cucumber-java from 6.4.0 to 6.6.0 in /examples (#3213) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 6.4.0 to 6.6.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.4.0...v6.6.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index fc4e4aaf3b1..1362b3f257a 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:6.4.0' + testImplementation 'io.cucumber:cucumber-java:6.6.0' testImplementation 'io.cucumber:cucumber-junit:6.6.0' testImplementation 'org.testcontainers:selenium' } From 3f5a8a2f0c7b16ff19ae581cc30cbca974f35636 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:51:11 +0100 Subject: [PATCH 0980/4969] Bump assertj-core from 3.17.1 to 3.17.2 in /modules/kafka (#3200) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.1 to 3.17.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.1...assertj-core-3.17.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 64c0ee4ce1a..95d844c7a41 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.6.0' - testCompile 'org.assertj:assertj-core:3.17.1' + testCompile 'org.assertj:assertj-core:3.17.2' testCompile 'com.google.guava:guava:23.0' } From 46788e1e980b7d73152cfd15f3949b067c07fa4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:51:24 +0100 Subject: [PATCH 0981/4969] Bump assertj-core from 3.17.1 to 3.17.2 in /modules/junit-jupiter (#3199) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.1 to 3.17.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.1...assertj-core-3.17.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 303d4b20d56..8293060b9b4 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.5.10') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.17.1' + testCompile 'org.assertj:assertj-core:3.17.2' testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' testRuntime 'org.postgresql:postgresql:42.2.16' From dafc8841ea5c0cba88ffdf79452925bd83fbdcd5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:51:35 +0100 Subject: [PATCH 0982/4969] Bump assertj-core from 3.17.1 to 3.17.2 in /modules/database-commons (#3197) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.1 to 3.17.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.1...assertj-core-3.17.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index ac27b84a662..e6d6a1812da 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.17.1' + testCompile 'org.assertj:assertj-core:3.17.2' } From e01495d168e951e644b06eb1b1b66dd98dae78ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 19:51:42 +0100 Subject: [PATCH 0983/4969] Bump aws-java-sdk-s3 from 1.11.856 to 1.11.860 in /modules/localstack (#3226) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.856 to 1.11.860. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.856...1.11.860) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 5c069167eb1..3eb02882546 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.856' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.856' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From 77251a17dad3ee3aa6017229f856d46a4a8689b8 Mon Sep 17 00:00:00 2001 From: Gapmeister66 Date: Mon, 14 Sep 2020 20:30:02 +0100 Subject: [PATCH 0984/4969] Add support for Docker compose `withOptions(...)` (#2827) Co-authored-by: Peter Lewis Co-authored-by: Richard North --- .../containers/DockerComposeContainer.java | 27 +++++++- ...DockerComposeContainerWithOptionsTest.java | 62 +++++++++++++++++++ .../with-deploy-block.yml | 8 +++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java create mode 100644 core/src/test/resources/compose-options-test/with-deploy-block.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index d2702b3db5b..bd06083644d 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -45,6 +45,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -81,6 +82,7 @@ public class DockerComposeContainer> e private boolean localCompose; private boolean pull = true; private boolean build = false; + private Set options = new HashSet<>(); private boolean tailChildContainers; private String project; @@ -213,7 +215,7 @@ private void createServices() { .distinct() .collect(joining(" ")); - String command = "up -d"; + String command = optionsAsString() + "up -d"; if (build) { command += " --build"; @@ -231,6 +233,19 @@ private void createServices() { runWithCompose(command); } + private String optionsAsString() { + String optionsString = options + .stream() + .collect(joining(" ")); + if (optionsString.length() !=0 ) { + // ensures that there is a space between the options and 'up' if options are passed. + return optionsString + " "; + } else { + // otherwise two spaces would appear between 'docker-compose' and 'up' + return StringUtils.EMPTY; + } + } + private void waitUntilServiceStarted() { listChildContainers().forEach(this::createServiceInstance); @@ -517,6 +532,16 @@ public SELF withBuild(boolean build) { return self(); } + /** + * Adds options to the docker-compose command, e.g. docker-compose --compatibility. + * + * @return this instance, for chaining + */ + public SELF withOptions(String... options) { + this.options = new HashSet<>(Arrays.asList(options)); + return self(); + } + /** * Remove images after containers shutdown. * diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java new file mode 100644 index 00000000000..375c9baa070 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java @@ -0,0 +1,62 @@ +package org.testcontainers.junit; + +import com.google.common.collect.ImmutableSet; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.containers.DockerComposeContainer; + +import java.io.File; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests the options associated with the docker-compose command. + */ +@RunWith(Parameterized.class) +public class DockerComposeContainerWithOptionsTest { + + public DockerComposeContainerWithOptionsTest(final File composeFile, final boolean local, final Set options, final boolean expectError) { + this.composeFile = composeFile; + this.local = local; + this.options = options; + this.expectError = expectError; + } + + private final File composeFile; + private final boolean local; + + private final Set options; + private final boolean expectError; + + @Parameterized.Parameters(name = "docker-compose test [compose file: {0}, local: {1}, options: {2}, expected result: {3}]") + + public static Object[][] params() { + return new Object[][]{ + // Test the happy day case. THe compatibility option should be accepted by docker-compose. + {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), false, ImmutableSet.of("--compatibility"), false}, + // Test with flags absent. Docker compose will warn but continue, ignoring the deploy block. + {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), false, ImmutableSet.of(""), false}, + // Test with a bad option. Compose will complain. + {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), false, ImmutableSet.of("--bad-option"), true}, + // Local compose + {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), true, ImmutableSet.of("--compatibility"), false}, + }; + } + + @Test + public void performTest() { + + try (DockerComposeContainer environment = new DockerComposeContainer<>(composeFile) + .withOptions(options.stream().toArray(String[]::new)) + .withLocalCompose(local)) { + environment.start(); + assertThat(expectError).isEqualTo(false); + } catch (Exception e) { + assertThat(expectError).isEqualTo(true); + } + + } + +} diff --git a/core/src/test/resources/compose-options-test/with-deploy-block.yml b/core/src/test/resources/compose-options-test/with-deploy-block.yml new file mode 100644 index 00000000000..f52f6747122 --- /dev/null +++ b/core/src/test/resources/compose-options-test/with-deploy-block.yml @@ -0,0 +1,8 @@ +version: '3.7' +services: + redis: + image: redis:2.6.17 + deploy: + resources: + limits: + memory: 150M From b0cdb60e5565ceabe527165143216eecb4532413 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:49:55 +0100 Subject: [PATCH 0985/4969] Bump assertj-core from 3.17.1 to 3.17.2 in /modules/pulsar (#3192) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.1 to 3.17.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.1...assertj-core-3.17.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 5dbbb0d6489..2d2ded0c765 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.1' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.1' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.2' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.1' } From 7c994846904d7fd7b4ae82b95b964f66199926bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:50:14 +0100 Subject: [PATCH 0986/4969] Bump aws-java-sdk-dynamodb from 1.11.860 to 1.11.865 in /modules/dynalite (#3242) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.860 to 1.11.865. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.860...1.11.865) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 7d9fa4d9ea5..0b2e334c633 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.860' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.856' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.865' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.865' } From 625fddb5900496723e18bf7af4e58a688c7d16af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:50:26 +0100 Subject: [PATCH 0987/4969] Bump mockito-core from 3.5.10 to 3.5.11 in /modules/junit-jupiter (#3243) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.10 to 3.5.11. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.10...v3.5.11) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 8293060b9b4..dbf54b8d291 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testCompile ('org.mockito:mockito-core:3.5.10') { + testCompile ('org.mockito:mockito-core:3.5.11') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.17.2' From 1e6665094fe8d3f30a9af0242f9bd204fea0699b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:50:34 +0100 Subject: [PATCH 0988/4969] Bump solr-solrj from 8.6.1 to 8.6.2 in /examples (#3244) Bumps solr-solrj from 8.6.1 to 8.6.2. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 89444aeb378..52fa54f1fc5 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.10" annotationProcessor "org.projectlombok:lombok:1.18.10" - implementation 'org.apache.solr:solr-solrj:8.6.1' + implementation 'org.apache.solr:solr-solrj:8.6.2' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From a55fc35345ecd332e2a84a4c451785586d6c6321 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:50:51 +0100 Subject: [PATCH 0989/4969] Bump okhttp from 4.8.1 to 4.9.0 in /examples (#3245) Bumps [okhttp](https://github.com/square/okhttp) from 4.8.1 to 4.9.0. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.8.1...parent-4.9.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 6877a35fec5..eac2c59df4a 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:4.8.1' + implementation 'com.squareup.okhttp3:okhttp:4.9.0' implementation 'org.json:json:20180813' testImplementation 'org.postgresql:postgresql:42.2.16' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From e90150d32b6e1ffc82ae687c85b17ab7e94b2c3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:51:01 +0100 Subject: [PATCH 0990/4969] Bump cucumber-junit from 6.6.0 to 6.7.0 in /examples (#3246) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 6.6.0 to 6.7.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.6.0...v6.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 1362b3f257a..318ed51f24c 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.6.0' - testImplementation 'io.cucumber:cucumber-junit:6.6.0' + testImplementation 'io.cucumber:cucumber-junit:6.7.0' testImplementation 'org.testcontainers:selenium' } From c56dcd8d8ee7a90a70dadddc7805836d07dd3a35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:51:37 +0100 Subject: [PATCH 0991/4969] Bump mockito-core from 3.5.7 to 3.5.11 in /core (#3250) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.7 to 3.5.11. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.7...v3.5.11) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index e233ef7b159..37595c18e7c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -205,7 +205,7 @@ dependencies { testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' - testCompile ('org.mockito:mockito-core:3.5.7') { + testCompile ('org.mockito:mockito-core:3.5.11') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From d81f236de640ae0325c7ffd94080aac9dddae358 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:51:45 +0100 Subject: [PATCH 0992/4969] Bump s3 from 2.14.16 to 2.14.21 in /modules/localstack (#3254) Bumps s3 from 2.14.16 to 2.14.21. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3eb02882546..7fa112b3cd2 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.856' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.14.16' + testCompile 'software.amazon.awssdk:s3:2.14.21' } From 53932d9988e8e09db45c8ccea0f39d0da7a24dc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2020 09:51:55 +0100 Subject: [PATCH 0993/4969] Bump aws-java-sdk-s3 from 1.11.860 to 1.11.865 in /modules/localstack (#3255) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.860 to 1.11.865. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.860...1.11.865) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 7fa112b3cd2..436f03ab236 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.860' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.856' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.865' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.865' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.14.21' From 27428a0ba798ca909db5b2f3202c15a74f34037e Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 28 Sep 2020 17:12:37 +0100 Subject: [PATCH 0994/4969] Remove dependency upon internet URLs for selenium tests (#3271) --- .../junit/BaseWebDriverContainerTest.java | 50 +++++++------- ...ChromeRecordingWebDriverContainerTest.java | 14 ++-- .../junit/ChromeWebDriverContainerTest.java | 10 +-- .../ContainerWithoutCapabilitiesTest.java | 3 +- ...stomWaitTimeoutWebDriverContainerTest.java | 11 +-- .../junit/FirefoxWebDriverContainerTest.java | 10 +-- .../junit/FlakyContainerCreationTest.java | 31 --------- .../junit/LinkedContainerTest.java | 69 ------------------- ...ecificImageNameWebDriverContainerTest.java | 8 +-- 9 files changed, 50 insertions(+), 156 deletions(-) delete mode 100644 modules/selenium/src/test/java/org/testcontainers/junit/FlakyContainerCreationTest.java delete mode 100644 modules/selenium/src/test/java/org/testcontainers/junit/LinkedContainerTest.java diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java index 0f41b2ce1d2..cf5c762f2ad 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java @@ -1,17 +1,20 @@ package org.testcontainers.junit; import org.jetbrains.annotations.NotNull; +import org.junit.ClassRule; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; -import org.openqa.selenium.support.ui.ExpectedConditions; -import org.openqa.selenium.support.ui.WebDriverWait; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.utility.DockerImageName; -import java.util.List; import java.util.concurrent.TimeUnit; import static java.lang.String.format; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** @@ -19,25 +22,31 @@ */ public class BaseWebDriverContainerTest { - protected void doSimpleWebdriverTest(BrowserWebDriverContainer rule) { + @ClassRule + public static Network NETWORK = Network.newNetwork(); + + @ClassRule + public static GenericContainer HELLO_WORLD = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld:1.0.0")) + .withNetwork(NETWORK) + .withNetworkAliases("helloworld") + .withExposedPorts(8080, 8081) + .waitingFor(new HttpWaitStrategy()); + + protected static void doSimpleExplore(BrowserWebDriverContainer rule) { RemoteWebDriver driver = setupDriverFromRule(rule); System.out.println("Selenium remote URL is: " + rule.getSeleniumAddress()); System.out.println("VNC URL is: " + rule.getVncAddress()); - driver.get("http://www.google.com"); - WebElement search = driver.findElement(By.name("q")); - search.sendKeys("testcontainers"); - search.submit(); + driver.get("http://helloworld:8080"); + WebElement title = driver.findElement(By.tagName("h1")); - List results = new WebDriverWait(driver, 15) - .until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("#search h3"))); - - assertTrue("the word 'testcontainers' appears in search results", - results.stream() - .anyMatch(el -> el.getText().contains("testcontainers"))); + assertEquals("the index page contains the title 'Hello world'", + "Hello world", + title.getText().trim() + ); } - protected void assertBrowserNameIs(BrowserWebDriverContainer rule, String expectedName) { + protected void assertBrowserNameIs(BrowserWebDriverContainer rule, String expectedName) { RemoteWebDriver driver = setupDriverFromRule(rule); String actual = driver.getCapabilities().getBrowserName(); assertTrue(format("actual browser name is %s", actual), @@ -45,18 +54,9 @@ protected void assertBrowserNameIs(BrowserWebDriverContainer rule, String expect } @NotNull - private static RemoteWebDriver setupDriverFromRule(BrowserWebDriverContainer rule) { + private static RemoteWebDriver setupDriverFromRule(BrowserWebDriverContainer rule) { RemoteWebDriver driver = rule.getWebDriver(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); return driver; } - - protected static void doSimpleExplore(BrowserWebDriverContainer rule) { - RemoteWebDriver driver = setupDriverFromRule(rule); - driver.get("http://en.wikipedia.org/wiki/Randomness"); - - // Oh! The irony! - assertTrue("Randomness' description has the word 'pattern'", driver.findElementByPartialLinkText("pattern").isDisplayed()); - } - } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java index ead9a21ae4f..cf8a6227ec1 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java @@ -33,11 +33,12 @@ public void recordingTestThatShouldBeRecordedAndRetained() { try ( // recordAll { // To do this, simply add extra parameters to the rule constructor: - BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) .withRecordingMode(RECORD_ALL, target) // } .withRecordingFileFactory(new DefaultRecordingFileFactory()) + .withNetwork(NETWORK) ) { chrome.start(); @@ -69,12 +70,13 @@ public static class ChromeThatRecordsFailingTests { public void recordingTestThatShouldBeRecordedButNotPersisted() { try ( // withRecordingFileFactory { - BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() // } .withCapabilities(new ChromeOptions()) // withRecordingFileFactory { .withRecordingFileFactory(new CustomRecordingFileFactory()) - // } + // } + .withNetwork(NETWORK) ) { chrome.start(); @@ -88,11 +90,12 @@ public void recordingTestThatShouldBeRecordedAndRetained() { try ( // recordFailing { // or if you only want videos for test failures: - BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) .withRecordingMode(RECORD_FAILING, target) // } .withRecordingFileFactory(new DefaultRecordingFileFactory()) + .withNetwork(NETWORK) ) { chrome.start(); @@ -115,6 +118,7 @@ public String getFilesystemFriendlyName() { } - private static class CustomRecordingFileFactory extends DefaultRecordingFileFactory { } + private static class CustomRecordingFileFactory extends DefaultRecordingFileFactory { + } } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java index 92ba4e2cd37..bea1909a145 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java @@ -13,20 +13,16 @@ public class ChromeWebDriverContainerTest extends BaseWebDriverContainerTest { // junitRule { @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()); + public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() + .withCapabilities(new ChromeOptions()) // } + .withNetwork(NETWORK); @Before public void checkBrowserIsIndeedChrome() { assertBrowserNameIs(chrome, "chrome"); } - @Test - public void simpleTest() { - doSimpleWebdriverTest(chrome); - } - @Test public void simpleExploreTest() { doSimpleExplore(chrome); diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java index c319395211c..b1214d18b60 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java @@ -7,7 +7,8 @@ public class ContainerWithoutCapabilitiesTest extends BaseWebDriverContainerTest{ @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer(); + public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() + .withNetwork(NETWORK); @Test public void chromeIsStartedIfNoCapabilitiesProvided() { diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java index 1d0f895b682..8448dc40d53 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java @@ -15,12 +15,13 @@ public class CustomWaitTimeoutWebDriverContainerTest extends BaseWebDriverContainerTest { @Rule - public BrowserWebDriverContainer chromeWithCustomTimeout = new BrowserWebDriverContainer<>() - .withCapabilities(new ChromeOptions()) - .withStartupTimeout(Duration.of(30, SECONDS)); + public BrowserWebDriverContainer chromeWithCustomTimeout = new BrowserWebDriverContainer<>() + .withCapabilities(new ChromeOptions()) + .withStartupTimeout(Duration.of(30, SECONDS)) + .withNetwork(NETWORK); @Test - public void simpleTest() { - doSimpleWebdriverTest(chromeWithCustomTimeout); + public void simpleExploreTest() { + doSimpleExplore(chromeWithCustomTimeout); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java index 1f687aab762..1cffec16bc6 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java @@ -13,20 +13,16 @@ public class FirefoxWebDriverContainerTest extends BaseWebDriverContainerTest { // junitRule { @Rule - public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer() - .withCapabilities(new FirefoxOptions()); + public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer<>() + .withCapabilities(new FirefoxOptions()) // } + .withNetwork(NETWORK); @Before public void checkBrowserIsIndeedFirefox() { assertBrowserNameIs(firefox, "firefox"); } - @Test - public void simpleTest() { - doSimpleWebdriverTest(firefox); - } - @Test public void simpleExploreTest() { doSimpleExplore(firefox); diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/FlakyContainerCreationTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/FlakyContainerCreationTest.java deleted file mode 100644 index d33a4c9c07e..00000000000 --- a/modules/selenium/src/test/java/org/testcontainers/junit/FlakyContainerCreationTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.testcontainers.junit; - -import org.junit.Ignore; -import org.junit.Test; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.testcontainers.containers.BrowserWebDriverContainer; - -import java.io.File; - -/** - * Created by rnorth on 30/01/2016. - */ -public class FlakyContainerCreationTest { - - @Test @Ignore - public void testCreationOfManyContainers() { - for (int i = 0; i < 50; i++) { - BrowserWebDriverContainer container = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()) - .withRecordingMode(BrowserWebDriverContainer.VncRecordingMode.RECORD_FAILING, new File("build")); - - container.start(); - RemoteWebDriver driver = container.getWebDriver(); - - driver.get("http://www.google.com"); - - container.stop(); - } - } -} diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/LinkedContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/LinkedContainerTest.java deleted file mode 100644 index d3e458e07ec..00000000000 --- a/modules/selenium/src/test/java/org/testcontainers/junit/LinkedContainerTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.testcontainers.junit; - -import lombok.Cleanup; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.openqa.selenium.By; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.testcontainers.SeleniumTestImages; -import org.testcontainers.containers.BrowserWebDriverContainer; -import org.testcontainers.containers.Network; -import org.testcontainers.containers.NginxContainer; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; - -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - - -/** - * @author richardnorth - */ -public class LinkedContainerTest { - - private static File contentFolder = new File(System.getProperty("user.home") + "/.tmp-test-container"); - - @Rule - public Network network = Network.newNetwork(); - - @Rule - public NginxContainer nginx = new NginxContainer<>(SeleniumTestImages.NGINX_TEST_IMAGE) - .withNetwork(network) - .withNetworkAliases("nginx") - .withCustomContent(contentFolder.toString()); - - @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() - .withNetwork(network) - .withCapabilities(new ChromeOptions()); - - @BeforeClass - public static void setupContent() throws FileNotFoundException { - contentFolder.mkdir(); - contentFolder.setReadable(true, false); - contentFolder.setWritable(true, false); - contentFolder.setExecutable(true, false); - - - File indexFile = new File(contentFolder, "index.html"); - indexFile.setReadable(true, false); - indexFile.setWritable(true, false); - indexFile.setExecutable(true, false); - - @Cleanup PrintStream printStream = new PrintStream(new FileOutputStream(indexFile)); - printStream.println("This worked"); - } - - @Test - public void testWebDriverToNginxContainerAccessViaContainerLink() { - RemoteWebDriver driver = chrome.getWebDriver(); - - driver.get("http://nginx/"); - - assertEquals("Using selenium, an HTTP GET from the nginx server returns the index.html from the custom content directory", "This worked", driver.findElement(By.tagName("body")).getText()); - } -} diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java index 6ecf0899ede..bbc3b4db7a0 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java @@ -12,12 +12,8 @@ public class SpecificImageNameWebDriverContainerTest extends BaseWebDriverContai @Rule public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer<>(FIREFOX_IMAGE) - .withCapabilities(new FirefoxOptions()); - - @Test - public void simpleTest() { - doSimpleWebdriverTest(firefox); - } + .withCapabilities(new FirefoxOptions()) + .withNetwork(NETWORK); @Test public void simpleExploreTest() { From 149badfb729504b91b9127d7e30c014741942918 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Sep 2020 19:11:46 +0100 Subject: [PATCH 0995/4969] Bump aws-java-sdk-s3 from 1.11.865 to 1.11.870 in /modules/localstack (#3285) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.865 to 1.11.870. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.865...1.11.870) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 436f03ab236..f48b3cf71bb 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.865' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.870' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.865' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.860' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From 63e2c49bbf88d9d5b4972051c5a127a34ee8a616 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 29 Sep 2020 09:45:39 +0100 Subject: [PATCH 0996/4969] Make testMatrix task emit all check tasks, rather than filtering out up-to-date tasks (#3287) --- gradle/ci-support.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/gradle/ci-support.gradle b/gradle/ci-support.gradle index e83c936f2f3..b878c107796 100644 --- a/gradle/ci-support.gradle +++ b/gradle/ci-support.gradle @@ -9,10 +9,7 @@ task testMatrix { dependsOn(checkTasks) doLast { - // Obtain a list of check tasks that are not up-to-date, i.e. - // the ones which Gradle cannot find a cached output for. def checkTaskPaths = checkTasks - .findAll { !it.state.upToDate } .collect { it.path } println(JsonOutput.toJson(checkTaskPaths)) From 1e597ccd4fa1a7113d3077599e0b13237c1fef51 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 29 Sep 2020 11:02:01 +0100 Subject: [PATCH 0997/4969] Add image compatibility checks (#3021) Co-authored-by: Kevin Wittek --- build.gradle | 2 +- .../containers/GenericContainer.java | 76 +++++---- .../utility/DockerImageName.java | 152 ++++++++++++------ .../utility/TestcontainersConfiguration.java | 51 +++--- .../testcontainers/utility/Versioning.java | 95 +++++++++++ .../utility/AuthenticatedImagePullTest.java | 17 +- .../DockerImageNameCompatibilityTest.java | 93 +++++++++++ .../utility/DockerImageNameTest.java | 4 +- .../TestcontainersConfigurationTest.java | 11 +- docs/modules/kafka.md | 4 +- .../containers/MongoDbContainer.java | 1 - .../containers/CassandraContainer.java | 14 +- .../containers/ClickHouseContainer.java | 15 +- .../containers/CockroachContainer.java | 21 ++- .../couchbase/CouchbaseContainer.java | 14 +- .../containers/Db2Container.java | 17 +- .../dynamodb/DynaliteContainer.java | 14 +- .../elasticsearch/ElasticsearchContainer.java | 31 ++-- .../ElasticsearchContainerTest.java | 17 +- .../containers/InfluxDBContainer.java | 14 +- .../containers/JdbcDatabaseContainer.java | 1 - .../containers/KafkaContainer.java | 9 +- .../containers/KafkaContainerTest.java | 43 +++-- .../localstack/LocalStackContainer.java | 31 ++-- .../containers/MariaDBContainer.java | 19 ++- .../containers/MockServerContainer.java | 13 +- .../containers/MongoDBContainer.java | 13 +- .../MSSQLR2DBCDatabaseContainerProvider.java | 1 + .../containers/MSSQLServerContainer.java | 17 +- .../containers/MySQLContainer.java | 17 +- .../containers/Neo4jContainer.java | 50 +++--- .../containers/NginxContainer.java | 16 +- .../containers/OracleContainer.java | 4 - .../containers/OrientDBContainer.java | 11 +- .../containers/PostgisContainerProvider.java | 4 +- .../containers/PostgreSQLContainer.java | 11 +- .../containers/PrestoContainer.java | 10 +- .../containers/PulsarContainer.java | 8 +- .../containers/RabbitMQContainer.java | 12 +- .../containers/BrowserWebDriverContainer.java | 60 +++---- .../testcontainers/junit/Selenium3xTest.java | 4 +- ...ecificImageNameWebDriverContainerTest.java | 3 +- .../containers/SolrContainer.java | 13 +- .../containers/ToxiproxyContainer.java | 12 +- .../testcontainers/vault/VaultContainer.java | 11 +- 45 files changed, 692 insertions(+), 364 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/utility/Versioning.java create mode 100644 core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java diff --git a/build.gradle b/build.gradle index b7830992b07..c51b24909cb 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ subprojects { } lombok { - version = '1.18.8' + version = '1.18.12' } task delombok(type: io.franzbecker.gradle.lombok.task.DelombokTask) { diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 22a6c2408d6..95050d8f8ee 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1,8 +1,10 @@ package org.testcontainers.containers; +import static com.google.common.collect.Lists.newArrayList; +import static org.testcontainers.utility.CommandLine.runShellCommand; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerCmd; @@ -21,6 +23,39 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.hash.Hashing; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.Adler32; +import java.util.zip.Checksum; import lombok.AccessLevel; import lombok.Data; import lombok.NonNull; @@ -62,43 +97,6 @@ import org.testcontainers.utility.ResourceReaper; import org.testcontainers.utility.TestcontainersConfiguration; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.UndeclaredThrowableException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.zip.Adler32; -import java.util.zip.Checksum; - -import static com.google.common.collect.Lists.newArrayList; -import static org.testcontainers.utility.CommandLine.runShellCommand; - /** * Base class for that allows a container to be launched and controlled. */ @@ -241,7 +239,7 @@ public GenericContainer(@NonNull final RemoteDockerImage image) { */ @Deprecated public GenericContainer() { - this(TestcontainersConfiguration.getInstance().getTinyImage()); + this(TestcontainersConfiguration.getInstance().getTinyDockerImageName().asCanonicalNameString()); } /** diff --git a/core/src/main/java/org/testcontainers/utility/DockerImageName.java b/core/src/main/java/org/testcontainers/utility/DockerImageName.java index b4a40be2f16..af8e5300863 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerImageName.java +++ b/core/src/main/java/org/testcontainers/utility/DockerImageName.java @@ -4,26 +4,32 @@ import com.google.common.net.HostAndPort; import lombok.AccessLevel; import lombok.AllArgsConstructor; -import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.With; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.testcontainers.utility.Versioning.Sha256Versioning; +import org.testcontainers.utility.Versioning.TagVersioning; import java.util.regex.Pattern; -@EqualsAndHashCode(exclude = "rawName") +@EqualsAndHashCode(exclude = { "rawName", "compatibleSubstituteFor" }) @AllArgsConstructor(access = AccessLevel.PRIVATE) public final class DockerImageName { /* Regex patterns used for validation */ private static final String ALPHA_NUMERIC = "[a-z0-9]+"; - private static final String SEPARATOR = "([\\.]{1}|_{1,2}|-+)"; + private static final String SEPARATOR = "([.]|_{1,2}|-+)"; private static final String REPO_NAME_PART = ALPHA_NUMERIC + "(" + SEPARATOR + ALPHA_NUMERIC + ")*"; private static final Pattern REPO_NAME = Pattern.compile(REPO_NAME_PART + "(/" + REPO_NAME_PART + ")*"); private final String rawName; private final String registry; private final String repo; - @NotNull private final Versioning versioning; + @NotNull @With(AccessLevel.PRIVATE) + private final Versioning versioning; + @Nullable @With(AccessLevel.PRIVATE) + private final DockerImageName compatibleSubstituteFor; /** * Parses a docker image name from a provided string. @@ -52,8 +58,8 @@ public DockerImageName(String fullImageName) { String remoteName; if (slashIndex == -1 || (!fullImageName.substring(0, slashIndex).contains(".") && - !fullImageName.substring(0, slashIndex).contains(":") && - !fullImageName.substring(0, slashIndex).equals("localhost"))) { + !fullImageName.substring(0, slashIndex).contains(":") && + !fullImageName.substring(0, slashIndex).equals("localhost"))) { registry = ""; remoteName = fullImageName; } else { @@ -69,8 +75,10 @@ public DockerImageName(String fullImageName) { versioning = new TagVersioning(remoteName.split(":")[1]); } else { repo = remoteName; - versioning = new TagVersioning("latest"); + versioning = Versioning.ANY; } + + compatibleSubstituteFor = null; } /** @@ -92,8 +100,8 @@ public DockerImageName(String nameWithoutTag, @NotNull String version) { String remoteName; if (slashIndex == -1 || (!nameWithoutTag.substring(0, slashIndex).contains(".") && - !nameWithoutTag.substring(0, slashIndex).contains(":") && - !nameWithoutTag.substring(0, slashIndex).equals("localhost"))) { + !nameWithoutTag.substring(0, slashIndex).contains(":") && + !nameWithoutTag.substring(0, slashIndex).equals("localhost"))) { registry = ""; remoteName = nameWithoutTag; } else { @@ -108,6 +116,8 @@ public DockerImageName(String nameWithoutTag, @NotNull String version) { repo = remoteName; versioning = new TagVersioning(version); } + + compatibleSubstituteFor = null; } /** @@ -132,7 +142,7 @@ public String getVersionPart() { * @return canonical name for the image */ public String asCanonicalNameString() { - return getUnversionedPart() + versioning.getSeparator() + versioning.toString(); + return getUnversionedPart() + versioning.getSeparator() + getVersionPart(); } @Override @@ -146,7 +156,8 @@ public String toString() { * @throws IllegalArgumentException if not valid */ public void assertValid() { - HostAndPort.fromString(registry); + //noinspection UnstableApiUsage + HostAndPort.fromString(registry); // return value ignored - this throws if registry is not a valid host:port string if (!REPO_NAME.matcher(repo).matches()) { throw new IllegalArgumentException(repo + " is not a valid Docker image name (in " + rawName + ")"); } @@ -159,63 +170,98 @@ public String getRegistry() { return registry; } + /** + * @param newTag version tag for the copy to use + * @return an immutable copy of this {@link DockerImageName} with the new version tag + */ public DockerImageName withTag(final String newTag) { - return new DockerImageName(rawName, registry, repo, new TagVersioning(newTag)); + return withVersioning(new TagVersioning(newTag)); } - private interface Versioning { - boolean isValid(); - - String getSeparator(); + /** + * Declare that this {@link DockerImageName} is a compatible substitute for another image - i.e. that this image + * behaves as the other does, and is compatible with Testcontainers' assumptions about the other image. + * + * @param otherImageName the image name of the other image + * @return an immutable copy of this {@link DockerImageName} with the compatibility declaration attached. + */ + public DockerImageName asCompatibleSubstituteFor(String otherImageName) { + return withCompatibleSubstituteFor(DockerImageName.parse(otherImageName)); } - @Data - private static class TagVersioning implements Versioning { - public static final String TAG_REGEX = "[\\w][\\w\\.\\-]{0,127}"; - private final String tag; - - TagVersioning(String tag) { - this.tag = tag; - } + /** + * Declare that this {@link DockerImageName} is a compatible substitute for another image - i.e. that this image + * behaves as the other does, and is compatible with Testcontainers' assumptions about the other image. + * + * @param otherImageName the image name of the other image + * @return an immutable copy of this {@link DockerImageName} with the compatibility declaration attached. + */ + public DockerImageName asCompatibleSubstituteFor(DockerImageName otherImageName) { + return withCompatibleSubstituteFor(otherImageName); + } - @Override - public boolean isValid() { - return tag.matches(TAG_REGEX); + /** + * Test whether this {@link DockerImageName} has declared compatibility with another image (set using + * {@link DockerImageName#asCompatibleSubstituteFor(String)} or + * {@link DockerImageName#asCompatibleSubstituteFor(DockerImageName)}. + *

+ * If a version tag part is present in the other image name, the tags must exactly match, unless it + * is 'latest'. If a version part is not present in the other image name, the tag contents are ignored. + * + * @param other the other image that we are trying to test compatibility with + * @return whether this image has declared compatibility. + */ + public boolean isCompatibleWith(DockerImageName other) { + // is this image already the same or equivalent? + if (other.equals(this)) { + return true; } - @Override - public String getSeparator() { - return ":"; + if (this.compatibleSubstituteFor == null) { + return false; } - @Override - public String toString() { - return tag; - } + return this.compatibleSubstituteFor.isCompatibleWith(other); } - @Data - private static class Sha256Versioning implements Versioning { - public static final String HASH_REGEX = "[0-9a-fA-F]{32,}"; - private final String hash; - - Sha256Versioning(String hash) { - this.hash = hash; - } - - @Override - public boolean isValid() { - return hash.matches(HASH_REGEX); + /** + * Behaves as {@link DockerImageName#isCompatibleWith(DockerImageName)} but throws an exception + * rather than returning false if a mismatch is detected. + * + * @param anyOthers the other image(s) that we are trying to check compatibility with. If more + * than one is provided, this method will check compatibility with at least one + * of them. + * @throws IllegalStateException if {@link DockerImageName#isCompatibleWith(DockerImageName)} + * returns false + */ + public void assertCompatibleWith(DockerImageName... anyOthers) { + if (anyOthers.length == 0) { + throw new IllegalArgumentException("anyOthers parameter must be non-empty"); } - @Override - public String getSeparator() { - return "@"; + for (DockerImageName anyOther : anyOthers) { + if (this.isCompatibleWith(anyOther)) { + return; + } } - @Override - public String toString() { - return "sha256:" + hash; - } + final DockerImageName exampleOther = anyOthers[0]; + + throw new IllegalStateException( + String.format( + "Failed to verify that image '%s' is a compatible substitute for '%s'. This generally means that " + + + "you are trying to use an image that Testcontainers has not been designed to use. If this is " + + + "deliberate, and if you are confident that the image is compatible, you should declare " + + + "compatibility in code using the `asCompatibleSubstituteFor` method. For example:\n" + + + " DockerImageName myImage = DockerImageName.parse(\"%s\").asCompatibleSubstituteFor(\"%s\");\n" + + + "and then use `myImage` instead.", + this.rawName, exampleOther.rawName, this.rawName, exampleOther.rawName + ) + ); } } diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 9f283ba2685..521a7519c2a 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -56,49 +56,58 @@ static AtomicReference getInstanceField() { this.properties.putAll(classpathProperties); this.properties.putAll(environmentProperties); - properties.keySet() - .forEach(key -> properties.replace(key, properties.getProperty(String.valueOf(key)).trim())); + } + + private DockerImageName getImage(final String key, final String defaultValue) { + return DockerImageName + .parse(properties.getProperty(key, defaultValue).trim()) + .asCompatibleSubstituteFor(defaultValue); } @Deprecated public String getAmbassadorContainerImage() { - return String.valueOf(properties.getOrDefault("ambassador.container.image", "richnorth/ambassador:latest")); + return getAmbassadorContainerDockerImageName().asCanonicalNameString(); + } + + @Deprecated + public DockerImageName getAmbassadorContainerDockerImageName() { + return getImage("ambassador.container.image", "richnorth/ambassador:latest"); } @Deprecated public String getSocatContainerImage() { - return String.valueOf(properties.getOrDefault("socat.container.image", "alpine/socat:latest")); + return getSocatDockerImageName().asCanonicalNameString(); } public DockerImageName getSocatDockerImageName() { - return DockerImageName.parse(getSocatContainerImage()); + return getImage("socat.container.image", "alpine/socat:latest"); } @Deprecated public String getVncRecordedContainerImage() { - return String.valueOf(properties.getOrDefault("vncrecorder.container.image", "testcontainers/vnc-recorder:1.1.0")); + return getVncDockerImageName().asCanonicalNameString(); } public DockerImageName getVncDockerImageName() { - return DockerImageName.parse(getVncRecordedContainerImage()); + return getImage("vncrecorder.container.image", "testcontainers/vnc-recorder:1.1.0"); } @Deprecated public String getDockerComposeContainerImage() { - return String.valueOf(properties.getOrDefault("compose.container.image", "docker/compose:1.24.1")); + return getDockerComposeDockerImageName().asCanonicalNameString(); } public DockerImageName getDockerComposeDockerImageName() { - return DockerImageName.parse(getDockerComposeContainerImage()); + return getImage("compose.container.image", "docker/compose:1.24.1"); } @Deprecated public String getTinyImage() { - return String.valueOf(properties.getOrDefault("tinyimage.container.image", "alpine:3.5")); + return getTinyDockerImageName().asCanonicalNameString(); } public DockerImageName getTinyDockerImageName() { - return DockerImageName.parse(getTinyImage()); + return getImage("tinyimage.container.image", "alpine:3.5"); } public boolean isRyukPrivileged() { @@ -107,20 +116,20 @@ public boolean isRyukPrivileged() { @Deprecated public String getRyukImage() { - return String.valueOf(properties.getOrDefault("ryuk.container.image", "testcontainers/ryuk:0.3.0")); + return getRyukDockerImageName().asCanonicalNameString(); } public DockerImageName getRyukDockerImageName() { - return DockerImageName.parse(getRyukImage()); + return getImage("ryuk.container.image", "testcontainers/ryuk:0.3.0"); } @Deprecated public String getSSHdImage() { - return String.valueOf(properties.getOrDefault("sshd.container.image", "testcontainers/sshd:1.0.0")); + return getSSHdDockerImageName().asCanonicalNameString(); } public DockerImageName getSSHdDockerImageName() { - return DockerImageName.parse(getSSHdImage()); + return getImage("sshd.container.image", "testcontainers/sshd:1.0.0"); } public Integer getRyukTimeout() { @@ -129,29 +138,29 @@ public Integer getRyukTimeout() { @Deprecated public String getKafkaImage() { - return String.valueOf(properties.getOrDefault("kafka.container.image", "confluentinc/cp-kafka")); + return getKafkaDockerImageName().asCanonicalNameString(); } public DockerImageName getKafkaDockerImageName() { - return DockerImageName.parse(getKafkaImage()); + return getImage("kafka.container.image", "confluentinc/cp-kafka"); } @Deprecated public String getPulsarImage() { - return String.valueOf(properties.getOrDefault("pulsar.container.image", "apachepulsar/pulsar")); + return getPulsarDockerImageName().asCanonicalNameString(); } public DockerImageName getPulsarDockerImageName() { - return DockerImageName.parse(getPulsarImage()); + return getImage("pulsar.container.image", "apachepulsar/pulsar"); } @Deprecated public String getLocalStackImage() { - return String.valueOf(properties.getOrDefault("localstack.container.image", "localstack/localstack")); + return getLocalstackDockerImageName().asCanonicalNameString(); } public DockerImageName getLocalstackDockerImageName() { - return DockerImageName.parse(getLocalStackImage()); + return getImage("localstack.container.image", "localstack/localstack"); } public boolean isDisableChecks() { diff --git a/core/src/main/java/org/testcontainers/utility/Versioning.java b/core/src/main/java/org/testcontainers/utility/Versioning.java new file mode 100644 index 00000000000..8944b3f0ba6 --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/Versioning.java @@ -0,0 +1,95 @@ +package org.testcontainers.utility; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * Represents mechanisms for versioning docker images. + */ +interface Versioning { + AnyVersion ANY = new AnyVersion(); + + boolean isValid(); + + String getSeparator(); + + @NoArgsConstructor(access = AccessLevel.PRIVATE) + class AnyVersion implements Versioning { + + @Override + public boolean isValid() { + return true; + } + + @Override + public String getSeparator() { + return ""; + } + + @Override + public String toString() { + return ""; + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof Versioning; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + } + + @EqualsAndHashCode + class TagVersioning implements Versioning { + public static final String TAG_REGEX = "[\\w][\\w.\\-]{0,127}"; + private final String tag; + + TagVersioning(String tag) { + this.tag = tag; + } + + @Override + public boolean isValid() { + return tag.matches(TAG_REGEX); + } + + @Override + public String getSeparator() { + return ":"; + } + + @Override + public String toString() { + return tag; + } + } + + @EqualsAndHashCode + class Sha256Versioning implements Versioning { + public static final String HASH_REGEX = "[0-9a-fA-F]{32,}"; + private final String hash; + + Sha256Versioning(String hash) { + this.hash = hash; + } + + @Override + public boolean isValid() { + return hash.matches(HASH_REGEX); + } + + @Override + public String getSeparator() { + return "@"; + } + + @Override + public String toString() { + return "sha256:" + hash; + } + } +} diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 0afb4d956a1..e49ff2880df 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -59,7 +59,7 @@ public class AuthenticatedImagePullTest { private static DockerClient client; private static String testImageName; - private static String testImageNameWithTag; + private static RegistryAuthLocator mockAuthLocator; @BeforeClass public static void setUp() throws InterruptedException { @@ -68,9 +68,8 @@ public static void setUp() throws InterruptedException { String testRegistryAddress = authenticatedRegistry.getHost() + ":" + authenticatedRegistry.getFirstMappedPort(); testImageName = testRegistryAddress + "/alpine"; - testImageNameWithTag = testImageName + ":latest"; - final DockerImageName expectedName = DockerImageName.parse(testImageNameWithTag); + final DockerImageName expectedName = DockerImageName.parse(testImageName); final AuthConfig authConfig = new AuthConfig() .withUsername("testuser") .withPassword("notasecret") @@ -89,7 +88,7 @@ public static void setUp() throws InterruptedException { @Before public void removeImageFromLocalDocker() { // remove the image tag from local docker so that it must be pulled before use - client.removeImageCmd(testImageNameWithTag).withForce(true).exec(); + client.removeImageCmd(testImageName).withForce(true).exec(); } @AfterClass @@ -100,7 +99,7 @@ public static void tearDown() { @Test public void testThatAuthLocatorIsUsedForContainerCreation() { // actually start a container, which will require an authenticated pull - try (final GenericContainer container = new GenericContainer<>(DockerImageName.parse(testImageNameWithTag)) + try (final GenericContainer container = new GenericContainer<>(DockerImageName.parse(testImageName)) .withCommand("/bin/sh", "-c", "sleep 10")) { container.start(); @@ -112,7 +111,7 @@ public void testThatAuthLocatorIsUsedForContainerCreation() { public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { // Prepare a simple temporary Dockerfile which requires our custom private image Path tempFile = getLocalTempFile(".Dockerfile"); - String dockerFileContent = "FROM " + testImageNameWithTag; + String dockerFileContent = "FROM " + testImageName; Files.write(tempFile, dockerFileContent.getBytes()); // Start a container built from a derived image, which will require an authenticated pull @@ -136,7 +135,7 @@ public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { "services:\n" + " privateservice:\n" + " command: /bin/sh -c 'sleep 60'\n" + - " image: " + testImageNameWithTag; + " image: " + testImageName; Files.write(tempFile, composeFileContent.getBytes()); // Start the docker compose project, which will require an authenticated pull @@ -177,9 +176,9 @@ private static void putImageInRegistry() throws InterruptedException { .getId(); // push the image to the registry - client.tagImageCmd(id, testImageName, "latest").exec(); + client.tagImageCmd(id, testImageName, "").exec(); - client.pushImageCmd(testImageNameWithTag) + client.pushImageCmd(testImageName) .exec(new ResultCallback.Adapter<>()) .awaitCompletion(1, TimeUnit.MINUTES); } diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java new file mode 100644 index 00000000000..9e7136ea6d3 --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java @@ -0,0 +1,93 @@ +package org.testcontainers.utility; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.hamcrest.core.StringContains.containsString; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; + + +public class DockerImageNameCompatibilityTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testPlainImage() { + DockerImageName subject = DockerImageName.parse("foo"); + + assertFalse("image name foo != bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + } + @Test + public void testNoTagTreatedAsWildcard() { + final DockerImageName subject = DockerImageName.parse("foo:4.5.6"); + /* + foo:1.2.3 != foo:4.5.6 + foo:1.2.3 ~= foo + foo:1.2.3 ~= foo:latest + + The test is effectively making sure that no tag and `latest` tag are equivalent + */ + assertFalse("foo:4.5.6 != foo:1.2.3", subject.isCompatibleWith(DockerImageName.parse("foo:1.2.3"))); + assertTrue("foo:4.5.6 ~= foo", subject.isCompatibleWith(DockerImageName.parse("foo"))); + } + + @Test + public void testImageWithAutomaticCompatibilityForFullPath() { + DockerImageName subject = DockerImageName.parse("repo/foo:1.2.3"); + + assertTrue("repo/foo:1.2.3 ~= repo/foo", subject.isCompatibleWith(DockerImageName.parse("repo/foo"))); + } + + @Test + public void testImageWithClaimedCompatibility() { + DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("bar"); + + assertTrue("foo(bar) ~= bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + assertFalse("foo(bar) != fizz", subject.isCompatibleWith(DockerImageName.parse("fizz"))); + } + + @Test + public void testImageWithClaimedCompatibilityAndVersion() { + DockerImageName subject = DockerImageName.parse("foo:1.2.3").asCompatibleSubstituteFor("bar"); + + assertTrue("foo:1.2.3(bar) ~= bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + } + + @Test + public void testImageWithClaimedCompatibilityForFullPath() { + DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("registry/repo/bar"); + + assertTrue("foo(registry/repo/bar) ~= registry/repo/bar", subject.isCompatibleWith(DockerImageName.parse("registry/repo/bar"))); + assertFalse("foo(registry/repo/bar) != repo/bar", subject.isCompatibleWith(DockerImageName.parse("repo/bar"))); + assertFalse("foo(registry/repo/bar) != bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + } + + @Test + public void testImageWithClaimedCompatibilityForVersion() { + DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("bar:1.2.3"); + + assertTrue("foo(bar:1.2.3) ~= bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + assertTrue("foo(bar:1.2.3) ~= bar:1.2.3", subject.isCompatibleWith(DockerImageName.parse("bar:1.2.3"))); + assertFalse("foo(bar:1.2.3) != bar:0.0.1", subject.isCompatibleWith(DockerImageName.parse("bar:0.0.1"))); + assertFalse("foo(bar:1.2.3) != bar:2.0.0", subject.isCompatibleWith(DockerImageName.parse("bar:2.0.0"))); + assertFalse("foo(bar:1.2.3) != bar:1.2.4", subject.isCompatibleWith(DockerImageName.parse("bar:1.2.4"))); + } + + @Test + public void testAssertMethodAcceptsCompatible() { + DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("bar"); + subject.assertCompatibleWith(DockerImageName.parse("bar")); + } + + @Test + public void testAssertMethodRejectsIncompatible() { + thrown.expect(IllegalStateException.class); + thrown.expectMessage(containsString("Failed to verify that image 'foo' is a compatible substitute for 'bar'")); + + DockerImageName subject = DockerImageName.parse("foo"); + subject.assertCompatibleWith(DockerImageName.parse("bar")); + } +} diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index b0ed9428a5d..34575f2b4b9 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -112,7 +112,7 @@ public void testParsing() { canonicalName = unversionedPart + versionSeparator + version; } else { combined = unversionedPart; - canonicalName = unversionedPart + ":latest"; + canonicalName = unversionedPart; } VisibleAssertions.context("For " + combined); @@ -124,7 +124,7 @@ public void testParsing() { if (version != null) { assertEquals(combined + " has version part: " + version, version, imageName.getVersionPart()); } else { - assertEquals(combined + " has implicit version: latest", "latest", imageName.getVersionPart()); + assertEquals(combined + " has no version specified", "", imageName.getVersionPart()); } assertEquals(combined + " has canonical name: " + canonicalName, canonicalName, imageName.asCanonicalNameString()); diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index f0b8fb36a37..ccd68fbd984 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -1,14 +1,13 @@ package org.testcontainers.utility; -import org.junit.Test; - -import java.util.Properties; -import java.util.UUID; - import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import java.util.Properties; +import java.util.UUID; +import org.junit.Test; + public class TestcontainersConfigurationTest { final Properties environmentProperties = new Properties(); @@ -48,7 +47,7 @@ public void shouldReadReuseFromEnvironmentOnly() { assertTrue("reuse enabled", newConfig().environmentSupportsReuse()); environmentProperties.setProperty("ryuk.container.image", " testcontainersofficial/ryuk:0.3.0 "); - assertEquals("trailing whitespace was not removed from image name property", "testcontainersofficial/ryuk:0.3.0",newConfig().getRyukImage()); + assertEquals("trailing whitespace was not removed from image name property", "testcontainersofficial/ryuk:0.3.0",newConfig().getRyukDockerImageName().asCanonicalNameString()); } diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index 83bb8af0628..d36273ac8e1 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -26,7 +26,7 @@ Now your tests or any other process running on your machine can get access to ru ### Selecting Kafka version -You can select a version of Confluent Platform by passing it to the container's constructor: +You can select a specific Confluent Platform Kafka docker image by passing it to the container's constructor: [Version Constructor](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:constructorWithVersion @@ -44,7 +44,7 @@ If for some reason you want to use an externally running Zookeeper, then just pa ## Multi-container usage -If your test needs to run some other Docker container which needs access to the Kafka, do the following: +If your test needs to run some other Docker container which needs access to Kafka, do the following: * Run your other container on the same network as Kafka container, e.g.: diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java index e44f2bb982e..c4c07c1f601 100644 --- a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java +++ b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java @@ -38,7 +38,6 @@ public MongoDbContainer() { * @param image the image (e.g. {@value DEFAULT_IMAGE_AND_TAG}) to use * @deprecated use {@link MongoDbContainer(DockerImageName)} instead */ - @Deprecated public MongoDbContainer(@NotNull String image) { this(DockerImageName.parse(image)); } diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index 681c58f4efb..597b1c9b017 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -25,8 +25,11 @@ */ public class CassandraContainer> extends GenericContainer { + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("cassandra"); + private static final String DEFAULT_TAG = "3.11.2"; + @Deprecated - public static final String IMAGE = "cassandra"; + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); public static final Integer CQL_PORT = 9042; private static final String CONTAINER_CONFIG_LOCATION = "/etc/cassandra"; @@ -42,19 +45,18 @@ public class CassandraContainer> extends G */ @Deprecated public CassandraContainer() { - this("cassandra:3.11.2"); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link #CassandraContainer(DockerImageName)} instead - */ - @Deprecated public CassandraContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public CassandraContainer(DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + addExposedPort(CQL_PORT); setStartupAttempts(3); this.enableJmxReporting = false; diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 6bdcff7b3f2..e26ca8c8416 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -7,7 +7,12 @@ public class ClickHouseContainer extends JdbcDatabaseContainer { public static final String NAME = "clickhouse"; - public static final String IMAGE = "yandex/clickhouse-server"; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("yandex/clickhouse-server"); + + @Deprecated + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); + @Deprecated public static final String DEFAULT_TAG = "18.10.3"; @@ -27,13 +32,9 @@ public class ClickHouseContainer extends JdbcDatabaseContainer { */ @Deprecated public ClickHouseContainer() { - super(IMAGE + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link ClickHouseContainer(DockerImageName)} instead - */ - @Deprecated public ClickHouseContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } @@ -41,6 +42,8 @@ public ClickHouseContainer(String dockerImageName) { public ClickHouseContainer(final DockerImageName dockerImageName) { super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(HTTP_PORT, NATIVE_PORT); waitingFor( new HttpWaitStrategy() diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index 54420155f05..2a7990413e4 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -6,9 +6,18 @@ import java.time.Duration; public class CockroachContainer extends JdbcDatabaseContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("cockroachdb/cockroach"); + private static final String DEFAULT_TAG = "v19.1.1"; + public static final String NAME = "cockroach"; - public static final String IMAGE = "cockroachdb/cockroach"; - public static final String IMAGE_TAG = "v19.1.1"; + + @Deprecated + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); + + @Deprecated + public static final String IMAGE_TAG = DEFAULT_TAG; + private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; private static final String JDBC_URL_PREFIX = "jdbc:postgresql"; private static final String TEST_QUERY_STRING = "SELECT 1"; @@ -24,13 +33,9 @@ public class CockroachContainer extends JdbcDatabaseContainer { private static final int KV_SSL_PORT = 11207; - private static final String DOCKER_IMAGE_NAME = "couchbase/server"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("couchbase/server"); - private static final String VERSION = "6.5.1"; + private static final String DEFAULT_TAG = "6.5.1"; private static final ObjectMapper MAPPER = new ObjectMapper(); @@ -92,26 +92,26 @@ public class CouchbaseContainer extends GenericContainer { */ @Deprecated public CouchbaseContainer() { - this(DOCKER_IMAGE_NAME + ":" + VERSION); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** - * Creates a new couchbase container with a custom image name. + * Creates a new couchbase container with the specified image name. * * @param dockerImageName the image name that should be used. - * @deprecated use {@link CouchbaseContainer(DockerImageName)} instead */ - @Deprecated public CouchbaseContainer(final String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } /** * Create a new couchbase container with the specified image name. - * @param dockerImageName + * @param dockerImageName the image name that should be used. */ public CouchbaseContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); } /** diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index aa6d136aaec..c1a252936ea 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -12,7 +12,13 @@ public class Db2Container extends JdbcDatabaseContainer { public static final String NAME = "db2"; - public static final String DEFAULT_DB2_IMAGE_NAME = "ibmcom/db2"; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("ibmcom/db2"); + + @Deprecated + public static final String DEFAULT_DB2_IMAGE_NAME = DEFAULT_IMAGE_NAME.getUnversionedPart(); + + @Deprecated public static final String DEFAULT_TAG = "11.5.0.0a"; public static final int DB2_PORT = 50000; @@ -25,19 +31,18 @@ public class Db2Container extends JdbcDatabaseContainer { */ @Deprecated public Db2Container() { - this(DEFAULT_DB2_IMAGE_NAME + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link Db2Container(DockerImageName)} instead - */ - @Deprecated public Db2Container(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public Db2Container(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withPrivilegedMode(true); this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*Setup has completed\\..*") diff --git a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java index 6063c1a5dbe..8900964a8bb 100644 --- a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java +++ b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java @@ -14,7 +14,8 @@ */ public class DynaliteContainer extends GenericContainer { - private static final String IMAGE_NAME = "quay.io/testcontainers/dynalite:v1.2.1-1"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("quay.io/testcontainers/dynalite"); + private static final String DEFAULT_TAG = "v1.2.1-1"; private static final int MAPPED_PORT = 4567; /** @@ -22,20 +23,19 @@ public class DynaliteContainer extends GenericContainer { */ @Deprecated public DynaliteContainer() { - this(IMAGE_NAME); - withExposedPorts(MAPPED_PORT); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link DynaliteContainer(DockerImageName)} instead - */ - @Deprecated public DynaliteContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public DynaliteContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(MAPPED_PORT); } diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index 6ad0172269d..7ed660d38c6 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -1,16 +1,15 @@ package org.testcontainers.elasticsearch; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +import java.net.InetSocketAddress; +import java.time.Duration; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.Base58; import org.testcontainers.utility.DockerImageName; -import java.net.InetSocketAddress; -import java.time.Duration; - -import static java.net.HttpURLConnection.HTTP_OK; -import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; - /** * Represents an elasticsearch docker instance which exposes by default port 9200 and 9300 (transport.tcp.port) * The docker image is by default fetched from docker.elastic.co/elasticsearch/elasticsearch @@ -28,35 +27,41 @@ public class ElasticsearchContainer extends GenericContainer> extends GenericContainer { - public static final String VERSION = "1.4.3"; public static final Integer INFLUXDB_PORT = 8086; - private static final String IMAGE_NAME = "influxdb"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("influxdb"); + private static final String DEFAULT_TAG = "1.4.3"; + + @Deprecated + public static final String VERSION = DEFAULT_TAG; private boolean authEnabled = true; private String admin = "admin"; @@ -32,7 +35,7 @@ public class InfluxDBContainer> extends Gen */ @Deprecated public InfluxDBContainer() { - this(VERSION); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** @@ -40,11 +43,14 @@ public InfluxDBContainer() { */ @Deprecated public InfluxDBContainer(final String version) { - this(DockerImageName.parse(IMAGE_NAME + ":" + version)); + this(DEFAULT_IMAGE_NAME.withTag(version)); } public InfluxDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + waitStrategy = new WaitAllStrategy() .withStrategy(Wait.forHttp("/ping").withBasicCredentials(username, password).forStatusCode(204)) .withStrategy(Wait.forListeningPort()); diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 4d1c4ece67b..26d699a1813 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -42,7 +42,6 @@ public abstract class JdbcDatabaseContainer { + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("confluentinc/cp-kafka"); + private static final String DEFAULT_TAG = "5.2.1"; + private static final String STARTER_SCRIPT = "/testcontainers_start.sh"; public static final int KAFKA_PORT = 9093; @@ -35,7 +38,7 @@ public class KafkaContainer extends GenericContainer { */ @Deprecated public KafkaContainer() { - this("5.2.1"); + this(TestcontainersConfiguration.getInstance().getKafkaDockerImageName().withTag(DEFAULT_TAG)); } /** @@ -43,12 +46,14 @@ public KafkaContainer() { */ @Deprecated public KafkaContainer(String confluentPlatformVersion) { - this(DockerImageName.parse(TestcontainersConfiguration.getInstance().getKafkaImage() + ":" + confluentPlatformVersion)); + this(TestcontainersConfiguration.getInstance().getKafkaDockerImageName().withTag(confluentPlatformVersion)); } public KafkaContainer(final DockerImageName dockerImageName) { super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(KAFKA_PORT); // Use two listeners with different names, it will force Kafka to communicate with itself via internal diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 71702ce8e62..6a669b2f60d 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -1,6 +1,13 @@ package org.testcontainers.containers; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + import com.google.common.collect.ImmutableMap; +import java.time.Duration; +import java.util.UUID; +import java.util.concurrent.TimeUnit; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; @@ -10,27 +17,19 @@ import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringSerializer; -import org.junit.Rule; +import org.junit.ClassRule; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.utility.DockerImageName; -import java.time.Duration; -import java.util.Arrays; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - public class KafkaContainerTest { private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:5.2.1"); private static final DockerImageName ZOOKEEPER_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-zookeeper:4.0.0"); // junitRule { - @Rule - public KafkaContainer kafka = new KafkaContainer(); + @ClassRule + public static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.2.1")); // } @Test @@ -43,10 +42,10 @@ public void testUsage() throws Exception { @Test - public void testUsageWithVersion() throws Exception { + public void testUsageWithSpecificImage() throws Exception { try ( // constructorWithVersion { - KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE) + KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.2.1")) // } ) { kafka.start(); @@ -58,6 +57,17 @@ public void testUsageWithVersion() throws Exception { } } + + @Test + public void testUsageWithVersion() throws Exception { + try ( + KafkaContainer kafka = new KafkaContainer("5.2.1") + ) { + kafka.start(); + testKafkaFunctionality(kafka.getBootstrapServers()); + } + } + @Test public void testExternalZookeeperWithExternalNetwork() throws Exception { try ( @@ -75,7 +85,8 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); // withKafkaNetwork { - GenericContainer application = new GenericContainer("alpine").withNetwork(network) + GenericContainer application = new GenericContainer<>(DockerImageName.parse("alpine")) + .withNetwork(network) // } .withNetworkAliases("dummy") .withCommand("sleep 10000") @@ -109,8 +120,8 @@ protected void testKafkaFunctionality(String bootstrapServers) throws Exception new StringDeserializer() ); ) { - String topicName = "messages"; - consumer.subscribe(Arrays.asList(topicName)); + String topicName = "messages-" + UUID.randomUUID(); + consumer.subscribe(singletonList(topicName)); producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index a9547eec94d..7532ebe0b3d 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -4,14 +4,6 @@ import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; -import java.net.InetAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; @@ -24,6 +16,15 @@ import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.TestcontainersConfiguration; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + /** *

Container for Atlassian Labs Localstack, 'A fully functional local AWS cloud stack'.

*

{@link LocalStackContainer#withServices(Service...)} should be used to select which services @@ -35,11 +36,16 @@ @Slf4j public class LocalStackContainer extends GenericContainer { - public static final String VERSION = "0.11.2"; static final int PORT = 4566; private static final String HOSTNAME_EXTERNAL_ENV_VAR = "HOSTNAME_EXTERNAL"; private final List services = new ArrayList<>(); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("localstack/localstack"); + private static final String DEFAULT_TAG = "0.11.2"; + + @Deprecated + public static final String VERSION = DEFAULT_TAG; + /** * Whether or to assume that all APIs run on different ports (when true) or are * exposed on a single port (false). From the Localstack README: @@ -59,7 +65,7 @@ public class LocalStackContainer extends GenericContainer { */ @Deprecated public LocalStackContainer() { - this(VERSION); + this(TestcontainersConfiguration.getInstance().getLocalstackDockerImageName().withTag(DEFAULT_TAG)); } /** @@ -67,7 +73,7 @@ public LocalStackContainer() { */ @Deprecated public LocalStackContainer(String version) { - this(DockerImageName.parse(TestcontainersConfiguration.getInstance().getLocalStackImage() + ":" + version)); + this(TestcontainersConfiguration.getInstance().getLocalstackDockerImageName().withTag(version)); } /** @@ -83,6 +89,9 @@ public LocalStackContainer(final DockerImageName dockerImageName) { */ public LocalStackContainer(final DockerImageName dockerImageName, boolean useLegacyMode) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + this.legacyMode = useLegacyMode; withFileSystemBind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), "/var/run/docker.sock"); diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index e137c186209..b43a5f237e5 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -9,10 +9,16 @@ */ public class MariaDBContainer> extends JdbcDatabaseContainer { - public static final String NAME = "mariadb"; - public static final String IMAGE = "mariadb"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mariadb"); + + @Deprecated public static final String DEFAULT_TAG = "10.3.6"; + public static final String NAME = "mariadb"; + + @Deprecated + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); + static final String DEFAULT_USER = "test"; static final String DEFAULT_PASSWORD = "test"; @@ -29,19 +35,18 @@ public class MariaDBContainer> extends JdbcD */ @Deprecated public MariaDBContainer() { - this(IMAGE + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link MariaDBContainer(DockerImageName)} instead - */ - @Deprecated public MariaDBContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public MariaDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + addExposedPort(MARIADB_PORT); } diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index 2aa33931d07..451a4710b20 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -6,7 +6,11 @@ @Slf4j public class MockServerContainer extends GenericContainer { - public static final String VERSION = "5.5.4"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("jamesdbloom/mockserver"); + private static final String DEFAULT_TAG = "mockserver-5.5.4"; + + @Deprecated + public static final String VERSION = DEFAULT_TAG; public static final int PORT = 1080; @@ -15,7 +19,7 @@ public class MockServerContainer extends GenericContainer { */ @Deprecated public MockServerContainer() { - this(VERSION); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** @@ -23,11 +27,14 @@ public MockServerContainer() { */ @Deprecated public MockServerContainer(String version) { - this(DockerImageName.parse("jamesdbloom/mockserver:mockserver-" + version)); + this(DEFAULT_IMAGE_NAME.withTag("mockserver-" + version)); } public MockServerContainer(DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withCommand("-logLevel INFO -serverPort " + PORT); addExposedPorts(PORT); } diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 1527b3924db..200b3aa0820 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -16,10 +16,12 @@ */ @Slf4j public class MongoDBContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mongo"); + private static final String DEFAULT_TAG = "4.0.10"; private static final int CONTAINER_EXIT_CODE_OK = 0; private static final int MONGODB_INTERNAL_PORT = 27017; private static final int AWAIT_INIT_REPLICA_SET_ATTEMPTS = 60; - private static final String MONGODB_VERSION_DEFAULT = "4.0.10"; private static final String MONGODB_DATABASE_NAME_DEFAULT = "test"; /** @@ -27,19 +29,18 @@ public class MongoDBContainer extends GenericContainer { */ @Deprecated public MongoDBContainer() { - this("mongo:" + MONGODB_VERSION_DEFAULT); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link MongoDBContainer(DockerImageName)} instead - */ - @Deprecated public MongoDBContainer(@NonNull final String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public MongoDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(MONGODB_INTERNAL_PORT); withCommand("--replSet", "docker-rs"); waitingFor( diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java index d72ab8e8419..fe7ada669bd 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainerProvider.java @@ -21,6 +21,7 @@ public boolean supports(ConnectionFactoryOptions options) { @Override public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) { + // TODO work out how best to do this if these constants become private String image = MSSQLServerContainer.IMAGE + ":" + options.getRequiredValue(IMAGE_TAG_OPTION); MSSQLServerContainer container = new MSSQLServerContainer<>(image); diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index 0a6d8149e34..a20c60fd2dc 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -11,10 +11,14 @@ */ public class MSSQLServerContainer> extends JdbcDatabaseContainer { - public static final String NAME = "sqlserver"; - public static final String IMAGE = "mcr.microsoft.com/mssql/server"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mcr.microsoft.com/mssql/server"); + @Deprecated public static final String DEFAULT_TAG = "2017-CU12"; + public static final String NAME = "sqlserver"; + + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); + public static final Integer MS_SQL_SERVER_PORT = 1433; static final String DEFAULT_USER = "SA"; @@ -38,19 +42,18 @@ public class MSSQLServerContainer> exten */ @Deprecated public MSSQLServerContainer() { - this(IMAGE + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link MSSQLServerContainer(DockerImageName)} instead - */ - @Deprecated public MSSQLServerContainer(final String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public MSSQLServerContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); addExposedPort(MS_SQL_SERVER_PORT); diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 35321db5d72..1dc235e6536 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -12,9 +12,15 @@ public class MySQLContainer> extends JdbcDatabaseContainer { public static final String NAME = "mysql"; - public static final String IMAGE = "mysql"; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mysql"); + + @Deprecated public static final String DEFAULT_TAG = "5.7.22"; + @Deprecated + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); + static final String DEFAULT_USER = "test"; static final String DEFAULT_PASSWORD = "test"; @@ -31,19 +37,18 @@ public class MySQLContainer> extends JdbcDatab */ @Deprecated public MySQLContainer() { - this(IMAGE + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link MySQLContainer(DockerImageName)} instead - */ - @Deprecated public MySQLContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public MySQLContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + addExposedPort(MYSQL_PORT); } diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index 5d4212ccacd..e93a840302a 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -1,5 +1,11 @@ package org.testcontainers.containers; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.stream.Collectors.toSet; + +import java.time.Duration; +import java.util.Set; +import java.util.stream.Stream; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; @@ -8,13 +14,6 @@ import org.testcontainers.utility.LicenseAcceptance; import org.testcontainers.utility.MountableFile; -import java.time.Duration; -import java.util.Set; -import java.util.stream.Stream; - -import static java.net.HttpURLConnection.HTTP_OK; -import static java.util.stream.Collectors.toSet; - /** * Testcontainer for Neo4j. * @@ -26,14 +25,13 @@ public class Neo4jContainer> extends GenericContaine /** * The image defaults to the official Neo4j image: Neo4j. */ - private static final String DEFAULT_IMAGE_NAME = "neo4j"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("neo4j"); /** * The default tag (version) to use. */ private static final String DEFAULT_TAG = "3.5.0"; - - private static final String DOCKER_IMAGE_NAME = DEFAULT_IMAGE_NAME + ":" + DEFAULT_TAG; + private static final String ENTERPRISE_TAG = DEFAULT_TAG + "-enterprise"; /** * Default port for the binary Bolt protocol. @@ -57,33 +55,41 @@ public class Neo4jContainer> extends GenericContaine private static final String AUTH_FORMAT = "neo4j/%s"; - private String adminPassword = DEFAULT_ADMIN_PASSWORD; + private final boolean standardImage; - private boolean standardImage = false; + private String adminPassword = DEFAULT_ADMIN_PASSWORD; /** - * Creates a Testcontainer using the official Neo4j docker image. + * Creates a Neo4jContainer using the official Neo4j docker image. * @deprecated use {@link Neo4jContainer(DockerImageName)} instead */ @Deprecated public Neo4jContainer() { - this(DOCKER_IMAGE_NAME); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** - * Creates a Testcontainer using a specific docker image. + * Creates a Neo4jContainer using a specific docker image. * * @param dockerImageName The docker image to use. - * @deprecated use {@link Neo4jContainer(DockerImageName)} instead */ - @Deprecated public Neo4jContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } + /** + * Creates a Neo4jContainer using a specific docker image. + * + * @param dockerImageName The docker image to use. + */ public Neo4jContainer(final DockerImageName dockerImageName) { super(dockerImageName); + this.standardImage = dockerImageName.getUnversionedPart() + .equals(DEFAULT_IMAGE_NAME.getUnversionedPart()); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + WaitStrategy waitForBolt = new LogMessageWaitStrategy() .withRegEx(String.format(".*Bolt enabled on 0\\.0\\.0\\.0:%d\\.\n", DEFAULT_BOLT_PORT)); WaitStrategy waitForHttp = new HttpWaitStrategy() @@ -96,10 +102,6 @@ public Neo4jContainer(final DockerImageName dockerImageName) { .withStartupTimeout(Duration.ofMinutes(2)); addExposedPorts(DEFAULT_BOLT_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); - - if (dockerImageName.getUnversionedPart().equals(DEFAULT_IMAGE_NAME)) { - this.standardImage = true; - } } @Override @@ -149,13 +151,13 @@ public String getHttpsUrl() { * @return This container. */ public S withEnterpriseEdition() { - if (!standardImage) { throw new IllegalStateException( - String.format("Cannot use enterprise version with alternative image %s.", getDockerImageName())); + String.format("Cannot use enterprise version with alternative image %s.", + getDockerImageName())); } - setDockerImageName(DOCKER_IMAGE_NAME + "-enterprise"); + setDockerImageName(DEFAULT_IMAGE_NAME.withTag(ENTERPRISE_TAG).asCanonicalNameString()); LicenseAcceptance.assertLicenseAccepted(getDockerImageName()); addEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes"); diff --git a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java index 75a4571b68e..296d82b7997 100644 --- a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java +++ b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java @@ -15,28 +15,28 @@ public class NginxContainer> extends GenericContainer implements LinkableContainer { private static final int NGINX_DEFAULT_PORT = 80; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("nginx"); + private static final String DEFAULT_TAG = "1.9.4"; /** * @deprecated use {@link NginxContainer(DockerImageName)} instead */ @Deprecated public NginxContainer() { - this("nginx:1.9.4"); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link NginxContainer(DockerImageName)} instead - */ - @Deprecated public NginxContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); - - addExposedPort(NGINX_DEFAULT_PORT); - setCommand("nginx", "-g", "daemon off;"); } public NginxContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + addExposedPort(NGINX_DEFAULT_PORT); + setCommand("nginx", "-g", "daemon off;"); } @NotNull diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index 8406d8275fb..b5700c1e84e 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -41,10 +41,6 @@ public OracleContainer() { this(resolveImageName()); } - /** - * @deprecated use {@link OracleContainer(DockerImageName)} instead - */ - @Deprecated public OracleContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } diff --git a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java index 797f73f7159..f6ce060b6ec 100644 --- a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java +++ b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java @@ -29,9 +29,8 @@ public class OrientDBContainer extends GenericContainer { private static final Logger LOGGER = LoggerFactory.getLogger(OrientDBContainer.class); - private static final String DEFAULT_IMAGE_NAME = "orientdb"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("orientdb"); private static final String DEFAULT_TAG = "3.0.24-tp3"; - private static final String DOCKER_IMAGE_NAME = DEFAULT_IMAGE_NAME + ":" + DEFAULT_TAG; private static final String DEFAULT_USERNAME = "admin"; private static final String DEFAULT_PASSWORD = "admin"; @@ -54,13 +53,9 @@ public class OrientDBContainer extends GenericContainer { */ @Deprecated public OrientDBContainer() { - this(DOCKER_IMAGE_NAME); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link OrientDBContainer(DockerImageName)} instead - */ - @Deprecated public OrientDBContainer(@NonNull String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } @@ -68,6 +63,8 @@ public OrientDBContainer(@NonNull String dockerImageName) { public OrientDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + serverPassword = DEFAULT_SERVER_PASSWORD; databaseName = DEFAULT_DATABASE_NAME; diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java index 9e59787837b..76c213f0931 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java @@ -9,8 +9,8 @@ public class PostgisContainerProvider extends JdbcDatabaseContainerProvider { private static final String NAME = "postgis"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("postgis/postgis").asCompatibleSubstituteFor("postgres"); private static final String DEFAULT_TAG = "12-3.0"; - private static final String DEFAULT_IMAGE = "postgis/postgis"; public static final String USER_PARAM = "user"; public static final String PASSWORD_PARAM = "password"; @@ -27,7 +27,7 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new PostgreSQLContainer(DockerImageName.parse(DEFAULT_IMAGE).withTag(DEFAULT_TAG)); + return new PostgreSQLContainer<>(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } @Override diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index b1ddb2a26ee..5a4abe6d0ee 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -16,7 +16,9 @@ public class PostgreSQLContainer> extends JdbcDatabaseContainer { public static final String NAME = "postgresql"; public static final String IMAGE = "postgres"; + public static final String DEFAULT_TAG = "9.6.12"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("postgres"); public static final Integer POSTGRESQL_PORT = 5432; @@ -37,19 +39,18 @@ public class PostgreSQLContainer> extends */ @Deprecated public PostgreSQLContainer() { - this(IMAGE + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link PostgreSQLContainer(DockerImageName)} instead - */ - @Deprecated public PostgreSQLContainer(final String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public PostgreSQLContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*database system is ready to accept connections.*\\s") .withTimes(2) diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index 1c8c03ce4de..e4934693d14 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -16,6 +16,7 @@ public class PrestoContainer> extends JdbcDatabaseContainer { public static final String NAME = "presto"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("prestosql/presto"); public static final String IMAGE = "prestosql/presto"; public static final String DEFAULT_TAG = "329"; @@ -29,19 +30,18 @@ public class PrestoContainer> extends JdbcDat */ @Deprecated public PrestoContainer() { - this(IMAGE + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link PrestoContainer(DockerImageName)} instead - */ - @Deprecated public PrestoContainer(final String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public PrestoContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*======== SERVER STARTED ========.*") .withStartupTimeout(Duration.of(60, SECONDS)); diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 4d30d947113..bceff8927d7 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -14,8 +14,9 @@ public class PulsarContainer extends GenericContainer { public static final int BROKER_HTTP_PORT = 8080; public static final String METRICS_ENDPOINT = "/metrics"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("apachepulsar/pulsar"); @Deprecated - private static final String DEFAULT_PULSAR_VERSION = "2.2.0"; + private static final String DEFAULT_TAG = "2.2.0"; private boolean functionsWorkerEnabled = false; @@ -24,7 +25,7 @@ public class PulsarContainer extends GenericContainer { */ @Deprecated public PulsarContainer() { - this(DEFAULT_PULSAR_VERSION); + this(TestcontainersConfiguration.getInstance().getPulsarDockerImageName().withTag(DEFAULT_TAG)); } /** @@ -37,6 +38,9 @@ public PulsarContainer(String pulsarVersion) { public PulsarContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DockerImageName.parse("apachepulsar/pulsar")); + withExposedPorts(BROKER_PORT, BROKER_HTTP_PORT); withCommand("/pulsar/bin/pulsar", "standalone", "--no-functions-worker", "-nss"); waitingFor(Wait.forHttp(METRICS_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index a3b6134b29c..edbffcf3174 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -28,7 +28,7 @@ public class RabbitMQContainer extends GenericContainer { /** * The image defaults to the official RabbitmQ image: RabbitMQ. */ - private static final String DEFAULT_IMAGE_NAME = "rabbitmq"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("rabbitmq"); private static final String DEFAULT_TAG = "3.7.25-management-alpine"; private static final int DEFAULT_AMQP_PORT = 5672; @@ -41,21 +41,19 @@ public class RabbitMQContainer extends GenericContainer { private final List> values = new ArrayList<>(); /** - * Creates a Testcontainer using the official RabbitMQ docker image. + * Creates a RabbitMQ container using the official RabbitMQ docker image. * @deprecated use {@link RabbitMQContainer(DockerImageName)} instead */ @Deprecated public RabbitMQContainer() { - this(DEFAULT_IMAGE_NAME + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** - * Creates a Testcontainer using a specific docker image. + * Creates a RabbitMQ container using a specific docker image. * * @param dockerImageName The docker image to use. - * @deprecated use {@link RabbitMQContainer(DockerImageName)} instead */ - @Deprecated public RabbitMQContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } @@ -63,6 +61,8 @@ public RabbitMQContainer(String dockerImageName) { public RabbitMQContainer(final DockerImageName dockerImageName) { super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + addExposedPorts(DEFAULT_AMQP_PORT, DEFAULT_AMQPS_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); this.waitStrategy = Wait. diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index f1cedab76ad..d60d9191748 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -1,10 +1,21 @@ package org.testcontainers.containers; +import static java.time.temporal.ChronoUnit.SECONDS; + import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.AccessMode; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Volume; import com.google.common.collect.ImmutableSet; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.time.Duration; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.openqa.selenium.Capabilities; @@ -25,18 +36,6 @@ import org.testcontainers.lifecycle.TestLifecycleAware; import org.testcontainers.utility.DockerImageName; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.file.Files; -import java.time.Duration; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import static java.time.temporal.ChronoUnit.SECONDS; - /** * A chrome/firefox/custom container based on SeleniumHQ's standalone container sets. *

@@ -44,8 +43,14 @@ */ public class BrowserWebDriverContainer> extends GenericContainer implements LinkableContainer, TestLifecycleAware { - private static final String CHROME_IMAGE = "selenium/standalone-chrome-debug:%s"; - private static final String FIREFOX_IMAGE = "selenium/standalone-firefox-debug:%s"; + private static final DockerImageName CHROME_IMAGE = DockerImageName.parse("selenium/standalone-chrome-debug"); + private static final DockerImageName FIREFOX_IMAGE = DockerImageName.parse("selenium/standalone-firefox-debug"); + private static final DockerImageName[] COMPATIBLE_IMAGES = new DockerImageName[] { + CHROME_IMAGE, + FIREFOX_IMAGE, + DockerImageName.parse("selenium/standalone-chrome"), + DockerImageName.parse("selenium/standalone-firefox") + }; private static final String DEFAULT_PASSWORD = "secret"; private static final int SELENIUM_PORT = 4444; @@ -56,7 +61,7 @@ public class BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>(imageName) .withCapabilities(new ChromeOptions())) { chrome.start(); diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java index bbc3b4db7a0..9a15c6b466d 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java @@ -8,7 +8,8 @@ public class SpecificImageNameWebDriverContainerTest extends BaseWebDriverContainerTest { - private static final DockerImageName FIREFOX_IMAGE = DockerImageName.parse("selenium/standalone-firefox:2.53.1-beryllium"); + private static final DockerImageName FIREFOX_IMAGE = DockerImageName + .parse("selenium/standalone-firefox:2.53.1-beryllium"); @Rule public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer<>(FIREFOX_IMAGE) diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java index aeadb664089..4bc2f19ec86 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java @@ -18,7 +18,12 @@ */ public class SolrContainer extends GenericContainer { - public static final String IMAGE = "solr"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("solr"); + + @Deprecated + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); + + @Deprecated public static final String DEFAULT_TAG = "8.3.0"; public static final Integer ZOOKEEPER_PORT = 9983; @@ -31,19 +36,21 @@ public class SolrContainer extends GenericContainer { */ @Deprecated public SolrContainer() { - this(IMAGE + ":" + DEFAULT_TAG); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** * @deprecated use {@link SolrContainer(DockerImageName)} instead */ - @Deprecated public SolrContainer(final String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public SolrContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*o\\.e\\.j\\.s\\.Server Started.*") .withStartupTimeout(Duration.of(60, SECONDS)); diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index b01d031cc5b..e6c143fa358 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -21,7 +21,8 @@ */ public class ToxiproxyContainer extends GenericContainer { - private static final String IMAGE_NAME = "shopify/toxiproxy:2.1.0"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("shopify/toxiproxy"); + private static final String DEFAULT_TAG = "2.1.0"; private static final int TOXIPROXY_CONTROL_PORT = 8474; private static final int FIRST_PROXIED_PORT = 8666; private static final int LAST_PROXIED_PORT = 8666 + 31; @@ -35,19 +36,18 @@ public class ToxiproxyContainer extends GenericContainer { */ @Deprecated public ToxiproxyContainer() { - this(IMAGE_NAME); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link ToxiproxyContainer(DockerImageName)} instead - */ - @Deprecated public ToxiproxyContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public ToxiproxyContainer(final DockerImageName dockerImageName) { super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + addExposedPorts(TOXIPROXY_CONTROL_PORT); setWaitStrategy(new HttpWaitStrategy().forPath("/version").forPort(TOXIPROXY_CONTROL_PORT)); diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java index 1532f463f37..b0c8a2a40e3 100644 --- a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java +++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java @@ -23,6 +23,9 @@ */ public class VaultContainer> extends GenericContainer { + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("vault"); + private static final String DEFAULT_TAG = "1.1.3"; + private static final int VAULT_PORT = 8200; private Map> secretsMap = new HashMap<>(); @@ -34,13 +37,9 @@ public class VaultContainer> extends GenericCo */ @Deprecated public VaultContainer() { - this("vault:1.1.3"); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } - /** - * @deprecated use {@link VaultContainer(DockerImageName)} instead - */ - @Deprecated public VaultContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } @@ -48,6 +47,8 @@ public VaultContainer(String dockerImageName) { public VaultContainer(final DockerImageName dockerImageName) { super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + // Use the vault healthcheck endpoint to check for readiness, per https://www.vaultproject.io/api/system/health.html setWaitStrategy(Wait.forHttp("/v1/sys/health").forStatusCode(200)); From 2cd32fd637d1846fba187cc11fd1ad6ef69c44dc Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 1 Oct 2020 10:53:41 +0200 Subject: [PATCH 0998/4969] Add support for MongoDB 4.4 (#3083) Make LogMessageWaitStrategy in MongoDBContainer compatible Fixes #3077 --- .../org/testcontainers/containers/MongoDBContainer.java | 2 +- .../testcontainers/containers/MongoDBContainerTest.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 200b3aa0820..5fd2451480b 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -44,7 +44,7 @@ public MongoDBContainer(final DockerImageName dockerImageName) { withExposedPorts(MONGODB_INTERNAL_PORT); withCommand("--replSet", "docker-rs"); waitingFor( - Wait.forLogMessage(".*waiting for connections on port.*", 1) + Wait.forLogMessage("(?i).*waiting for connections.*", 1) ); } diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index d637cb07f2d..b18e7f15a01 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -73,4 +73,13 @@ public void shouldExecuteTransactions() { } } } + + @Test + public void supportsMongoDB_4_4() { + try ( + final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.4")) + ) { + mongoDBContainer.start(); + } + } } From 17b4f6c136f6f2c7dc223bad407221f62a8f0088 Mon Sep 17 00:00:00 2001 From: Rishu Mehrotra Date: Sat, 3 Oct 2020 16:00:03 +0530 Subject: [PATCH 0999/4969] Don't display a stack trace in the logs when .testcontainers.properties is not found (#2293) Co-authored-by: Richard North --- .../testcontainers/utility/TestcontainersConfiguration.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 521a7519c2a..5b89140fd61 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -9,6 +9,7 @@ import lombok.SneakyThrows; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.exception.ExceptionUtils; import org.testcontainers.UnstableAPI; import java.io.File; @@ -232,9 +233,9 @@ private static Properties readProperties(URL url) { try (InputStream inputStream = url.openStream()) { properties.load(inputStream); } catch (FileNotFoundException e) { - log.trace("Testcontainers config override was found on {} but the file was not found", url, e); + log.warn("Testcontainers config override was found on {} but the file was not found. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); } catch (IOException e) { - log.warn("Testcontainers config override was found on {} but could not be loaded", url, e); + log.warn("Testcontainers config override was found on {} but could not be loaded. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); } return properties; } From ae46d1049230dbc8797b077e4d475a11bfeab6ac Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 7 Oct 2020 12:58:47 +0200 Subject: [PATCH 1000/4969] Support Confluent Platform 6 in Kafka (#3293) * Support Confluent Platform 6 in Kafka * remove `KafkaContainer#startZookeeper` --- .../containers/KafkaContainer.java | 26 +++++-------------- .../containers/KafkaContainerTest.java | 10 +++++++ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 4086cd4e2e4..ae44e4803a9 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -1,6 +1,5 @@ package org.testcontainers.containers; -import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.command.InspectContainerResponse; import lombok.SneakyThrows; import org.testcontainers.images.builder.Transferable; @@ -8,7 +7,6 @@ import org.testcontainers.utility.TestcontainersConfiguration; import java.nio.charset.StandardCharsets; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -108,14 +106,18 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole return; } + String command = "#!/bin/bash\n"; final String zookeeperConnect; if (externalZookeeperConnect != null) { zookeeperConnect = externalZookeeperConnect; } else { - zookeeperConnect = startZookeeper(); + zookeeperConnect = "localhost:" + ZOOKEEPER_PORT; + command += "echo 'clientPort=" + ZOOKEEPER_PORT + "' > zookeeper.properties\n"; + command += "echo 'dataDir=/var/lib/zookeeper/data' >> zookeeper.properties\n"; + command += "echo 'dataLogDir=/var/lib/zookeeper/log' >> zookeeper.properties\n"; + command += "zookeeper-server-start zookeeper.properties &\n"; } - String command = "#!/bin/bash \n"; command += "export KAFKA_ZOOKEEPER_CONNECT='" + zookeeperConnect + "'\n"; command += "export KAFKA_ADVERTISED_LISTENERS='" + Stream .concat( @@ -130,22 +132,8 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole command += "/etc/confluent/docker/launch \n"; copyFileToContainer( - Transferable.of(command.getBytes(StandardCharsets.UTF_8), 700), + Transferable.of(command.getBytes(StandardCharsets.UTF_8), 0777), STARTER_SCRIPT ); } - - @SneakyThrows(InterruptedException.class) - private String startZookeeper() { - ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(getContainerId()) - .withCmd("sh", "-c", "" + - "printf 'clientPort=" + ZOOKEEPER_PORT + "\ndataDir=/var/lib/zookeeper/data\ndataLogDir=/var/lib/zookeeper/log' > /zookeeper.properties\n" + - "zookeeper-server-start /zookeeper.properties\n" - ) - .exec(); - - dockerClient.execStartCmd(execCreateCmdResponse.getId()).start().awaitStarted(10, TimeUnit.SECONDS); - - return "localhost:" + ZOOKEEPER_PORT; - } } diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 6a669b2f60d..08b9fb6f856 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -99,6 +99,16 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { } } + @Test + public void testConfluentPlatformVersion6() throws Exception { + try ( + KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.0.0")) + ) { + kafka.start(); + testKafkaFunctionality(kafka.getBootstrapServers()); + } + } + protected void testKafkaFunctionality(String bootstrapServers) throws Exception { try ( KafkaProducer producer = new KafkaProducer<>( From 3f1cddbb33a2f75f8299a18bc794446768629f29 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 11 Oct 2020 07:05:52 +0100 Subject: [PATCH 1001/4969] When an image version is not specified, use `latest` as the default tag (#3313) --- .../testcontainers/utility/Versioning.java | 4 +-- .../dockerclient/AmbiguousImagePullTest.java | 34 +++++++++++++++++++ .../utility/DockerImageNameTest.java | 4 +-- 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java diff --git a/core/src/main/java/org/testcontainers/utility/Versioning.java b/core/src/main/java/org/testcontainers/utility/Versioning.java index 8944b3f0ba6..84dcf46274e 100644 --- a/core/src/main/java/org/testcontainers/utility/Versioning.java +++ b/core/src/main/java/org/testcontainers/utility/Versioning.java @@ -24,12 +24,12 @@ public boolean isValid() { @Override public String getSeparator() { - return ""; + return ":"; } @Override public String toString() { - return ""; + return "latest"; } @Override diff --git a/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java new file mode 100644 index 00000000000..5d2c42ed1b2 --- /dev/null +++ b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java @@ -0,0 +1,34 @@ +package org.testcontainers.dockerclient; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Image; +import org.junit.Test; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.utility.DockerImageName; + +import java.util.List; + +public class AmbiguousImagePullTest { + + @Test(timeout = 30_000) + public void testNotUsingParse() { + DockerClient client = DockerClientFactory.instance().client(); + List alpineImages = client.listImagesCmd() + .withImageNameFilter("alpine:latest") + .exec(); + for (Image alpineImage : alpineImages) { + client.removeImageCmd(alpineImage.getId()).exec(); + } + + try ( + final GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine")) + .withCommand("/bin/sh", "-c", "sleep 0") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + // do nothing other than start and stop + } + } +} diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index 34575f2b4b9..e06407fbf56 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -112,7 +112,7 @@ public void testParsing() { canonicalName = unversionedPart + versionSeparator + version; } else { combined = unversionedPart; - canonicalName = unversionedPart; + canonicalName = unversionedPart + ":latest"; } VisibleAssertions.context("For " + combined); @@ -124,7 +124,7 @@ public void testParsing() { if (version != null) { assertEquals(combined + " has version part: " + version, version, imageName.getVersionPart()); } else { - assertEquals(combined + " has no version specified", "", imageName.getVersionPart()); + assertEquals(combined + " has automatic 'latest' version specified", "latest", imageName.getVersionPart()); } assertEquals(combined + " has canonical name: " + canonicalName, canonicalName, imageName.asCanonicalNameString()); From bc7aaafa75265049c700583b5230dd639b45a30e Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Sun, 11 Oct 2020 19:19:13 +0100 Subject: [PATCH 1002/4969] Add workflow for Update Gradle Wrapper Action. (#3297) Co-authored-by: Richard North --- .github/workflows/update-gradle-wrapper.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/update-gradle-wrapper.yml diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml new file mode 100644 index 00000000000..f3a01949324 --- /dev/null +++ b/.github/workflows/update-gradle-wrapper.yml @@ -0,0 +1,20 @@ +name: Update Gradle Wrapper + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + update-gradle-wrapper: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Update Gradle Wrapper + uses: gradle-update/update-gradle-wrapper-action@74a035c + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + labels: dependencies + + - uses: gradle/wrapper-validation-action@e2c57ac From edd2a1c44d3e7f9bd9d4a21dd885da394023a0f5 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 12 Oct 2020 17:06:28 +0100 Subject: [PATCH 1003/4969] Always continue on error for examples CI (#3339) --- .github/workflows/ci-examples.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index d81a4ffb509..6f8e4868a97 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -20,6 +20,7 @@ jobs: java-version: '1.8' - name: Cache Gradle Home files uses: actions/cache@v1 + continue-on-error: true with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-examples-${{ hashFiles('**/*.gradle') }} @@ -48,6 +49,7 @@ jobs: java-version: '1.8' - name: Cache Gradle Home files uses: actions/cache@v1 + continue-on-error: true with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} From 5cc47ef9d33028477cc5f678fbeb8ef1d5ddcb74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:10:23 +0100 Subject: [PATCH 1004/4969] Bump snakeyaml from 1.25 to 1.27 in /core (#3252) Bumps [snakeyaml](https://bitbucket.org/asomov/snakeyaml) from 1.25 to 1.27. - [Commits](https://bitbucket.org/asomov/snakeyaml/branches/compare/snakeyaml-1.27..snakeyaml-1.25) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 37595c18e7c..222c04384fb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -192,7 +192,7 @@ dependencies { compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.5' - shaded "org.yaml:snakeyaml:1.25" + shaded "org.yaml:snakeyaml:1.27" shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From 7d1734c2e3bb539870ee36524dcdec6cf2bc98e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:12:00 +0100 Subject: [PATCH 1005/4969] Bump lombok from 1.18.12 to 1.18.14 in /examples (#3322) Bumps [lombok](https://github.com/rzwitserloot/lombok) from 1.18.12 to 1.18.14. - [Release notes](https://github.com/rzwitserloot/lombok/releases) - [Changelog](https://github.com/rzwitserloot/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/rzwitserloot/lombok/compare/v1.18.12...v1.18.14) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/disque-job-queue/build.gradle | 4 ++-- examples/solr-container/build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index fb8413bdec8..c5e191f4f94 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,8 +7,8 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.12" - annotationProcessor "org.projectlombok:lombok:1.18.10" + compileOnly "org.projectlombok:lombok:1.18.14" + annotationProcessor "org.projectlombok:lombok:1.18.14" implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 52fa54f1fc5..f72c3376cac 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.10" + compileOnly "org.projectlombok:lombok:1.18.14" annotationProcessor "org.projectlombok:lombok:1.18.10" implementation 'org.apache.solr:solr-solrj:8.6.2' From aeec90a4529b7ccbe507592f732d7c8c3fba71be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:12:12 +0100 Subject: [PATCH 1006/4969] Bump r2dbc-mariadb from 0.8.3-beta1 to 0.8.4-rc in /modules/mariadb (#3300) Bumps [r2dbc-mariadb](https://github.com/mariadb-corporation/mariadb-connector-r2dbc) from 0.8.3-beta1 to 0.8.4-rc. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 94164468855..19f1adba2cc 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'org.mariadb:r2dbc-mariadb:0.8.3-beta1' + compileOnly 'org.mariadb:r2dbc-mariadb:0.8.4-rc' testCompile project(':jdbc-test') testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.2' From 413965a9711621473137e107871eb624ed19c450 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:12:18 +0100 Subject: [PATCH 1007/4969] Bump testng from 7.2.0 to 7.3.0 in /examples (#3068) Bumps [testng](https://github.com/cbeust/testng) from 7.2.0 to 7.3.0. - [Release notes](https://github.com/cbeust/testng/releases) - [Changelog](https://github.com/cbeust/testng/blob/master/CHANGES.txt) - [Commits](https://github.com/cbeust/testng/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/redis-backed-cache-testng/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 62f7de6dcf8..6ef351764f5 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' - testImplementation 'org.testng:testng:7.2.0' + testImplementation 'org.testng:testng:7.3.0' } test { From 1845cfb8ffea55e29ea3c07435367309efe8ce7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:12:42 +0100 Subject: [PATCH 1008/4969] Bump assertj-core from 3.17.1 to 3.17.2 in /core (#3251) Bumps [assertj-core](https://github.com/joel-costigliola/assertj-core) from 3.17.1 to 3.17.2. - [Release notes](https://github.com/joel-costigliola/assertj-core/releases) - [Commits](https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.17.1...assertj-core-3.17.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 222c04384fb..37c42577942 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -211,7 +211,7 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.17.1' + testCompile 'org.assertj:assertj-core:3.17.2' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" From 05a30f6561509a3c354a14c0655fe939458d3da9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:13:35 +0100 Subject: [PATCH 1009/4969] Bump aws-java-sdk-dynamodb from 1.11.865 to 1.11.880 in /modules/dynalite (#3332) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.865 to 1.11.880. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.865...1.11.880) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 0b2e334c633..fe8fb883839 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.865' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.865' } From 8b17881508e57b8b807d3a7ca456d28aa6728b66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:16:44 +0100 Subject: [PATCH 1010/4969] Bump mockito-core from 3.5.11 to 3.5.13 in /core (#3275) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 37c42577942..b08e54c9b97 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -205,7 +205,7 @@ dependencies { testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' - testCompile ('org.mockito:mockito-core:3.5.11') { + testCompile ('org.mockito:mockito-core:3.5.13') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 66e5f8a6b018433e17d9389ac9f8686bf87c1c4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 17:17:10 +0100 Subject: [PATCH 1011/4969] Bump elasticsearch-rest-client from 7.9.1 to 7.9.2 in /modules/elasticsearch (#3276) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.9.1 to 7.9.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.9.1...v7.9.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 44a5cca5963..e6de1daa7ab 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.9.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.9.2" testCompile "org.elasticsearch.client:transport:6.7.1" } From 759a441f370ab589b36099ee0a7c2952bc0d139c Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 12 Oct 2020 19:33:35 +0100 Subject: [PATCH 1012/4969] Increase memory limits used in example (#3340) For improved test stability --- .../generic/src/test/java/generic/CmdModifierTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index f49e6a26565..73338ba38ee 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -19,8 +19,8 @@ public class CmdModifierTest { // } // memory { - private long memoryInBytes = 8 * 1024 * 1024; - private long memorySwapInBytes = 12 * 1024 * 1024; + private long memoryInBytes = 32 * 1024 * 1024; + private long memorySwapInBytes = 64 * 1024 * 1024; @Rule public GenericContainer memoryLimitedRedis = new GenericContainer<>(DockerImageName.parse("redis:3.0.2")) @@ -40,6 +40,6 @@ public void testHostnameModified() throws IOException, InterruptedException { @Test public void testMemoryLimitModified() throws IOException, InterruptedException { final Container.ExecResult execResult = memoryLimitedRedis.execInContainer("cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"); - assertEquals("8388608", execResult.getStdout().trim()); + assertEquals(String.valueOf(memoryInBytes), execResult.getStdout().trim()); } } From 831b63918e671c9bfde508c064699ca2a1dd91a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:18:07 +0100 Subject: [PATCH 1013/4969] Bump mockito-core from 3.5.11 to 3.5.13 in /modules/junit-jupiter (#3283) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index dbf54b8d291..7b0c0cb82f9 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testCompile ('org.mockito:mockito-core:3.5.11') { + testCompile ('org.mockito:mockito-core:3.5.13') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.17.2' From 61c4119be926e4a8f19b873de10b2815b3530cbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:19:11 +0100 Subject: [PATCH 1014/4969] Bump tomcat-jdbc from 9.0.37 to 9.0.39 in /modules/jdbc-test (#3338) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index d8df69b094f..ec57ddcea41 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -15,7 +15,7 @@ dependencies { } compile 'commons-dbutils:commons-dbutils:1.7' - compile 'org.apache.tomcat:tomcat-jdbc:9.0.37' + compile 'org.apache.tomcat:tomcat-jdbc:9.0.39' compile 'org.vibur:vibur-dbcp:25.0' compile 'mysql:mysql-connector-java:8.0.21' } From 0fc92bda50cff021ff4e78bb129a51cb0097c3e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:19:22 +0100 Subject: [PATCH 1015/4969] Bump junit from 4.13 to 4.13.1 in /examples (#3328) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/mongodb-container/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index c09cb033489..57b578a1607 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -8,6 +8,6 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' - testImplementation 'junit:junit:4.13' + testImplementation 'junit:junit:4.13.1' testCompileClasspath 'org.jetbrains:annotations:20.1.0' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 258c98fb107..b0b6865aea7 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -12,6 +12,6 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'junit:junit:4.13' + testImplementation 'junit:junit:4.13.1' testImplementation 'ch.qos.logback:logback-classic:1.2.3' } From b2db18f097fcf134c4c6f2288ba0c7939ceee950 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:20:24 +0100 Subject: [PATCH 1016/4969] Bump mariadb-java-client from 2.6.2 to 2.7.0 in /modules/mariadb (#3278) Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.6.2 to 2.7.0. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.6.2...2.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 19f1adba2cc..e5f19eed97b 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:0.8.4-rc' testCompile project(':jdbc-test') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.6.2' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.7.0' testCompile testFixtures(project(':r2dbc')) testCompile 'org.mariadb:r2dbc-mariadb:0.8.3-beta1' From 1261fee751b570ba231ae45854801facb9bcc1b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:20:52 +0100 Subject: [PATCH 1017/4969] Bump solr-solrj from 8.6.2 to 8.6.3 in /examples (#3321) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index f72c3376cac..5a8973cab27 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.14" annotationProcessor "org.projectlombok:lombok:1.18.10" - implementation 'org.apache.solr:solr-solrj:8.6.2' + implementation 'org.apache.solr:solr-solrj:8.6.3' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From b6b828ee0606dd046bcb832333d5eeb1842a1fb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:21:05 +0100 Subject: [PATCH 1018/4969] Bump postgresql from 42.2.16 to 42.2.17 in /examples (#3323) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index eac2c59df4a..5c4c473becb 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.9.0' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.16' + testImplementation 'org.postgresql:postgresql:42.2.17' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From 0f58f36406edf917487345647996afc6cf4ba0e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:21:15 +0100 Subject: [PATCH 1019/4969] Bump postgresql from 42.2.16 to 42.2.17 in /modules/junit-jupiter (#3327) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7b0c0cb82f9..a1acce9f0f3 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'org.assertj:assertj-core:3.17.2' testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' - testRuntime 'org.postgresql:postgresql:42.2.16' + testRuntime 'org.postgresql:postgresql:42.2.17' testRuntime 'mysql:mysql-connector-java:8.0.21' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } From 8558994aa7e66585ad6249cb24fce049b6037629 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:21:32 +0100 Subject: [PATCH 1020/4969] Bump postgresql from 42.2.16 to 42.2.17 in /modules/spock (#3330) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 3d0948e9e83..8d05bdf58b6 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'org.apache.httpcomponents:httpclient:4.5.12' - testRuntime 'org.postgresql:postgresql:42.2.16' + testRuntime 'org.postgresql:postgresql:42.2.17' testRuntime 'mysql:mysql-connector-java:8.0.21' testCompileClasspath 'org.jetbrains:annotations:20.1.0' From 5b70c5860587ed3ed4073cef13d72a0d7ac4362e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:21:42 +0100 Subject: [PATCH 1021/4969] Bump tomcat-jdbc from 9.0.37 to 9.0.39 in /modules/jdbc (#3333) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 6453b49b052..2045461785e 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:20.1.0' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.37' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.39' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' } From 7681f1214c94042ae937ad010de485dd9f4229fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:21:51 +0100 Subject: [PATCH 1022/4969] Bump postgresql from 42.2.16 to 42.2.17 in /modules/postgresql (#3334) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index ea6e4a87226..aa5db7028b5 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':jdbc-test') testCompile project(':test-support') - testCompile 'org.postgresql:postgresql:42.2.16' + testCompile 'org.postgresql:postgresql:42.2.17' testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' From 304c2d702096714fba15270616a5f3c56328a560 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:21:59 +0100 Subject: [PATCH 1023/4969] Bump aws-java-sdk-sqs from 1.11.860 to 1.11.880 in /modules/localstack (#3337) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index f48b3cf71bb..8d4b9576cae 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.870' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.865' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.860' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.14.21' } From aa8e5ed0a77f48858fb3622664844d14f5068a3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 21:47:43 +0100 Subject: [PATCH 1024/4969] Bump httpclient from 4.5.12 to 4.5.13 in /modules/junit-jupiter (#3326) Bumps httpclient from 4.5.12 to 4.5.13. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index a1acce9f0f3..28f6049faf4 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,7 +8,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' - testCompile 'org.apache.httpcomponents:httpclient:4.5.12' + testCompile 'org.apache.httpcomponents:httpclient:4.5.13' testCompile ('org.mockito:mockito-core:3.5.13') { exclude(module: 'hamcrest-core') } From 98a8260bf05953a823b4a526637effa50054de0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 22:05:52 +0100 Subject: [PATCH 1025/4969] Bump httpclient from 4.5.12 to 4.5.13 in /modules/spock (#3329) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 8d05bdf58b6..86724262a29 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -13,7 +13,7 @@ dependencies { testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.5' - testCompile 'org.apache.httpcomponents:httpclient:4.5.12' + testCompile 'org.apache.httpcomponents:httpclient:4.5.13' testRuntime 'org.postgresql:postgresql:42.2.17' testRuntime 'mysql:mysql-connector-java:8.0.21' From a0942943e03fc07bfcd03fa2fa0558f32a73d789 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 22:06:12 +0100 Subject: [PATCH 1026/4969] Bump cucumber-junit from 6.7.0 to 6.8.1 in /examples (#3325) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 318ed51f24c..5a9fd6f048f 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.6.0' - testImplementation 'io.cucumber:cucumber-junit:6.7.0' + testImplementation 'io.cucumber:cucumber-junit:6.8.1' testImplementation 'org.testcontainers:selenium' } From c1e8234f737756619f6b861e94621a7546834042 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 22:15:40 +0100 Subject: [PATCH 1027/4969] Bump org.springframework.boot from 2.3.3.RELEASE to 2.3.4.RELEASE in /examples (#3247) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index eb9c2d9ce3a..2dca03f4004 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.3.RELEASE' + id 'org.springframework.boot' version '2.3.4.RELEASE' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index d74851d8eac..75907da4c0d 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.3.RELEASE' + id 'org.springframework.boot' version '2.3.4.RELEASE' } apply plugin: 'io.spring.dependency-management' From 325c8b287c7d9a6d56d15bc8c5bb5efa0c5e0d5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 08:09:54 +0100 Subject: [PATCH 1028/4969] Bump aws-java-sdk-s3 from 1.11.870 to 1.11.880 in /modules/localstack (#3336) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.870 to 1.11.880. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.870...1.11.880) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8d4b9576cae..b99ec1c54fe 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.870' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.865' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.880' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.14.21' From 4801ed82400afd53fb991649cf1f9cf6931030ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 08:48:27 +0100 Subject: [PATCH 1029/4969] Bump zt-exec from 1.10 to 1.12 in /core (#3253) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b08e54c9b97..e043313ac38 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -196,7 +196,7 @@ dependencies { shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' - shaded 'org.zeroturnaround:zt-exec:1.10', { + shaded 'org.zeroturnaround:zt-exec:1.12', { exclude(group: 'org.slf4j') } From b2b8e62d1ffbd9f8951944bb7f44f0429fa89156 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 08:48:39 +0100 Subject: [PATCH 1030/4969] Bump s3 from 2.14.21 to 2.15.7 in /modules/localstack (#3335) Bumps s3 from 2.14.21 to 2.15.7. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index b99ec1c54fe..29abca90878 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.14.21' + testCompile 'software.amazon.awssdk:s3:2.15.7' } From e4c4cfebdbbb21b2b008f86bf6995c7477c59b9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 08:48:52 +0100 Subject: [PATCH 1031/4969] Bump cucumber-java from 6.6.0 to 6.8.1 in /examples (#3324) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 6.6.0 to 6.8.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.6.0...v6.8.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 5a9fd6f048f..57104731c7e 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:6.6.0' + testImplementation 'io.cucumber:cucumber-java:6.8.1' testImplementation 'io.cucumber:cucumber-junit:6.8.1' testImplementation 'org.testcontainers:selenium' } From b0735235f0bd990665584f739726a4c4dee1b80f Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 13 Oct 2020 09:31:33 +0100 Subject: [PATCH 1032/4969] Remove GitHub Actions cache restore keys (#3342) For more specific cache matching --- .github/workflows/ci-examples.yml | 4 ---- .github/workflows/ci.yml | 4 ---- 2 files changed, 8 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 6f8e4868a97..4f91341a4a6 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -24,8 +24,6 @@ jobs: with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-examples-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle-home-testmatrix-examples- - id: set-matrix working-directory: ./examples/ env: @@ -53,8 +51,6 @@ jobs: with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check- - name: Clear existing docker image cache run: docker image prune -af - name: Build and test Examples with Gradle (${{matrix.gradle_args}}) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b5a37a3405..df38f3b8a4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,8 +23,6 @@ jobs: with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle-home-testmatrix- - id: set-matrix env: # Since we override the tests executor, @@ -51,8 +49,6 @@ jobs: with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check- - name: Clear existing docker image cache run: docker image prune -af - name: Build and test with Gradle (${{matrix.gradle_args}}) From 8ab49eec547103d5d3e4410e3fb0deef08f52336 Mon Sep 17 00:00:00 2001 From: silaev Date: Tue, 13 Oct 2020 15:36:05 +0300 Subject: [PATCH 1033/4969] Allow users to specify a MongoDB database name (#2980) Co-authored-by: Richard North --- .../containers/MongoDBContainer.java | 17 ++++++++++++++++- .../containers/MongoDBContainerTest.java | 13 +++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 5fd2451480b..662c4b575f7 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -48,7 +48,22 @@ public MongoDBContainer(final DockerImageName dockerImageName) { ); } + /** + * Gets a replica set url for the default {@value #MONGODB_DATABASE_NAME_DEFAULT} database. + * + * @return a replica set url. + */ public String getReplicaSetUrl() { + return getReplicaSetUrl(MONGODB_DATABASE_NAME_DEFAULT); + } + + /** + * Gets a replica set url for a provided databaseName. + * + * @param databaseName a database name. + * @return a replica set url. + */ + public String getReplicaSetUrl(final String databaseName) { if (!isRunning()) { throw new IllegalStateException("MongoDBContainer should be started first"); } @@ -56,7 +71,7 @@ public String getReplicaSetUrl() { "mongodb://%s:%d/%s", getContainerIpAddress(), getMappedPort(MONGODB_INTERNAL_PORT), - MONGODB_DATABASE_NAME_DEFAULT + databaseName ); } diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index b18e7f15a01..ff5243acea7 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -13,8 +13,10 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import static org.hamcrest.CoreMatchers.endsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; public class MongoDBContainerTest { @@ -82,4 +84,15 @@ public void supportsMongoDB_4_4() { mongoDBContainer.start(); } } + + @Test + public void shouldTestDatabaseName() { + try ( + final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")) + ) { + mongoDBContainer.start(); + final String databaseName = "my-db"; + assertThat(mongoDBContainer.getReplicaSetUrl(databaseName), endsWith(databaseName)); + } + } } From 0065801b4f13cd29af7904abd6a57d4525e710fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 13 Oct 2020 09:51:44 -0500 Subject: [PATCH 1034/4969] Add GCloud module for Google Cloud Datastore, Firestore, PubSub, and Spanner emulators (#2690) Co-authored-by: Richard North --- docs/modules/gcloud.md | 44 ++++++++ mkdocs.yml | 1 + modules/gcloud/build.gradle | 11 ++ .../DatastoreEmulatorContainer.java | 29 +++++ .../FirestoreEmulatorContainer.java | 30 ++++++ .../containers/PubSubEmulatorContainer.java | 30 ++++++ .../containers/SpannerEmulatorContainer.java | 28 +++++ .../DatastoreEmulatorContainerTest.java | 43 ++++++++ .../FirestoreEmulatorContainerTest.java | 49 +++++++++ .../PubSubEmulatorContainerTest.java | 102 ++++++++++++++++++ .../SpannerEmulatorContainerTest.java | 80 ++++++++++++++ 11 files changed, 447 insertions(+) create mode 100644 docs/modules/gcloud.md create mode 100644 modules/gcloud/build.gradle create mode 100644 modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java create mode 100644 modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java create mode 100644 modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java create mode 100644 modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java create mode 100644 modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java create mode 100644 modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java create mode 100644 modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java create mode 100644 modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md new file mode 100644 index 00000000000..3400ad881a9 --- /dev/null +++ b/docs/modules/gcloud.md @@ -0,0 +1,44 @@ +# GCloud Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +Testcontainers module for the Google's [Cloud SDK](https://cloud.google.com/sdk/). + +Currently, the module supports `Datastore`, `Firestore`, `Pub/Sub` and `Spanner` emulators. In order to use it, you should use the following classes: + +* DatastoreEmulatorContainer +* FirestoreEmulatorContainer +* PubSubEmulatorContainer +* SpannerEmulatorContainer + +## Usage example + +Running GCloud as a stand-in for Google Datastore during a test: + + +[Creating a Datastore container](../../modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) inside_block:creatingDatastoreEmulatorContainer + + +And how to start it: + + +[Starting a Datastore container](../../modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) inside_block:startingDatastoreEmulatorContainer + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:gcloud:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + gcloud + {{latest_version}} + test + +``` diff --git a/mkdocs.yml b/mkdocs.yml index b8372e81ed8..dfff99bb302 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -60,6 +60,7 @@ nav: - modules/databases/presto.md - modules/docker_compose.md - modules/elasticsearch.md + - modules/gcloud.md - modules/kafka.md - modules/localstack.md - modules/mockserver.md diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle new file mode 100644 index 00000000000..a5737648a4b --- /dev/null +++ b/modules/gcloud/build.gradle @@ -0,0 +1,11 @@ +description = "Testcontainers :: GCloud" + +dependencies { + compile project(':testcontainers') + + testCompile 'com.google.cloud:google-cloud-datastore:1.102.4' + testCompile 'com.google.cloud:google-cloud-firestore:1.33.0' + testCompile 'com.google.cloud:google-cloud-pubsub:1.105.0' + testCompile 'com.google.cloud:google-cloud-spanner:1.50.0' + testCompile 'org.assertj:assertj-core:3.15.0' +} diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java new file mode 100644 index 00000000000..85b07b94591 --- /dev/null +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java @@ -0,0 +1,29 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +/** + * A Datastore container that relies in google cloud sdk. + * + * Default port is 8081. + * + * @author Eddú Meléndez + */ +public class DatastoreEmulatorContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + + private static final String CMD = "gcloud beta emulators datastore start --project test-project --host-port 0.0.0.0:8081"; + + public DatastoreEmulatorContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(8081); + setWaitStrategy(Wait.forHttp("/").forStatusCode(200)); + withCommand("/bin/sh", "-c", CMD); + } + +} diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java new file mode 100644 index 00000000000..41442f0f531 --- /dev/null +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java @@ -0,0 +1,30 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; + +/** + * A Firestore container that relies in google cloud sdk. + * + * Default port is 8080. + * + * @author Eddú Meléndez + */ +public class FirestoreEmulatorContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + + private static final String CMD = "gcloud beta emulators firestore start --host-port 0.0.0.0:8080"; + + public FirestoreEmulatorContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(8080); + setWaitStrategy(new LogMessageWaitStrategy() + .withRegEx("(?s).*running.*$")); + withCommand("/bin/sh", "-c", CMD); + } + +} diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java new file mode 100644 index 00000000000..c92145b3d3a --- /dev/null +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java @@ -0,0 +1,30 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; + +/** + * A PubSub container that relies in google cloud sdk. + * + * Default port is 8085. + * + * @author Eddú Meléndez + */ +public class PubSubEmulatorContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + + private static final String CMD = "gcloud beta emulators pubsub start --host-port 0.0.0.0:8085"; + + public PubSubEmulatorContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(8085); + setWaitStrategy(new LogMessageWaitStrategy() + .withRegEx("(?s).*started.*$")); + withCommand("/bin/sh", "-c", CMD); + } + +} diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java new file mode 100644 index 00000000000..5f2a203d911 --- /dev/null +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java @@ -0,0 +1,28 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; + +/** + * A Spanner container. Default ports: 9010 for GRPC and 9020 for HTTP. + * + * @author Eddú Meléndez + */ +public class SpannerEmulatorContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator"); + + private static final int GRPC_PORT = 9010; + private static final int HTTP_PORT = 9020; + + public SpannerEmulatorContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(GRPC_PORT, HTTP_PORT); + setWaitStrategy(new LogMessageWaitStrategy() + .withRegEx(".*Cloud Spanner emulator running\\..*")); + } + +} diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java new file mode 100644 index 00000000000..f8285e4c691 --- /dev/null +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java @@ -0,0 +1,43 @@ +package org.testcontainers.containers; + +import com.google.cloud.NoCredentials; +import com.google.cloud.ServiceOptions; +import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.DatastoreOptions; +import com.google.cloud.datastore.Entity; +import com.google.cloud.datastore.Key; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DatastoreEmulatorContainerTest { + + @Rule + // creatingDatastoreEmulatorContainer { + public DatastoreEmulatorContainer emulator = new DatastoreEmulatorContainer( + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:313.0.0") + ); + // } + + // startingDatastoreEmulatorContainer { + @Test + public void testSimple() { + DatastoreOptions options = DatastoreOptions.newBuilder() + .setHost(emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(8081)) + .setCredentials(NoCredentials.getInstance()) + .setRetrySettings(ServiceOptions.getNoRetrySettings()) + .setProjectId("test-project") + .build(); + Datastore datastore = options.getService(); + + Key key = datastore.newKeyFactory().setKind("Task").newKey("sample"); + Entity entity = Entity.newBuilder(key).set("description", "my description").build(); + datastore.put(entity); + + assertThat(datastore.get(key).getString("description")).isEqualTo("my description"); + } + // } + +} diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java new file mode 100644 index 00000000000..2f23ff40483 --- /dev/null +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java @@ -0,0 +1,49 @@ +package org.testcontainers.containers; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import com.google.api.core.ApiFuture; +import com.google.cloud.NoCredentials; +import com.google.cloud.firestore.CollectionReference; +import com.google.cloud.firestore.DocumentReference; +import com.google.cloud.firestore.Firestore; +import com.google.cloud.firestore.FirestoreOptions; +import com.google.cloud.firestore.QuerySnapshot; +import com.google.cloud.firestore.WriteResult; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + +import static org.assertj.core.api.Assertions.assertThat; + +public class FirestoreEmulatorContainerTest { + + @Rule + public FirestoreEmulatorContainer emulator = new FirestoreEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:313.0.0")); + + @Test + public void testSimple() throws ExecutionException, InterruptedException { + FirestoreOptions options = FirestoreOptions.getDefaultInstance().toBuilder() + .setHost(emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(8080)) + .setCredentials(NoCredentials.getInstance()) + .setProjectId("test-project") + .build(); + Firestore firestore = options.getService(); + + CollectionReference users = firestore.collection("users"); + DocumentReference docRef = users.document("alovelace"); + Map data = new HashMap<>(); + data.put("first", "Ada"); + data.put("last", "Lovelace"); + ApiFuture result = docRef.set(data); + result.get(); + + ApiFuture query = users.get(); + QuerySnapshot querySnapshot = query.get(); + + assertThat(querySnapshot.getDocuments().get(0).getData()).containsEntry("first", "Ada"); + } + +} diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java new file mode 100644 index 00000000000..0c5ec888de5 --- /dev/null +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java @@ -0,0 +1,102 @@ +package org.testcontainers.containers; + +import java.io.IOException; + +import com.google.api.gax.core.NoCredentialsProvider; +import com.google.api.gax.grpc.GrpcTransportChannel; +import com.google.api.gax.rpc.FixedTransportChannelProvider; +import com.google.api.gax.rpc.TransportChannelProvider; +import com.google.cloud.pubsub.v1.Publisher; +import com.google.cloud.pubsub.v1.SubscriptionAdminClient; +import com.google.cloud.pubsub.v1.SubscriptionAdminSettings; +import com.google.cloud.pubsub.v1.TopicAdminClient; +import com.google.cloud.pubsub.v1.TopicAdminSettings; +import com.google.cloud.pubsub.v1.stub.GrpcSubscriberStub; +import com.google.cloud.pubsub.v1.stub.SubscriberStub; +import com.google.cloud.pubsub.v1.stub.SubscriberStubSettings; +import com.google.protobuf.ByteString; +import com.google.pubsub.v1.ProjectSubscriptionName; +import com.google.pubsub.v1.PubsubMessage; +import com.google.pubsub.v1.PullRequest; +import com.google.pubsub.v1.PullResponse; +import com.google.pubsub.v1.PushConfig; +import com.google.pubsub.v1.TopicName; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PubSubEmulatorContainerTest { + + public static final String PROJECT_ID = "my-project-id"; + + @Rule + public PubSubEmulatorContainer emulator = new PubSubEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:313.0.0")); + + @Test + public void testSimple() throws IOException { + String hostport = emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(8085); + ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build(); + try { + TransportChannelProvider channelProvider = + FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel)); + NoCredentialsProvider credentialsProvider = NoCredentialsProvider.create(); + + String topicId = "my-topic-id"; + createTopic(topicId, channelProvider, credentialsProvider); + + String subscriptionId = "my-subscription-id"; + createSubscription(subscriptionId, topicId, channelProvider, credentialsProvider); + + Publisher publisher = Publisher.newBuilder(TopicName.of(PROJECT_ID, topicId)) + .setChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); + PubsubMessage message = PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8("test message")).build(); + publisher.publish(message); + + SubscriberStubSettings subscriberStubSettings = + SubscriberStubSettings.newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); + try (SubscriberStub subscriber = GrpcSubscriberStub.create(subscriberStubSettings)) { + PullRequest pullRequest = PullRequest.newBuilder() + .setMaxMessages(1) + .setSubscription(ProjectSubscriptionName.format(PROJECT_ID, subscriptionId)) + .build(); + PullResponse pullResponse = subscriber.pullCallable().call(pullRequest); + + assertThat(pullResponse.getReceivedMessagesList()).hasSize(1); + assertThat(pullResponse.getReceivedMessages(0).getMessage().getData().toStringUtf8()).isEqualTo("test message"); + } + } finally { + channel.shutdown(); + } + } + + private void createTopic(String topicId, TransportChannelProvider channelProvider, NoCredentialsProvider credentialsProvider) throws IOException { + TopicAdminSettings topicAdminSettings = TopicAdminSettings.newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); + try (TopicAdminClient topicAdminClient = TopicAdminClient.create(topicAdminSettings)) { + TopicName topicName = TopicName.of(PROJECT_ID, topicId); + topicAdminClient.createTopic(topicName); + } + } + + private void createSubscription(String subscriptionId, String topicId, TransportChannelProvider channelProvider, NoCredentialsProvider credentialsProvider) throws IOException { + SubscriptionAdminSettings subscriptionAdminSettings = SubscriptionAdminSettings.newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); + SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create(subscriptionAdminSettings); + ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(PROJECT_ID, subscriptionId); + subscriptionAdminClient.createSubscription(subscriptionName, TopicName.of(PROJECT_ID, topicId), PushConfig.getDefaultInstance(), 10); + } + +} diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java new file mode 100644 index 00000000000..9093530236a --- /dev/null +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java @@ -0,0 +1,80 @@ +package org.testcontainers.containers; + +import java.util.Arrays; +import java.util.concurrent.ExecutionException; + +import com.google.cloud.NoCredentials; +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.Instance; +import com.google.cloud.spanner.InstanceAdminClient; +import com.google.cloud.spanner.InstanceConfigId; +import com.google.cloud.spanner.InstanceId; +import com.google.cloud.spanner.InstanceInfo; +import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import com.google.cloud.spanner.Statement; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SpannerEmulatorContainerTest { + + @Rule + public SpannerEmulatorContainer emulator = new SpannerEmulatorContainer(DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.1.0")); + + private static final String PROJECT_NAME = "test-project"; + private static final String INSTANCE_NAME = "test-instance"; + private static final String DATABASE_NAME = "test-database"; + + @Test + public void testSimple() throws ExecutionException, InterruptedException { + SpannerOptions options = SpannerOptions.newBuilder() + .setEmulatorHost(emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(9010)) + .setCredentials(NoCredentials.getInstance()) + .setProjectId(PROJECT_NAME) + .build(); + + Spanner spanner = options.getService(); + + InstanceId instanceId = createInstance(spanner); + + createDatabase(spanner); + + DatabaseId databaseId = DatabaseId.of(instanceId, DATABASE_NAME); + DatabaseClient dbClient = spanner.getDatabaseClient(databaseId); + dbClient.readWriteTransaction() + .run(tx -> { + String sql1 = "Delete from TestTable where 1=1"; + tx.executeUpdate(Statement.of(sql1)); + String sql = "INSERT INTO TestTable (Key, Value) VALUES (1, 'Java'), (2, 'Go')"; + tx.executeUpdate(Statement.of(sql)); + return null; + }); + + ResultSet resultSet = dbClient.readOnlyTransaction() + .executeQuery(Statement.of("select * from TestTable order by Key")); + resultSet.next(); + assertThat(resultSet.getLong(0)).isEqualTo(1); + assertThat(resultSet.getString(1)).isEqualTo("Java"); + } + + private void createDatabase(Spanner spanner) throws InterruptedException, ExecutionException { + DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient(); + Database database = dbAdminClient.createDatabase(INSTANCE_NAME, DATABASE_NAME, Arrays.asList("CREATE TABLE TestTable (Key INT64, Value STRING(MAX)) PRIMARY KEY (Key)")).get(); + } + + private InstanceId createInstance(Spanner spanner) throws InterruptedException, ExecutionException { + InstanceConfigId instanceConfig = InstanceConfigId.of(PROJECT_NAME, "emulator-config"); + InstanceId instanceId = InstanceId.of(PROJECT_NAME, INSTANCE_NAME); + InstanceAdminClient insAdminClient = spanner.getInstanceAdminClient(); + Instance instance = insAdminClient.createInstance(InstanceInfo.newBuilder(instanceId).setNodeCount(1).setDisplayName("Test instance").setInstanceConfigId(instanceConfig).build()).get(); + return instanceId; + } + +} From 3bf8d76683a38bdcdef6b12ab2f699e04b9c6a1c Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 13 Oct 2020 20:01:20 +0100 Subject: [PATCH 1035/4969] Use a lighter weight image for MultiplePortsExposedTest (#3343) * Use a lighter weight image for MultiplePortsExposedTest * Update helloworld container version --- .../java/generic/MultiplePortsExposedTest.java | 14 +++++++------- .../junit/BaseWebDriverContainerTest.java | 13 ++++++------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java index 329fd8d8e19..de2b56c6a63 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java @@ -1,5 +1,7 @@ package generic; +import static org.slf4j.LoggerFactory.getLogger; + import org.junit.Rule; import org.junit.Test; import org.slf4j.Logger; @@ -7,23 +9,21 @@ import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.utility.DockerImageName; -import static org.slf4j.LoggerFactory.getLogger; - public class MultiplePortsExposedTest { private static final Logger log = getLogger(MultiplePortsExposedTest.class); @Rule // rule { - public GenericContainer container = new GenericContainer(DockerImageName.parse("orientdb:3.0.13")) - .withExposedPorts(2424, 2480) + public GenericContainer container = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld:1.1.0")) + .withExposedPorts(8080, 8081) .withLogConsumer(new Slf4jLogConsumer(log)); // } @Test public void fetchPortsByNumber() { - Integer firstMappedPort = container.getMappedPort(2424); - Integer secondMappedPort = container.getMappedPort(2480); + Integer firstMappedPort = container.getMappedPort(8080); + Integer secondMappedPort = container.getMappedPort(8081); } @Test @@ -39,6 +39,6 @@ public void getHostOnly() { @Test public void getHostAndMappedPort() { String address = - container.getHost() + ":" + container.getMappedPort(2424); + container.getHost() + ":" + container.getMappedPort(8080); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java index cf5c762f2ad..db369824442 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java @@ -1,5 +1,10 @@ package org.testcontainers.junit; +import static java.lang.String.format; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; + +import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; import org.junit.ClassRule; import org.openqa.selenium.By; @@ -11,12 +16,6 @@ import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.DockerImageName; -import java.util.concurrent.TimeUnit; - -import static java.lang.String.format; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; - /** * */ @@ -26,7 +25,7 @@ public class BaseWebDriverContainerTest { public static Network NETWORK = Network.newNetwork(); @ClassRule - public static GenericContainer HELLO_WORLD = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld:1.0.0")) + public static GenericContainer HELLO_WORLD = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld:1.1.0")) .withNetwork(NETWORK) .withNetworkAliases("helloworld") .withExposedPorts(8080, 8081) From ae5010aee429620acac888cef532d89135710c1d Mon Sep 17 00:00:00 2001 From: vcvitaly Date: Wed, 14 Oct 2020 19:26:16 +0300 Subject: [PATCH 1036/4969] docker-machine: get full remote daemon URL, to allow for use of custom daemon port (#2769) (#3237) Co-authored-by: Vitalii Chura --- .../dockerclient/DockerMachineClientProviderStrategy.java | 6 +++--- .../org/testcontainers/utility/DockerMachineClient.java | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java index 2b0454c1ee6..4de508ea808 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java @@ -37,12 +37,12 @@ private TransportConfig resolveTransportConfig() throws InvalidConfigurationExce DockerMachineClient.instance().ensureMachineRunning(machineName); - String dockerDaemonIpAddress = DockerMachineClient.instance().getDockerDaemonIpAddress(machineName); + String dockerDaemonUrl = DockerMachineClient.instance().getDockerDaemonUrl(machineName); - log.info("Docker daemon IP address for docker machine {} is {}", machineName, dockerDaemonIpAddress); + log.info("Docker daemon URL for docker machine {} is {}", machineName, dockerDaemonUrl); return TransportConfig.builder() - .dockerHost(URI.create("tcp://" + dockerDaemonIpAddress + ":2376")) + .dockerHost(URI.create(dockerDaemonUrl)) .sslConfig( new LocalDirectorySSLConfig( Paths.get(System.getProperty("user.home") + "/.docker/machine/certs/").toString() diff --git a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java index fe12e9f541d..021baf270d9 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java +++ b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java @@ -79,10 +79,18 @@ public void ensureMachineRunning(@NonNull String machineName) { } } + /** + * @deprecated Use getDockerDaemonUrl(@NonNull String machineName) for connection to docker-machine + */ + @Deprecated public String getDockerDaemonIpAddress(@NonNull String machineName) { return runShellCommand(executableName, "ip", machineName); } + public String getDockerDaemonUrl(@NonNull String machineName) { + return runShellCommand(executableName, "url", machineName); + } + public boolean isMachineRunning(String machineName) { String status = runShellCommand("docker-machine", "status", machineName); return status.trim().equalsIgnoreCase("running"); From abf0f9aa65207f67e1174ad2b43b4a354f5ae998 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 14 Oct 2020 22:46:52 +0100 Subject: [PATCH 1037/4969] Fix remote gradle cache 400 InvalidArgument error (#3346) per hint given in https://www.digitalocean.com/community/questions/node-upload-file-to-s3-error-invalidargument-null --- settings.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.gradle b/settings.gradle index 2ea21599ceb..849a1ade06b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -46,6 +46,7 @@ buildCache { region = 'fra1' bucket = 'testcontainers' path = 'cache' + reducedRedundancy = false push = isMasterBuild && !System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") headers = [ 'x-amz-acl': 'public-read' From a33622f143c93ee2d771eda30bb8ab88eb450c9d Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 15 Oct 2020 08:46:41 +0100 Subject: [PATCH 1038/4969] Add gcloud endpoint accessors (#3344) --- .../containers/DatastoreEmulatorContainer.java | 11 ++++++++++- .../containers/FirestoreEmulatorContainer.java | 11 ++++++++++- .../containers/PubSubEmulatorContainer.java | 9 +++++++++ .../containers/SpannerEmulatorContainer.java | 16 ++++++++++++++++ .../DatastoreEmulatorContainerTest.java | 6 +++--- .../FirestoreEmulatorContainerTest.java | 11 +++++------ .../containers/PubSubEmulatorContainerTest.java | 7 +++---- .../containers/SpannerEmulatorContainerTest.java | 9 ++++----- .../gcloud/src/test/resources/logback-test.xml | 16 ++++++++++++++++ 9 files changed, 76 insertions(+), 20 deletions(-) create mode 100644 modules/gcloud/src/test/resources/logback-test.xml diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java index 85b07b94591..fe0a9959f2d 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java @@ -15,15 +15,24 @@ public class DatastoreEmulatorContainer extends GenericContainerhost:port pair corresponding to the address on which the emulator is + * reachable from the test host machine. Directly usable as a parameter to the + * com.google.cloud.ServiceOptions.Builder#setHost(java.lang.String) method. + */ + public String getEmulatorEndpoint() { + return getContainerIpAddress() + ":" + getMappedPort(8081); + } } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java index 41442f0f531..6353a679130 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java @@ -15,16 +15,25 @@ public class FirestoreEmulatorContainer extends GenericContainerhost:port pair corresponding to the address on which the emulator is + * reachable from the test host machine. Directly usable as a parameter to the + * com.google.cloud.ServiceOptions.Builder#setHost(java.lang.String) method. + */ + public String getEmulatorEndpoint() { + return getContainerIpAddress() + ":" + getMappedPort(8080); + } } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java index c92145b3d3a..90d77c837cf 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java @@ -15,6 +15,7 @@ public class PubSubEmulatorContainer extends GenericContainerhost:port pair corresponding to the address on which the emulator is + * reachable from the test host machine. Directly usable as a parameter to the + * io.grpc.ManagedChannelBuilder#forTarget(java.lang.String) method. + */ + public String getEmulatorEndpoint() { + return getContainerIpAddress() + ":" + getMappedPort(PORT); + } } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java index 5f2a203d911..8603b1f3437 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java @@ -25,4 +25,20 @@ public SpannerEmulatorContainer(final DockerImageName dockerImageName) { .withRegEx(".*Cloud Spanner emulator running\\..*")); } + /** + * @return a host:port pair corresponding to the address on which the emulator's + * gRPC endpoint is reachable from the test host machine. Directly usable as a parameter to the + * com.google.cloud.spanner.SpannerOptions.Builder#setEmulatorHost(java.lang.String) method. + */ + public String getEmulatorGrpcEndpoint() { + return getContainerIpAddress() + ":" + getMappedPort(GRPC_PORT); + } + + /** + * @return a host:port pair corresponding to the address on which the emulator's + * HTTP REST endpoint is reachable from the test host machine. + */ + public String getEmulatorHttpEndpoint() { + return getContainerIpAddress() + ":" + getMappedPort(HTTP_PORT); + } } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java index f8285e4c691..4709ed1bbd6 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java @@ -1,5 +1,7 @@ package org.testcontainers.containers; +import static org.assertj.core.api.Assertions.assertThat; + import com.google.cloud.NoCredentials; import com.google.cloud.ServiceOptions; import com.google.cloud.datastore.Datastore; @@ -10,8 +12,6 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.assertj.core.api.Assertions.assertThat; - public class DatastoreEmulatorContainerTest { @Rule @@ -25,7 +25,7 @@ public class DatastoreEmulatorContainerTest { @Test public void testSimple() { DatastoreOptions options = DatastoreOptions.newBuilder() - .setHost(emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(8081)) + .setHost(emulator.getEmulatorEndpoint()) .setCredentials(NoCredentials.getInstance()) .setRetrySettings(ServiceOptions.getNoRetrySettings()) .setProjectId("test-project") diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java index 2f23ff40483..766ce657bf0 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java @@ -1,8 +1,6 @@ package org.testcontainers.containers; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutionException; +import static org.assertj.core.api.Assertions.assertThat; import com.google.api.core.ApiFuture; import com.google.cloud.NoCredentials; @@ -12,12 +10,13 @@ import com.google.cloud.firestore.FirestoreOptions; import com.google.cloud.firestore.QuerySnapshot; import com.google.cloud.firestore.WriteResult; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; import org.junit.Rule; import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.assertj.core.api.Assertions.assertThat; - public class FirestoreEmulatorContainerTest { @Rule @@ -26,7 +25,7 @@ public class FirestoreEmulatorContainerTest { @Test public void testSimple() throws ExecutionException, InterruptedException { FirestoreOptions options = FirestoreOptions.getDefaultInstance().toBuilder() - .setHost(emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(8080)) + .setHost(emulator.getEmulatorEndpoint()) .setCredentials(NoCredentials.getInstance()) .setProjectId("test-project") .build(); diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java index 0c5ec888de5..2a0acaa14e1 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java @@ -1,6 +1,6 @@ package org.testcontainers.containers; -import java.io.IOException; +import static org.assertj.core.api.Assertions.assertThat; import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.grpc.GrpcTransportChannel; @@ -23,12 +23,11 @@ import com.google.pubsub.v1.TopicName; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; +import java.io.IOException; import org.junit.Rule; import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.assertj.core.api.Assertions.assertThat; - public class PubSubEmulatorContainerTest { public static final String PROJECT_ID = "my-project-id"; @@ -38,7 +37,7 @@ public class PubSubEmulatorContainerTest { @Test public void testSimple() throws IOException { - String hostport = emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(8085); + String hostport = emulator.getEmulatorEndpoint(); ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build(); try { TransportChannelProvider channelProvider = diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java index 9093530236a..5a47f9429ad 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java @@ -1,7 +1,6 @@ package org.testcontainers.containers; -import java.util.Arrays; -import java.util.concurrent.ExecutionException; +import static org.assertj.core.api.Assertions.assertThat; import com.google.cloud.NoCredentials; import com.google.cloud.spanner.Database; @@ -17,12 +16,12 @@ import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.SpannerOptions; import com.google.cloud.spanner.Statement; +import java.util.Arrays; +import java.util.concurrent.ExecutionException; import org.junit.Rule; import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.assertj.core.api.Assertions.assertThat; - public class SpannerEmulatorContainerTest { @Rule @@ -35,7 +34,7 @@ public class SpannerEmulatorContainerTest { @Test public void testSimple() throws ExecutionException, InterruptedException { SpannerOptions options = SpannerOptions.newBuilder() - .setEmulatorHost(emulator.getContainerIpAddress() + ":" + emulator.getMappedPort(9010)) + .setEmulatorHost(emulator.getEmulatorGrpcEndpoint()) .setCredentials(NoCredentials.getInstance()) .setProjectId(PROJECT_NAME) .build(); diff --git a/modules/gcloud/src/test/resources/logback-test.xml b/modules/gcloud/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/gcloud/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 85f1e5e1352c95fb4f66b688c00e32fcf72546c1 Mon Sep 17 00:00:00 2001 From: David Pilato Date: Thu, 15 Oct 2020 21:34:44 +0200 Subject: [PATCH 1039/4969] Elasticsearch: Add test and documentation for secured cluster, bump default Elasticsearch version (deprecated constructor) from 6.4.1 to 7.9.2 (#2320) This can be now activated for free with the default basic license. Also change latest version to 7.9.2. --- docs/modules/elasticsearch.md | 13 ++- modules/elasticsearch/build.gradle | 2 +- .../elasticsearch/ElasticsearchContainer.java | 10 +- .../ElasticsearchContainerTest.java | 106 +++++++++++++++--- 4 files changed, 111 insertions(+), 20 deletions(-) diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index 9959d0b7926..f84a7840e4c 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -3,7 +3,7 @@ This module helps running [elasticsearch](https://www.elastic.co/products/elasticsearch) using Testcontainers. -Note that it's based on the [official Docker image](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/docker.html) provided by elastic. +Note that it's based on the [official Docker image](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html) provided by elastic. ## Usage example @@ -15,10 +15,19 @@ You can start an elasticsearch container instance from any Java application by u -Note that if you are still using the [TransportClient](https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.3/transport-client.html) +Note that if you are still using the [TransportClient](https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html) (not recommended as it is deprecated), the default cluster name is set to `docker-cluster` so you need to change `cluster.name` setting or set `client.transport.ignore_cluster_name` to `true`. +## Secure your Elasticsearch cluster + +The default distribution of Elasticsearch comes with the basic license which contains security feature. +You can turn on security by providing some extra environment settings: + + +[HttpClient](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:httpClientSecuredContainer + + ## Choose your Elasticsearch license If you prefer to start a Docker image with the pure OSS version (which means with no security in older versions or diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index e6de1daa7ab..126722759ec 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.9.2" - testCompile "org.elasticsearch.client:transport:6.7.1" + testCompile "org.elasticsearch.client:transport:7.9.2" } diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index 7ed660d38c6..e0880aa7849 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -23,7 +23,9 @@ public class ElasticsearchContainer extends GenericContainer basic + * Elasticsearch default username, when secured */ private static final String ELASTICSEARCH_USERNAME = "elastic"; /** - * Elasticsearch 5.x default password. In 6.x images, there's no security by default as shipped with a basic license. + * From 6.8, we can optionally activate security with a default password. */ private static final String ELASTICSEARCH_PASSWORD = "changeme"; private RestClient client = null; + private RestClient anonymousClient = null; @After public void stopRestClient() throws IOException { @@ -56,11 +55,16 @@ public void stopRestClient() throws IOException { client.close(); client = null; } + if (anonymousClient != null) { + anonymousClient.close(); + anonymousClient = null; + } } @SuppressWarnings("deprecation") // Using deprecated constructor for verification of backwards compatibility @Test - public void elasticsearchDefaultTest() throws IOException { + @Deprecated // We will remove this test in the future + public void elasticsearchDeprecatedCtorTest() throws IOException { // Create the elasticsearch container. try (ElasticsearchContainer container = new ElasticsearchContainer() .withEnv("foo", "bar") // dummy env for compiler checking correct generics usage @@ -71,7 +75,29 @@ public void elasticsearchDefaultTest() throws IOException { // Do whatever you want with the rest client ... Response response = getClient(container).performRequest(new Request("GET", "/")); assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString(DEFAULT_TAG)); + assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION)); + + // The default image is running with the features under Elastic License + response = getClient(container).performRequest(new Request("GET", "/_xpack/")); + assertThat(response.getStatusLine().getStatusCode(), is(200)); + // For now we test that we have the monitoring feature available + assertThat(EntityUtils.toString(response.getEntity()), containsString("monitoring")); + } + } + + @Test + public void elasticsearchDefaultTest() throws IOException { + // Create the elasticsearch container. + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) + .withEnv("foo", "bar") // dummy env for compiler checking correct generics usage + ) { + // Start the container. This step might take some time... + container.start(); + + // Do whatever you want with the rest client ... + Response response = getClient(container).performRequest(new Request("GET", "/")); + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION)); // The default image is running with the features under Elastic License response = getClient(container).performRequest(new Request("GET", "/_xpack/")); @@ -81,6 +107,26 @@ public void elasticsearchDefaultTest() throws IOException { } } + @Test + public void elasticsearchSecuredTest() throws IOException { + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) + .withEnv("ELASTIC_PASSWORD", ELASTICSEARCH_PASSWORD) + .withEnv("xpack.security.enabled", "true") + ) { + container.start(); + + // The cluster should be secured so it must fail when we try to access / without credentials + assertThrows("We should not be able to access / URI with an anonymous client.", + ResponseException.class, + () -> getAnonymousClient(container).performRequest(new Request("GET", "/"))); + + // But it should work when we try to access / with the proper login and password + Response response = getClient(container).performRequest(new Request("GET", "/")); + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION)); + } + } + @Test public void elasticsearchVersion() throws IOException { try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)) { @@ -113,12 +159,11 @@ public void elasticsearchOssImage() throws IOException { } } - @SuppressWarnings("deprecation") // Using deprecated constructor for verification of backwards compatibility @Test public void restClientClusterHealth() throws IOException { // httpClientContainer { // Create the elasticsearch container. - try (ElasticsearchContainer container = new ElasticsearchContainer()) { + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)) { // Start the container. This step might take some time... container.start(); @@ -140,15 +185,41 @@ public void restClientClusterHealth() throws IOException { // } } + @Test + public void restClientSecuredClusterHealth() throws IOException { + // httpClientSecuredContainer { + // Create the elasticsearch container. + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) + // With a password + .withEnv("ELASTIC_PASSWORD", ELASTICSEARCH_PASSWORD) + .withEnv("xpack.security.enabled", "true")) { + // Start the container. This step might take some time... + container.start(); + + // Create the secured client. + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)); + + client = RestClient.builder(HttpHost.create(container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)) + .build(); + + Response response = client.performRequest(new Request("GET", "/_cluster/health")); + // }} + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + // httpClientSecuredContainer {{ + } + // } + } + + @SuppressWarnings("deprecation") // The TransportClient will be removed in Elasticsearch 8. @Test public void transportClientClusterHealth() { // transportClientContainer { // Create the elasticsearch container. - try (ElasticsearchContainer container = new ElasticsearchContainer( - DockerImageName - .parse("docker.elastic.co/elasticsearch/elasticsearch") - .withTag("6.4.1") - )){ + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)){ // Start the container. This step might take some time... container.start(); @@ -182,4 +253,11 @@ private RestClient getClient(ElasticsearchContainer container) { return client; } + private RestClient getAnonymousClient(ElasticsearchContainer container) { + if (anonymousClient == null) { + anonymousClient = RestClient.builder(HttpHost.create(container.getHttpHostAddress())).build(); + } + + return anonymousClient; + } } From edb7f7a8e3233f9504f737102aa4180fe0949ec4 Mon Sep 17 00:00:00 2001 From: Kirill Artamonov Date: Thu, 15 Oct 2020 22:08:53 +0200 Subject: [PATCH 1040/4969] Update image references in Localstack module docs (#3076) Co-authored-by: Richard North --- docs/modules/localstack.md | 4 +++- .../containers/localstack/LocalstackContainerTest.java | 9 +++------ .../containers/localstack/LocalstackTestImages.java | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index 4ff46233b05..41fd2a50a52 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -7,8 +7,10 @@ Testcontainers module for the Atlassian's [LocalStack](https://github.com/locals Running LocalStack as a stand-in for AWS S3 during a test: ```java +DockerImageName localstackImage = DockerImageName.parse("localstack/localstack:0.11.3"); + @Rule -public LocalStackContainer localstack = new LocalStackContainer() +public LocalStackContainer localstack = new LocalStackContainer(localstackImage) .withServices(S3); @Test diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index fad4060341c..af4d0694ab6 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -10,6 +10,7 @@ import static org.testcontainers.containers.localstack.LocalStackContainer.Service.KMS; import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; +import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_IMAGE; import com.amazonaws.services.kms.AWSKMS; import com.amazonaws.services.kms.AWSKMSClientBuilder; @@ -64,9 +65,7 @@ public static class WithoutNetwork { // without_network { @ClassRule - public static LocalStackContainer localstack = new LocalStackContainer( - DockerImageName.parse("localstack/localstack:0.11.0") - ) + public static LocalStackContainer localstack = new LocalStackContainer(LOCALSTACK_IMAGE) .withServices(S3, SQS, CLOUDWATCHLOGS, KMS); // } @@ -179,9 +178,7 @@ public static class WithNetwork { private static Network network = Network.newNetwork(); @ClassRule - public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer( - DockerImageName.parse("localstack/localstack:0.11.0") - ) + public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer(LOCALSTACK_IMAGE) .withNetwork(network) .withNetworkAliases("notthis", "localstack") // the last alias is used for HOSTNAME_EXTERNAL .withServices(S3, SQS, CLOUDWATCHLOGS); diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java index 60e5498daf3..0dd0ca9b9ac 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java @@ -3,6 +3,6 @@ import org.testcontainers.utility.DockerImageName; public interface LocalstackTestImages { - DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.11.0"); + DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.11.3"); DockerImageName AWS_CLI_IMAGE = DockerImageName.parse("atlassian/pipelines-awscli:1.16.302"); } From 9d4b31d23d21bacf1f54791264c292e15df61d58 Mon Sep 17 00:00:00 2001 From: David Pilato Date: Fri, 16 Oct 2020 10:43:46 +0200 Subject: [PATCH 1041/4969] Fix `oos` -> `oss` in Elasticsearch's docs (#3349) --- docs/modules/elasticsearch.md | 2 +- .../elasticsearch/ElasticsearchContainerTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index f84a7840e4c..357ca782eaa 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -34,7 +34,7 @@ If you prefer to start a Docker image with the pure OSS version (which means wit other new and advanced features), you can use this instead: -[Elasticsearch OSS](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:oosContainer +[Elasticsearch OSS](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:ossContainer ## Adding this module to your project dependencies diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index f86f1e8c104..3050ab4aedb 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -141,7 +141,7 @@ public void elasticsearchVersion() throws IOException { @Test public void elasticsearchOssImage() throws IOException { try (ElasticsearchContainer container = - // oosContainer { + // ossContainer { new ElasticsearchContainer( DockerImageName .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") From 443307c21e4c4b20e7cee143b9bbd619f2319333 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 21 Oct 2020 09:28:34 +0100 Subject: [PATCH 1042/4969] Upgrade mkdocs-codeinclude-plugin (#3354) Fixes indentation of ellipsis in within example code blocks --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 227c646dd6b..f962b36a44f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ mkdocs==1.0.4 -mkdocs-codeinclude-plugin==0.0.1 +mkdocs-codeinclude-plugin==0.1.0 mkdocs-material==4.6.0 mkdocs-markdownextradata-plugin==0.1.1 markdown>=3.1,<3.2 From ec43c31f06d2ec46014d3a2e63a2577e375008ec Mon Sep 17 00:00:00 2001 From: David Pilato Date: Wed, 21 Oct 2020 17:35:25 +0200 Subject: [PATCH 1043/4969] Elasticsearch: Add withPassword(String) method for secure access (#2321) --- docs/modules/elasticsearch.md | 2 +- .../elasticsearch/ElasticsearchContainer.java | 21 +++++++++++++++++++ .../ElasticsearchContainerTest.java | 20 +++++++++++++----- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index 357ca782eaa..cd47c9c4ed3 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -22,7 +22,7 @@ or set `client.transport.ignore_cluster_name` to `true`. ## Secure your Elasticsearch cluster The default distribution of Elasticsearch comes with the basic license which contains security feature. -You can turn on security by providing some extra environment settings: +You can turn on security by providing a password: [HttpClient](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:httpClientSecuredContainer diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index e0880aa7849..acbca15aaf5 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -39,6 +39,7 @@ public class ElasticsearchContainer extends GenericContainer new ElasticsearchContainer( + DockerImageName + .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") + .withTag(ELASTICSEARCH_VERSION)) + .withPassword("foo") + ); + } + private RestClient getClient(ElasticsearchContainer container) { if (client == null) { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); From d3829ed535d3c92fa34dad49fd84ec05fd258630 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:13:09 +0100 Subject: [PATCH 1044/4969] Bump aws-java-sdk-dynamodb from 1.11.880 to 1.11.882 in /modules/dynalite (#3356) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.880 to 1.11.882. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.880...1.11.882) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index fe8fb883839..8aa9959ea13 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.880' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.865' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.882' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.882' } From 769e202808439baa67bd47ce476144f48e29f772 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:13:29 +0100 Subject: [PATCH 1045/4969] Bump postgresql from 42.2.17 to 42.2.18 in /modules/postgresql (#3358) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.17 to 42.2.18. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.18/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.17...REL42.2.18) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index aa5db7028b5..b16ceaea2a8 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile project(':jdbc-test') testCompile project(':test-support') - testCompile 'org.postgresql:postgresql:42.2.17' + testCompile 'org.postgresql:postgresql:42.2.18' testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' From 05691471fdb7fb61b90c2d4b286415492f2d7b57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:14:25 +0100 Subject: [PATCH 1046/4969] Bump mysql-connector-java from 8.0.21 to 8.0.22 in /modules/mysql (#3357) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.21 to 8.0.22. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 9df2e177d3f..da3dad9f2b3 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testCompile project(':jdbc-test') - testCompile 'mysql:mysql-connector-java:8.0.21' + testCompile 'mysql:mysql-connector-java:8.0.22' testCompile testFixtures(project(':r2dbc')) testCompile 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' From 1d80a407c0821d1c269a7ca0108f00a2703fc3a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:14:34 +0100 Subject: [PATCH 1047/4969] Bump guava from 29.0-jre to 30.0-jre in /modules/jdbc-test (#3359) Bumps [guava](https://github.com/google/guava) from 29.0-jre to 30.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index ec57ddcea41..661cc1b4301 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -2,7 +2,7 @@ dependencies { compile project(':jdbc') compile project(':test-support') - compile 'com.google.guava:guava:29.0-jre' + compile 'com.google.guava:guava:30.0-jre' compile 'org.apache.commons:commons-lang3:3.11' compile 'com.zaxxer:HikariCP-java6:2.3.13' compile 'commons-dbutils:commons-dbutils:1.7' From a71887b5d86fdbd1b4e0a23e87c232395e44fb7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:14:47 +0100 Subject: [PATCH 1048/4969] Bump mysql-connector-java from 8.0.21 to 8.0.22 in /modules/jdbc-test (#3360) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.21 to 8.0.22. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 661cc1b4301..99841c1d62a 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -17,5 +17,5 @@ dependencies { compile 'commons-dbutils:commons-dbutils:1.7' compile 'org.apache.tomcat:tomcat-jdbc:9.0.39' compile 'org.vibur:vibur-dbcp:25.0' - compile 'mysql:mysql-connector-java:8.0.21' + compile 'mysql:mysql-connector-java:8.0.22' } From 8b10cee92c3e80ed2c833c41f037dc3cbc3a3aa3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:15:00 +0100 Subject: [PATCH 1049/4969] Bump mysql-connector-java from 8.0.21 to 8.0.22 in /modules/spock (#3363) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.21 to 8.0.22. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 86724262a29..92e75e8cb86 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.13' testRuntime 'org.postgresql:postgresql:42.2.17' - testRuntime 'mysql:mysql-connector-java:8.0.21' + testRuntime 'mysql:mysql-connector-java:8.0.22' testCompileClasspath 'org.jetbrains:annotations:20.1.0' } From 2fb35460ba9324544e83a1990409b4dda616f6d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:15:36 +0100 Subject: [PATCH 1050/4969] Bump mssql-jdbc from 8.4.1.jre8 to 9.1.0.jre8-preview in /modules/mssqlserver (#3364) Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 8.4.1.jre8 to 9.1.0.jre8-preview. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/dev/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index f0170500e7d..9aab7844148 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,12 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.4.RELEASE' testCompile project(':jdbc-test') - testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.4.1.jre8' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.0.jre8-preview' testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.3.RELEASE' // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) - testCompile 'com.microsoft.sqlserver:mssql-jdbc:8.4.1.jre8' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.0.jre8-preview' } From e7c007b03a1fd74d489d562f4c430bf3180a4af9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:15:43 +0100 Subject: [PATCH 1051/4969] Bump aws-java-sdk-s3 from 1.11.880 to 1.11.882 in /modules/localstack (#3365) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.880 to 1.11.882. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.880...1.11.882) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 29abca90878..dcae987bbf4 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.880' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.882' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From 6985c996daa85c01883cf83276ba193bd59eeb0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:16:04 +0100 Subject: [PATCH 1052/4969] Bump lombok from 1.18.14 to 1.18.16 in /examples (#3368) Bumps [lombok](https://github.com/rzwitserloot/lombok) from 1.18.14 to 1.18.16. - [Release notes](https://github.com/rzwitserloot/lombok/releases) - [Changelog](https://github.com/rzwitserloot/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/rzwitserloot/lombok/compare/v1.18.14...v1.18.16) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/disque-job-queue/build.gradle | 2 +- examples/solr-container/build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index c5e191f4f94..c31cb39b7fe 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.14" + compileOnly "org.projectlombok:lombok:1.18.16" annotationProcessor "org.projectlombok:lombok:1.18.14" implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.6' diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 5a8973cab27..75524364100 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -7,8 +7,8 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.14" - annotationProcessor "org.projectlombok:lombok:1.18.10" + compileOnly "org.projectlombok:lombok:1.18.16" + annotationProcessor "org.projectlombok:lombok:1.18.16" implementation 'org.apache.solr:solr-solrj:8.6.3' From eeecf94f7c42b628599de13bbc5dbeaa5296f6ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:16:25 +0100 Subject: [PATCH 1053/4969] Bump s3 from 2.15.7 to 2.15.9 in /modules/localstack (#3361) Bumps s3 from 2.15.7 to 2.15.9. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index dcae987bbf4..ee02504309f 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.15.7' + testCompile 'software.amazon.awssdk:s3:2.15.9' } From 153b3baf2dce22d706c76d679ba4220cf87a1e55 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 22 Oct 2020 14:22:00 +0100 Subject: [PATCH 1054/4969] Update version to 1.15.0-rc2 --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index dfff99bb302..0fa9b2b4c91 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -92,4 +92,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.14.3 + latest_version: 1.15.0-rc2 From c110086287f96a408c5fbfb589be72d67b033c57 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 22 Oct 2020 17:31:23 +0100 Subject: [PATCH 1055/4969] Change image used for test to avoid image name cache preventing proper pull (#3378) --- .../dockerclient/AmbiguousImagePullTest.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java index 5d2c42ed1b2..9e62148c3bb 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java @@ -5,7 +5,6 @@ import org.junit.Test; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.utility.DockerImageName; import java.util.List; @@ -16,16 +15,15 @@ public class AmbiguousImagePullTest { public void testNotUsingParse() { DockerClient client = DockerClientFactory.instance().client(); List alpineImages = client.listImagesCmd() - .withImageNameFilter("alpine:latest") + .withImageNameFilter("testcontainers/helloworld:latest") .exec(); for (Image alpineImage : alpineImages) { client.removeImageCmd(alpineImage.getId()).exec(); } try ( - final GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine")) - .withCommand("/bin/sh", "-c", "sleep 0") - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + final GenericContainer container = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld")) + .withExposedPorts(8080) ) { container.start(); // do nothing other than start and stop From bd86ca421482b66df6828dd29ee214bbfb9f0e67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2020 15:47:49 +0100 Subject: [PATCH 1056/4969] Bump postgresql from 42.2.17 to 42.2.18 in /modules/spock (#3362) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.17 to 42.2.18. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.18/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.17...REL42.2.18) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 92e75e8cb86..a095bcb8a80 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntime 'org.postgresql:postgresql:42.2.17' + testRuntime 'org.postgresql:postgresql:42.2.18' testRuntime 'mysql:mysql-connector-java:8.0.22' testCompileClasspath 'org.jetbrains:annotations:20.1.0' From 4e1db24e195ff1c8fdf8f8cb3bf1e0d152d97b34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2020 15:48:02 +0100 Subject: [PATCH 1057/4969] Bump postgresql from 42.2.17 to 42.2.18 in /examples (#3367) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.17 to 42.2.18. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.18/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.17...REL42.2.18) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 5c4c473becb..f5f21a57d21 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.9.0' implementation 'org.json:json:20180813' - testImplementation 'org.postgresql:postgresql:42.2.17' + testImplementation 'org.postgresql:postgresql:42.2.18' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From d20619cfec8cb55a86ed2cb6b4de14dd3a0c16cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2020 15:48:10 +0100 Subject: [PATCH 1058/4969] Bump mysql-connector-java from 8.0.21 to 8.0.22 in /modules/junit-jupiter (#3370) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.21 to 8.0.22. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 28f6049faf4..d85fc9fa85c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' testRuntime 'org.postgresql:postgresql:42.2.17' - testRuntime 'mysql:mysql-connector-java:8.0.21' + testRuntime 'mysql:mysql-connector-java:8.0.22' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } From 9353569be58e8bf0d35b2838eebc68e75b07ca43 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2020 15:48:21 +0100 Subject: [PATCH 1059/4969] Bump guava from 29.0-jre to 30.0-jre in /core (#3371) Bumps [guava](https://github.com/google/guava) from 29.0-jre to 30.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index e043313ac38..723b14fd0e6 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ buildscript { dependencies { // https://github.com/melix/japicmp-gradle-plugin/issues/36 - classpath 'com.google.guava:guava:29.0-jre' + classpath 'com.google.guava:guava:30.0-jre' } } From b4ac0f39748c9cf45998352f404ae2a0d266d855 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2020 19:14:37 +0100 Subject: [PATCH 1060/4969] Bump aws-java-sdk-sqs from 1.11.880 to 1.11.884 in /modules/localstack (#3377) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.880 to 1.11.884. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.880...1.11.884) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ee02504309f..418344b82f2 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.882' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.880' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.884' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.15.9' } From 1b4a2a6356cb12796b57816e9f90a23e7f5a2a57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2020 19:14:49 +0100 Subject: [PATCH 1061/4969] Bump postgresql from 42.2.17 to 42.2.18 in /modules/junit-jupiter (#3369) Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.17 to 42.2.18. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.18/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.17...REL42.2.18) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index d85fc9fa85c..61594d9842b 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'org.assertj:assertj-core:3.17.2' testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' - testRuntime 'org.postgresql:postgresql:42.2.17' + testRuntime 'org.postgresql:postgresql:42.2.18' testRuntime 'mysql:mysql-connector-java:8.0.22' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } From f4fb79b002c25d71ab7a64d90860058b0f24e672 Mon Sep 17 00:00:00 2001 From: codefiddler Date: Thu, 29 Oct 2020 13:21:49 +0100 Subject: [PATCH 1062/4969] Remove potential NullPointerException when trying to log an error in VNC recorder (#3408) --- .../testcontainers/containers/BrowserWebDriverContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index d60d9191748..884cd33a9dd 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -171,7 +171,7 @@ protected void configure() { vncRecordingDirectory = Files.createTempDirectory(TC_TEMP_DIR_PREFIX).toFile(); } catch (IOException e) { // should never happen as per javadoc, since we use valid prefix - logger().error("Exception while trying to create temp directory " + vncRecordingDirectory.getAbsolutePath(), e); + logger().error("Exception while trying to create temp directory", e); throw new ContainerLaunchException("Exception while trying to create temp directory", e); } } From ed6d94f392c4beb23cfa2bd7924376ee7d80d446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 29 Oct 2020 06:23:07 -0600 Subject: [PATCH 1063/4969] Update tests to use emulators image (#3406) `Google Cloud SDK` released a new image which has just emulators installed. --- .../containers/DatastoreEmulatorContainerTest.java | 2 +- .../containers/FirestoreEmulatorContainerTest.java | 2 +- .../testcontainers/containers/PubSubEmulatorContainerTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java index 4709ed1bbd6..f7b35936197 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java @@ -17,7 +17,7 @@ public class DatastoreEmulatorContainerTest { @Rule // creatingDatastoreEmulatorContainer { public DatastoreEmulatorContainer emulator = new DatastoreEmulatorContainer( - DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:313.0.0") + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") ); // } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java index 766ce657bf0..4003ebdd342 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java @@ -20,7 +20,7 @@ public class FirestoreEmulatorContainerTest { @Rule - public FirestoreEmulatorContainer emulator = new FirestoreEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:313.0.0")); + public FirestoreEmulatorContainer emulator = new FirestoreEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators")); @Test public void testSimple() throws ExecutionException, InterruptedException { diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java index 2a0acaa14e1..3ea9f831d8e 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java @@ -33,7 +33,7 @@ public class PubSubEmulatorContainerTest { public static final String PROJECT_ID = "my-project-id"; @Rule - public PubSubEmulatorContainer emulator = new PubSubEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:313.0.0")); + public PubSubEmulatorContainer emulator = new PubSubEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators")); @Test public void testSimple() throws IOException { From a4ea01764c9b3792911dcf6cade3612969a9baeb Mon Sep 17 00:00:00 2001 From: Kirill Artamonov Date: Thu, 29 Oct 2020 13:26:56 +0100 Subject: [PATCH 1064/4969] Latest kafka container 5.4.3 (#3402) --- docs/modules/kafka.md | 15 +++------------ .../testcontainers/containers/KafkaContainer.java | 2 +- .../containers/KafkaContainerTest.java | 8 ++++---- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index d36273ac8e1..b74d4ef49bd 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -14,25 +14,16 @@ The following field in your JUnit test class will prepare a container running Ka [JUnit Rule](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:junitRule - + +The correspondence between Confluent Platform versions and Kafka versions can be seen [in Confluent documentation](https://docs.confluent.io/current/installation/versions-interoperability.html#cp-and-apache-kafka-compatibility) + Now your tests or any other process running on your machine can get access to running Kafka broker by using the following bootstrap server location: [Bootstrap Servers](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:getBootstrapServers - ## Options - -### Selecting Kafka version - -You can select a specific Confluent Platform Kafka docker image by passing it to the container's constructor: - -[Version Constructor](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:constructorWithVersion - - - -The correspondence between Confluent Platform versions and Kafka versions can be seen [in Confluent documentation](https://docs.confluent.io/current/installation/versions-interoperability.html#cp-and-apache-kafka-compatibility) ### Using external Zookeeper diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index ae44e4803a9..37f99bf970b 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -17,7 +17,7 @@ public class KafkaContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("confluentinc/cp-kafka"); - private static final String DEFAULT_TAG = "5.2.1"; + private static final String DEFAULT_TAG = "5.4.3"; private static final String STARTER_SCRIPT = "/testcontainers_start.sh"; diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 08b9fb6f856..4f721424bb6 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -24,12 +24,12 @@ public class KafkaContainerTest { - private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:5.2.1"); + private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:5.4.3"); private static final DockerImageName ZOOKEEPER_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-zookeeper:4.0.0"); // junitRule { @ClassRule - public static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.2.1")); + public static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3")); // } @Test @@ -45,7 +45,7 @@ public void testUsage() throws Exception { public void testUsageWithSpecificImage() throws Exception { try ( // constructorWithVersion { - KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.2.1")) + KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3")) // } ) { kafka.start(); @@ -61,7 +61,7 @@ public void testUsageWithSpecificImage() throws Exception { @Test public void testUsageWithVersion() throws Exception { try ( - KafkaContainer kafka = new KafkaContainer("5.2.1") + KafkaContainer kafka = new KafkaContainer("5.4.3") ) { kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); From e97fd3d0251e9f054052cd30009db6122c979210 Mon Sep 17 00:00:00 2001 From: DevilzOwn Date: Thu, 29 Oct 2020 17:58:47 +0530 Subject: [PATCH 1065/4969] Reduce severity of warning for failed auth config lookups (fixes #1399) (#3353) Co-authored-by: Prateek Bokade Co-authored-by: Richard North --- .../java/org/testcontainers/utility/RegistryAuthLocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index 32b49bd8172..846b62f1f25 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -145,7 +145,7 @@ private Optional lookupUncachedAuthConfig(String registryName, Docke return Optional.of(existingAuthConfig); } } catch (Exception e) { - log.warn("Failure when attempting to lookup auth config (dockerImageName: {}, configFile: {}. Falling back to docker-java default behaviour. Exception message: {}", + log.info("Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: {}, configFile: {}. Falling back to docker-java default behaviour. Exception message: {}", dockerImageName, configFile, e.getMessage()); From 18fec1dcf5ba43298cdc344bc70293c91f2af28f Mon Sep 17 00:00:00 2001 From: ae-govau Date: Thu, 29 Oct 2020 23:29:42 +1100 Subject: [PATCH 1066/4969] Correct documentation for ryuk image (#3383) Commit 7ba06573feb6561c6fc857cd5b53ff1449808da9 changed the default values in code, this commit updates the documentation to match. --- docs/features/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 8b12f8e8d54..e3ac0fb6ac3 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -32,7 +32,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **tinyimage.container.image = alpine:3.5** > Used by Testcontainers' core -> **vncrecorder.container.image = testcontainersofficial/vnc-recorder:1.1.0** +> **vncrecorder.container.image = testcontainers/vnc-recorder:1.1.0** > Used by VNC recorder in Testcontainers' Seleniun integration > **ambassador.container.image = richnorth/ambassador:latest** @@ -53,7 +53,7 @@ For more information, see the [official Docker documentation about "Registry as ## Customizing Ryuk resource reaper -> **ryuk.container.image = testcontainersofficial/ryuk:0.3.0** +> **ryuk.container.image = testcontainers/ryuk:0.3.0** > The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown > **ryuk.container.privileged = false** From 4a529f6aaeb1ec9f59068d70f45b7e558dabcbe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=C5=81ozi=C5=84ski?= Date: Thu, 29 Oct 2020 13:31:55 +0100 Subject: [PATCH 1067/4969] Fix use of HostPortWaitStrategy with Postgres container (fixes #3382) (#3403) --- .../org/testcontainers/containers/PostgreSQLContainer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 5a4abe6d0ee..6c16bb8fe61 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -5,10 +5,10 @@ import org.testcontainers.utility.DockerImageName; import java.time.Duration; -import java.util.HashSet; import java.util.Set; import static java.time.temporal.ChronoUnit.SECONDS; +import static java.util.Collections.singleton; /** * @author richardnorth @@ -63,7 +63,7 @@ public PostgreSQLContainer(final DockerImageName dockerImageName) { @NotNull @Override protected Set getLivenessCheckPorts() { - return new HashSet<>(getMappedPort(POSTGRESQL_PORT)); + return singleton(getMappedPort(POSTGRESQL_PORT)); } @Override From ca74b044e222e725c72083a1d5d7d70d17a04ecf Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 29 Oct 2020 13:12:50 +0000 Subject: [PATCH 1068/4969] Refactor TestcontainersConfiguration to allow config by env var (#3411) --- .../utility/TestcontainersConfiguration.java | 252 +++++++++++++----- .../TestcontainersConfigurationTest.java | 86 ++++-- 2 files changed, 258 insertions(+), 80 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 5b89140fd61..b3c8e88a328 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -1,15 +1,17 @@ package org.testcontainers.utility; import com.google.common.annotations.VisibleForTesting; -import lombok.AccessLevel; +import com.google.common.collect.ImmutableMap; import lombok.Data; import lombok.Getter; import lombok.NonNull; -import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.exception.ExceptionUtils; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.testcontainers.UnstableAPI; import java.io.File; @@ -20,22 +22,57 @@ import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; +import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; /** - * Provides a mechanism for fetching configuration/defaults from the classpath. + * Provides a mechanism for fetching configuration/default settings. + *

+ * Configuration may be provided in: + *

    + *
  • A file in the user's home directory named .testcontainers.properties
  • + *
  • A file in the classpath named testcontainers.properties
  • + *
  • Environment variables
  • + *
+ *

+ * Note that, if using environment variables, property names are in upper case separated by underscores, preceded by + * TESTCONTAINERS_. */ @Data @Slf4j -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class TestcontainersConfiguration { private static String PROPERTIES_FILE_NAME = "testcontainers.properties"; - private static File ENVIRONMENT_CONFIG_FILE = new File(System.getProperty("user.home"), "." + PROPERTIES_FILE_NAME); + private static File USER_CONFIG_FILE = new File(System.getProperty("user.home"), "." + PROPERTIES_FILE_NAME); + + private static final String AMBASSADOR_IMAGE = "richnorth/ambassador"; + private static final String SOCAT_IMAGE = "alpine/socat"; + private static final String VNC_RECORDER_IMAGE = "testcontainers/vnc-recorder"; + private static final String COMPOSE_IMAGE = "docker/compose"; + private static final String ALPINE_IMAGE = "alpine"; + private static final String RYUK_IMAGE = "testcontainers/ryuk"; + private static final String KAFKA_IMAGE = "confluentinc/cp-kafka"; + private static final String PULSAR_IMAGE = "apachepulsar/pulsar"; + private static final String LOCALSTACK_IMAGE = "localstack/localstack"; + private static final String SSHD_IMAGE = "testcontainers/sshd"; + + private static final ImmutableMap CONTAINER_MAPPING = ImmutableMap.builder() + .put(DockerImageName.parse(AMBASSADOR_IMAGE), "ambassador.container.image") + .put(DockerImageName.parse(SOCAT_IMAGE), "socat.container.image") + .put(DockerImageName.parse(VNC_RECORDER_IMAGE), "vncrecorder.container.image") + .put(DockerImageName.parse(COMPOSE_IMAGE), "compose.container.image") + .put(DockerImageName.parse(ALPINE_IMAGE), "tinyimage.container.image") + .put(DockerImageName.parse(RYUK_IMAGE), "ryuk.container.image") + .put(DockerImageName.parse(KAFKA_IMAGE), "kafka.container.image") + .put(DockerImageName.parse(PULSAR_IMAGE), "pulsar.container.image") + .put(DockerImageName.parse(LOCALSTACK_IMAGE), "localstack.container.image") + .put(DockerImageName.parse(SSHD_IMAGE), "sshd.container.image") + .build(); @Getter(lazy = true) private static final TestcontainersConfiguration instance = loadConfiguration(); @@ -47,163 +84,234 @@ static AtomicReference getInstanceField() { return (AtomicReference) (Object) instance; } - @Getter(AccessLevel.NONE) - private final Properties environmentProperties; + private final Properties userProperties; + private final Properties classpathProperties; + private final Map environment; - private final Properties properties = new Properties(); - - TestcontainersConfiguration(Properties environmentProperties, Properties classpathProperties) { - this.environmentProperties = environmentProperties; - - this.properties.putAll(classpathProperties); - this.properties.putAll(environmentProperties); - } - - private DockerImageName getImage(final String key, final String defaultValue) { - return DockerImageName - .parse(properties.getProperty(key, defaultValue).trim()) - .asCompatibleSubstituteFor(defaultValue); + TestcontainersConfiguration(Properties userProperties, Properties classpathProperties, final Map environment) { + this.userProperties = userProperties; + this.classpathProperties = classpathProperties; + this.environment = environment; } @Deprecated public String getAmbassadorContainerImage() { - return getAmbassadorContainerDockerImageName().asCanonicalNameString(); - } - - @Deprecated - public DockerImageName getAmbassadorContainerDockerImageName() { - return getImage("ambassador.container.image", "richnorth/ambassador:latest"); + return getImage(AMBASSADOR_IMAGE).asCanonicalNameString(); } @Deprecated public String getSocatContainerImage() { - return getSocatDockerImageName().asCanonicalNameString(); + return getImage(SOCAT_IMAGE).asCanonicalNameString(); } public DockerImageName getSocatDockerImageName() { - return getImage("socat.container.image", "alpine/socat:latest"); + return getImage(SOCAT_IMAGE); } @Deprecated public String getVncRecordedContainerImage() { - return getVncDockerImageName().asCanonicalNameString(); + return getImage(VNC_RECORDER_IMAGE).asCanonicalNameString(); } public DockerImageName getVncDockerImageName() { - return getImage("vncrecorder.container.image", "testcontainers/vnc-recorder:1.1.0"); + return getImage(VNC_RECORDER_IMAGE); } @Deprecated public String getDockerComposeContainerImage() { - return getDockerComposeDockerImageName().asCanonicalNameString(); + return getImage(COMPOSE_IMAGE).asCanonicalNameString(); } public DockerImageName getDockerComposeDockerImageName() { - return getImage("compose.container.image", "docker/compose:1.24.1"); + return getImage(COMPOSE_IMAGE); } @Deprecated public String getTinyImage() { - return getTinyDockerImageName().asCanonicalNameString(); + return getImage(ALPINE_IMAGE).asCanonicalNameString(); } public DockerImageName getTinyDockerImageName() { - return getImage("tinyimage.container.image", "alpine:3.5"); + return getImage(ALPINE_IMAGE); } public boolean isRyukPrivileged() { - return Boolean.parseBoolean((String) properties.getOrDefault("ryuk.container.privileged", "false")); + return Boolean + .parseBoolean(getEnvVarOrProperty("ryuk.container.privileged", "false")); } @Deprecated public String getRyukImage() { - return getRyukDockerImageName().asCanonicalNameString(); + return getImage(RYUK_IMAGE).asCanonicalNameString(); } public DockerImageName getRyukDockerImageName() { - return getImage("ryuk.container.image", "testcontainers/ryuk:0.3.0"); + return getImage(RYUK_IMAGE); } @Deprecated public String getSSHdImage() { - return getSSHdDockerImageName().asCanonicalNameString(); + return getImage(SSHD_IMAGE).asCanonicalNameString(); } public DockerImageName getSSHdDockerImageName() { - return getImage("sshd.container.image", "testcontainers/sshd:1.0.0"); + return getImage(SSHD_IMAGE); } public Integer getRyukTimeout() { - return Integer.parseInt((String) properties.getOrDefault("ryuk.container.timeout", "30")); + return Integer.parseInt(getEnvVarOrProperty("ryuk.container.timeout", "30")); } @Deprecated public String getKafkaImage() { - return getKafkaDockerImageName().asCanonicalNameString(); + return getImage(KAFKA_IMAGE).asCanonicalNameString(); } public DockerImageName getKafkaDockerImageName() { - return getImage("kafka.container.image", "confluentinc/cp-kafka"); + return getImage(KAFKA_IMAGE); + } + + + @Deprecated + public String getOracleImage() { + return getEnvVarOrUserProperty("oracle.container.image", null); } @Deprecated public String getPulsarImage() { - return getPulsarDockerImageName().asCanonicalNameString(); + return getImage(PULSAR_IMAGE).asCanonicalNameString(); } public DockerImageName getPulsarDockerImageName() { - return getImage("pulsar.container.image", "apachepulsar/pulsar"); + return getImage(PULSAR_IMAGE); } @Deprecated public String getLocalStackImage() { - return getLocalstackDockerImageName().asCanonicalNameString(); + return getImage(LOCALSTACK_IMAGE).asCanonicalNameString(); } public DockerImageName getLocalstackDockerImageName() { - return getImage("localstack.container.image", "localstack/localstack"); + return getImage(LOCALSTACK_IMAGE); } + public boolean isDisableChecks() { - return Boolean.parseBoolean((String) environmentProperties.getOrDefault("checks.disable", "false")); + return Boolean.parseBoolean(getEnvVarOrUserProperty("checks.disable", "false")); } @UnstableAPI public boolean environmentSupportsReuse() { - return Boolean.parseBoolean((String) environmentProperties.getOrDefault("testcontainers.reuse.enable", "false")); + // specifically not supported as an environment variable or classpath property + return Boolean.parseBoolean(getEnvVarOrUserProperty("testcontainers.reuse.enable", "false")); } public String getDockerClientStrategyClassName() { - return (String) environmentProperties.get("docker.client.strategy"); + return getEnvVarOrUserProperty("docker.client.strategy", null); } public String getTransportType() { - return properties.getProperty("transport.type", "okhttp"); + return getEnvVarOrProperty("transport.type", "okhttp"); } public Integer getImagePullPauseTimeout() { - return Integer.parseInt((String) properties.getOrDefault("pull.pause.timeout", "30")); + return Integer.parseInt(getEnvVarOrProperty("pull.pause.timeout", "30")); } - @Synchronized + @Nullable + @Contract("_, !null, _ -> !null") + private String getConfigurable(@NotNull final String propertyName, @Nullable final String defaultValue, Properties... propertiesSources) { + String envVarName = propertyName.replaceAll("\\.", "_").toUpperCase(); + if (!envVarName.startsWith("TESTCONTAINERS_")) { + envVarName = "TESTCONTAINERS_" + envVarName; + } + + if (environment.containsKey(envVarName)) { + return environment.get(envVarName); + } + + for (final Properties properties : propertiesSources) { + if (properties.get(propertyName) != null) { + return (String) properties.get(propertyName); + } + } + + return defaultValue; + } + + /** + * Gets a configured setting from an environment variable (if present) or a configuration file property otherwise. + * The configuration file will be the .testcontainers.properties file in the user's home directory or + * a testcontainers.properties found on the classpath. + * + * @param propertyName name of configuration file property (dot-separated lower case) + * @return the found value, or null if not set + */ + @Nullable + @Contract("_, !null -> !null") + public String getEnvVarOrProperty(@NotNull final String propertyName, @Nullable final String defaultValue) { + return getConfigurable(propertyName, defaultValue, userProperties, classpathProperties); + } + + /** + * Gets a configured setting from an environment variable (if present) or a configuration file property otherwise. + * The configuration file will be the .testcontainers.properties file in the user's home directory. + * + * @param propertyName name of configuration file property (dot-separated lower case) + * @return the found value, or null if not set + */ + @Nullable + @Contract("_, !null -> !null") + public String getEnvVarOrUserProperty(@NotNull final String propertyName, @Nullable final String defaultValue) { + return getConfigurable(propertyName, defaultValue, userProperties); + } + + /** + * Gets a configured setting from a the user's configuration file. + * The configuration file will be the .testcontainers.properties file in the user's home directory. + * + * @param propertyName name of configuration file property (dot-separated lower case) + * @return the found value, or null if not set + */ + @Nullable + @Contract("_, !null -> !null") + public String getUserProperty(@NotNull final String propertyName, @Nullable final String defaultValue) { + return getConfigurable(propertyName, defaultValue); + } + + @Deprecated + public Properties getProperties() { + return Stream.of(userProperties, classpathProperties) + .reduce(new Properties(), (a, b) -> { + a.putAll(b); + return a; + }); + } + + @Deprecated public boolean updateGlobalConfig(@NonNull String prop, @NonNull String value) { + return updateUserConfig(prop, value); + } + + @Synchronized + public boolean updateUserConfig(@NonNull String prop, @NonNull String value) { try { - if (value.equals(environmentProperties.get(prop))) { + if (value.equals(userProperties.get(prop))) { return false; } - environmentProperties.setProperty(prop, value); + userProperties.setProperty(prop, value); - ENVIRONMENT_CONFIG_FILE.createNewFile(); - try (OutputStream outputStream = new FileOutputStream(ENVIRONMENT_CONFIG_FILE)) { - environmentProperties.store(outputStream, "Modified by Testcontainers"); + USER_CONFIG_FILE.createNewFile(); + try (OutputStream outputStream = new FileOutputStream(USER_CONFIG_FILE)) { + userProperties.store(outputStream, "Modified by Testcontainers"); } // Update internal state only if environment config was successfully updated - properties.setProperty(prop, value); + userProperties.setProperty(prop, value); return true; } catch (Exception e) { - log.debug("Can't store environment property {} in {}", prop, ENVIRONMENT_CONFIG_FILE); + log.debug("Can't store environment property {} in {}", prop, USER_CONFIG_FILE); return false; } } @@ -211,7 +319,7 @@ public boolean updateGlobalConfig(@NonNull String prop, @NonNull String value) { @SneakyThrows(MalformedURLException.class) private static TestcontainersConfiguration loadConfiguration() { return new TestcontainersConfiguration( - readProperties(ENVIRONMENT_CONFIG_FILE.toURI().toURL()), + readProperties(USER_CONFIG_FILE.toURI().toURL()), Stream .of( TestcontainersConfiguration.class.getClassLoader(), @@ -223,8 +331,8 @@ private static TestcontainersConfiguration loadConfiguration() { .reduce(new Properties(), (a, b) -> { a.putAll(b); return a; - }) - ); + }), + System.getenv()); } private static Properties readProperties(URL url) { @@ -239,4 +347,24 @@ private static Properties readProperties(URL url) { } return properties; } + + private DockerImageName getImage(final String defaultValue) { + return getConfiguredSubstituteImage(DockerImageName.parse(defaultValue)); + } + + DockerImageName getConfiguredSubstituteImage(DockerImageName original) { + for (final Map.Entry entry : CONTAINER_MAPPING.entrySet()) { + if (original.isCompatibleWith(entry.getKey())) { + return + Optional.ofNullable(entry.getValue()) + .map(propertyName -> getEnvVarOrProperty(propertyName, null)) + .map(String::valueOf) + .map(String::trim) + .map(DockerImageName::parse) + .orElse(original) + .asCompatibleSubstituteFor(original); + } + } + return original; + } } diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index ccd68fbd984..e48a2a6fdf9 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -1,57 +1,107 @@ package org.testcontainers.utility; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import org.junit.Before; +import org.junit.Test; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; import java.util.UUID; -import org.junit.Test; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class TestcontainersConfigurationTest { - final Properties environmentProperties = new Properties(); + private Properties userProperties; + private Properties classpathProperties; + private Map environment; - final Properties classpathProperties = new Properties(); + @Before + public void setUp() { + userProperties = new Properties(); + classpathProperties = new Properties(); + environment = new HashMap<>(); + } @Test - public void shouldReadChecksFromEnvironmentOnly() { + public void shouldNotReadChecksFromClasspathProperties() { assertFalse("checks enabled by default", newConfig().isDisableChecks()); classpathProperties.setProperty("checks.disable", "true"); assertFalse("checks are not affected by classpath properties", newConfig().isDisableChecks()); + } + + @Test + public void shouldReadChecksFromUserProperties() { + assertFalse("checks enabled by default", newConfig().isDisableChecks()); - environmentProperties.setProperty("checks.disable", "true"); - assertTrue("checks disabled", newConfig().isDisableChecks()); + userProperties.setProperty("checks.disable", "true"); + assertTrue("checks disabled via user properties", newConfig().isDisableChecks()); } @Test - public void shouldReadDockerClientStrategyFromEnvironmentOnly() { + public void shouldReadChecksFromEnvironment() { + assertFalse("checks enabled by default", newConfig().isDisableChecks()); + + userProperties.remove("checks.disable"); + environment.put("TESTCONTAINERS_CHECKS_DISABLE", "true"); + assertTrue("checks disabled via env var", newConfig().isDisableChecks()); + } + + @Test + public void shouldNotReadDockerClientStrategyFromClasspathProperties() { String currentValue = newConfig().getDockerClientStrategyClassName(); classpathProperties.setProperty("docker.client.strategy", UUID.randomUUID().toString()); assertEquals("Docker client strategy is not affected by classpath properties", currentValue, newConfig().getDockerClientStrategyClassName()); + } + + @Test + public void shouldReadDockerClientStrategyFromUserProperties() { + userProperties.setProperty("docker.client.strategy", "foo"); + assertEquals("Docker client strategy is changed by user property", "foo", newConfig().getDockerClientStrategyClassName()); + } - environmentProperties.setProperty("docker.client.strategy", "foo"); - assertEquals("Docker client strategy is changed", "foo", newConfig().getDockerClientStrategyClassName()); + @Test + public void shouldReadDockerClientStrategyFromEnvironment() { + userProperties.remove("docker.client.strategy"); + environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "foo"); + assertEquals("Docker client strategy is changed by env var", "foo", newConfig().getDockerClientStrategyClassName()); } @Test - public void shouldReadReuseFromEnvironmentOnly() { + public void shouldNotReadReuseFromClasspathProperties() { assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); classpathProperties.setProperty("testcontainers.reuse.enable", "true"); assertFalse("reuse is not affected by classpath properties", newConfig().environmentSupportsReuse()); + } - environmentProperties.setProperty("testcontainers.reuse.enable", "true"); - assertTrue("reuse enabled", newConfig().environmentSupportsReuse()); + @Test + public void shouldReadReuseFromUserProperties() { + assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); + + userProperties.setProperty("testcontainers.reuse.enable", "true"); + assertTrue("reuse enabled via user property", newConfig().environmentSupportsReuse()); + } + @Test + public void shouldReadReuseFromEnvironment() { + assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); - environmentProperties.setProperty("ryuk.container.image", " testcontainersofficial/ryuk:0.3.0 "); - assertEquals("trailing whitespace was not removed from image name property", "testcontainersofficial/ryuk:0.3.0",newConfig().getRyukDockerImageName().asCanonicalNameString()); + userProperties.remove("testcontainers.reuse.enable"); + environment.put("TESTCONTAINERS_REUSE_ENABLE", "true"); + assertTrue("reuse enabled via env var", newConfig().environmentSupportsReuse()); + } + @Test + public void shouldTrimImageNames() { + userProperties.setProperty("ryuk.container.image", " testcontainersofficial/ryuk:0.3.0 "); + assertEquals("trailing whitespace was not removed from image name property", "testcontainersofficial/ryuk:0.3.0",newConfig().getRyukImage()); } private TestcontainersConfiguration newConfig() { - return new TestcontainersConfiguration(environmentProperties, classpathProperties); + return new TestcontainersConfiguration(userProperties, classpathProperties, environment); } } From b94da0a425ad404a316363bce3241f07233479f2 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 29 Oct 2020 18:22:06 +0000 Subject: [PATCH 1069/4969] Update sponsors (#3410) Co-authored-by: Fedor Korotkov --- docs/index.md | 61 ++++++++++++++++++++--------- docs/sponsor_logos/cirrus_labs.jpg | Bin 0 -> 3204 bytes docs/sponsor_logos/jooq.jpg | Bin 0 -> 3559 bytes docs/sponsor_logos/vivy.png | Bin 0 -> 4170 bytes 4 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 docs/sponsor_logos/cirrus_labs.jpg create mode 100644 docs/sponsor_logos/jooq.jpg create mode 100644 docs/sponsor_logos/vivy.png diff --git a/docs/index.md b/docs/index.md index 131a9074bfd..28ca2453993 100644 --- a/docs/index.md +++ b/docs/index.md @@ -90,6 +90,48 @@ testImplementation('org.testcontainers:mysql') //no version specified These libraries in particular seem to be especially prone to conflicts with test code/application under test code. As such, **these libraries are 'shaded' into the core testcontainers JAR** and relocated under `org.testcontainers.shaded` to prevent class conflicts. +## Sponsors + +Testcontainers is on Github Sponsors! Please consider sponsoring us to sustain the project and help us improve it further. + + + +A huge thank you to our sponsors: + +### Bronze sponsors + +

+ + + + + +### Backers + +* [Philip Riecks (@rieckpil)](https://github.com/rieckpil) +* [Karl Heinz Marbaise (@khmarbaise)](https://github.com/khmarbaise) +* [Sascha Frinken (@sascha-frinken)](https://github.com/sascha-frinken) +* [Christoph Dreis (@dreis2211)](https://github.com/dreis2211) +* [Pascal Zwick (@pas2al)](https://github.com/pas2al) +* [Nikita Zhevnitskiy (@zhenik)](https://github.com/zhenik) +* [Bas Stoker (@bastoker)](https://github.com/bastoker) + ## Who is using Testcontainers? * [ZeroTurnaround](https://zeroturnaround.com) - Testing of the Java Agents, micro-services, Selenium browser automation @@ -121,25 +163,6 @@ testImplementation('org.testcontainers:mysql') //no version specified * [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) * [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS -## Sponsors - -Testcontainers is on Github Sponsors! Please consider sponsoring us to sustain the project and help us improve it further. - - - -### Backers - -A huge thank you to our backers: - -* [Philip Riecks (@rieckpil)](https://github.com/rieckpil) -* [Karl Heinz Marbaise (@khmarbaise)](https://github.com/khmarbaise) -* [Sascha Frinken (@sascha-frinken)](https://github.com/sascha-frinken) -* [Lukas Eder (@lukaseder)](https://github.com/lukaseder) -* [Fedor Korotkov (@fkorotkov)](https://github.com/fkorotkov) -* [Christoph Dreis (@dreis2211)](https://github.com/dreis2211) -* [Pascal Zwick (@pas2al)](https://github.com/pas2al) -* [Nikita Zhevnitskiy (@zhenik)](https://github.com/zhenik) - ## License diff --git a/docs/sponsor_logos/cirrus_labs.jpg b/docs/sponsor_logos/cirrus_labs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3bec84f0a22693cde05118fa3c241ed9e89cf389 GIT binary patch literal 3204 zcmd6odpOkF8pqd|F&9Mc#x)I@5{hxD6GIMC$8kxaY12(ECA%U+F{o68bRo(m_Y%{% z#x9i0D4kG>klTboE|c4j#_zXh?|q(qcDw%A=RD`x&wiihyPjvgYprLk&wAIpUZfN0 z2Il}Ci^XAu@i-igK){QL$*d3)6%`{&NlVD6D5|NdC@L$j($LjfwR$~CS($9ScKwEp z6beO6Ym=#o{uW&Wiav@!Ac%>IDXdtbps%j1uK!;fQVS&Upb0dgQLBNFBnmBwLh4bO z0HB0XKO6YBp@h&FVJr?$5D{GogivU-5C$zQjKK(Ih6=_2Mp9TxeWL|d+HpT_^>G>f zh=eb2`P5|eHwr(|Yj=j7()-@R8{Qd(AC z@vyS$XQ;STEwfn?w`EqmZZn~0nS zWk8en6VlH_e+(${elgtO9UDLKlCggkG|y$xo}k08EB+f_E=+g?0J}k02MXkQFCQKnW9*w;>|ZaO;%lA z=|cvY(SJ-iNrVdCMw}7VdQ+@TPwr zD8Dt>y-Djlsq9T8JUQf|)C9}VsV>`a!#t~5m9O@{4++AWqH zg_ouRK^}Wq_!=gbcS4W$xn?vdt_NpNHvDMg-h!LP5)LOG+$L`FeYk1OpOb= z_Od@z{DfKA{4Tl|`@M)s_l^#dgGw{)AGLw71_It8U_0P#|K_h#P-T51sK~c`$?sg4 z=fCRwEN)9U**_p^jhf5kGXq%=%G=Mmcf2H-Hxn#Lb_m6uuyaE|6yp_xYaA*F_p9(N z*yx2R$ZJ^(J{#1xFhTzFM$7psUMCqGJ4I3RM*ni_{`dirCoy3_8gda_ZXMN!I6|vN zK#k9L>E~b-Z+8jtdC6xwuZub=Z%3Ul#R1f8hIsiSCZ{LA8ee=d;qg>!{u1c}TvHg5 zb7qA1Lw(y=FR9{{&TYzO-v?LDKDoh4fB>#N1$^rI)Nzt){bRUG7INL0wyU5>jx22Hj!z#6Y7-uAwBZ{Ht*m7`SdyJs3jzl(r@Ej<5a zv5-6%QvtQ&I!axdJf_p=6>yZP;BgDl_}&OOH`7ovyKyWXlIr7_tGTy%s571h5B4o7 z%-Qn^{=6($x?e7?R+XYXw5O?a4Bu0es5FxyA^PnK^JaSZ zY~Y|@NQZ5y`k~ayQ`~5*TYM|poapTG%E&{AuPt1h^CGE3pEG==xkRfI#U9^H9k8Vv z!}MN8zioy@ay~Pc@gGMPER%GWF%mlhV^Y9kO7xP~Zyf)pg#~w}brS*$=^fk4%d9nZ zrF;|^LL}_LiCTUWldgt&q?ESrky+!1j-3Mtz;mnRE4%|@$P)|83qz^!eOp0ND%}{O zs_8mzAs#%oZAPtw1R2NRaSEmA(JE9ip+% zG>#HoLn7DtLW!G(FZ#v#tPIhXwEyhc!RNOifUyFEGOf-y&Nnj`7t>)_(d=Cy0;mQE z=&LhVJJRMM6IwhDhj|IoF)F_NJ4VY31T0Lq;<{#C8q|(fAs{^&0aF866G_z`Dic-|p<8MhO1VQ*df7*KVa(QWBa zBB#O9NXu@;u>^05v!PvQ=oQ~!*hVz6*u!Yo%^>{d_`4&WflQ^Z3jDW<{$Im~y!#Px CQQ(vS literal 0 HcmV?d00001 diff --git a/docs/sponsor_logos/jooq.jpg b/docs/sponsor_logos/jooq.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a64f773d615adaa24276c8e47bdd6da063f7b2e GIT binary patch literal 3559 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 literal 0 HcmV?d00001 From 0ac96892fbd9fa91e586658338ef2d22cb5db294 Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Fri, 30 Oct 2020 17:23:16 +0100 Subject: [PATCH 1070/4969] Presto: Bump default Presto version (used in deprecated constructor and unversioned JDBC URL) from 329 to 344 (#3312) --- docs/modules/databases/jdbc.md | 2 +- .../java/org/testcontainers/containers/PrestoContainer.java | 2 +- .../src/test/java/org/testcontainers/PrestoTestImages.java | 4 ++-- .../org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 21393455a9f..65db9aaf07f 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -41,7 +41,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database #### Using Presto -`jdbc:tc:presto:329://localhost/memory/default` +`jdbc:tc:presto:344://localhost/memory/default` ### Using a classpath init script diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index e4934693d14..54cc6758562 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -18,7 +18,7 @@ public class PrestoContainer> extends JdbcDat public static final String NAME = "presto"; private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("prestosql/presto"); public static final String IMAGE = "prestosql/presto"; - public static final String DEFAULT_TAG = "329"; + public static final String DEFAULT_TAG = "344"; public static final Integer PRESTO_PORT = 8080; diff --git a/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java b/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java index 1b4e449c99f..a257500576c 100644 --- a/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java +++ b/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java @@ -3,6 +3,6 @@ import org.testcontainers.utility.DockerImageName; public interface PrestoTestImages { - DockerImageName PRESTO_TEST_IMAGE = DockerImageName.parse("prestosql/presto:329"); - DockerImageName PRESTO_PREVIOUS_VERSION_TEST_IMAGE = DockerImageName.parse("prestosql/presto:328"); + DockerImageName PRESTO_TEST_IMAGE = DockerImageName.parse("prestosql/presto:344"); + DockerImageName PRESTO_PREVIOUS_VERSION_TEST_IMAGE = DockerImageName.parse("prestosql/presto:343"); } diff --git a/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java b/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java index 88939c62939..d1a64c92aaa 100644 --- a/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java +++ b/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java @@ -15,7 +15,7 @@ public class PrestoJDBCDriverTest extends AbstractJDBCDriverTest { public static Iterable data() { return asList( new Object[][]{ - {"jdbc:tc:presto:329://hostname/", EnumSet.of(Options.PmdKnownBroken)}, + {"jdbc:tc:presto:344://hostname/", EnumSet.of(Options.PmdKnownBroken)}, }); } } From e64db24003e05a642b5f3d8ce0cb084fc6ac7adb Mon Sep 17 00:00:00 2001 From: Or Noyman Date: Fri, 30 Oct 2020 18:23:55 +0200 Subject: [PATCH 1071/4969] Vault: add a fluent API for configuring Vault's logging level (#2231) --- .../org/testcontainers/vault/VaultContainer.java | 12 ++++++++++++ .../org/testcontainers/vault/VaultLogLevel.java | 14 ++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java index b0c8a2a40e3..f47818d8c7d 100644 --- a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java +++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import static com.github.dockerjava.api.model.Capability.IPC_LOCK; @@ -106,6 +107,17 @@ public SELF withVaultPort(int port) { return self(); } + /** + * Sets the logging level for the Vault server in the container. + * Logs can be consumed through {@link #withLogConsumer(Consumer)}. + * + * @param level the logging level to set for Vault. + * @return this + */ + public SELF withLogLevel(VaultLogLevel level) { + return withEnv("VAULT_LOG_LEVEL", level.config); + } + /** * Pre-loads secrets into Vault container. User may specify one or more secrets and all will be added to each path * that is specified. Thus this can be called more than once for multiple paths to be added to Vault. diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java new file mode 100644 index 00000000000..58b22f975ff --- /dev/null +++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java @@ -0,0 +1,14 @@ +package org.testcontainers.vault; + +/** + * Vault preset of logging levels. + */ +public enum VaultLogLevel { + Trace("trace"), Debug("debug"), Info("info"), Warn("warn"), Error("err"); + + public final String config; + + VaultLogLevel(String config) { + this.config = config; + } +} From 30c29905babb9fb394be697f2c576be9756a71e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:25:54 +0000 Subject: [PATCH 1072/4969] Bump assertj-core from 3.17.2 to 3.18.0 in /modules/vault (#3384) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.17.2 to 3.18.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.17.2...assertj-core-3.18.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 6d862eeba2c..caddc81d3a7 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.1' - testCompile 'org.assertj:assertj-core:3.17.2' + testCompile 'org.assertj:assertj-core:3.18.0' } From f9f2c8369d4af951197bcbde0bf70397613f4d05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:26:09 +0000 Subject: [PATCH 1073/4969] Bump assertj-core from 3.17.2 to 3.18.0 in /modules/neo4j (#3385) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.17.2 to 3.18.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.17.2...assertj-core-3.18.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index da90a493a01..8d7f59e564e 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.17.2' + testCompile 'org.assertj:assertj-core:3.18.0' } From 4ec423484658eabc1b60f6b66c36005c7e36e7b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:26:31 +0000 Subject: [PATCH 1074/4969] Bump assertj-core from 3.17.2 to 3.18.0 in /modules/junit-jupiter (#3386) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.17.2 to 3.18.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.17.2...assertj-core-3.18.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 61594d9842b..321ac8fa82e 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.5.13') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.17.2' + testCompile 'org.assertj:assertj-core:3.18.0' testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' testRuntime 'org.postgresql:postgresql:42.2.18' From 6107d553d7fd74d97af2da9220d43ddee0834a8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:26:46 +0000 Subject: [PATCH 1075/4969] Bump mockito-core from 3.5.13 to 3.5.15 in /modules/junit-jupiter (#3387) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.13 to 3.5.15. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.13...v3.5.15) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 321ac8fa82e..7986c067c89 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.13' - testCompile ('org.mockito:mockito-core:3.5.13') { + testCompile ('org.mockito:mockito-core:3.5.15') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.18.0' From ef899a2ce5c43b890ab26ef32e4f7a33959ed4e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 31 Oct 2020 09:59:52 +0000 Subject: [PATCH 1076/4969] Bump s3 from 2.15.9 to 2.15.14 in /modules/localstack (#3388) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 418344b82f2..908f87de07d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.884' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.15.9' + testCompile 'software.amazon.awssdk:s3:2.15.14' } From 8d1a723617aecda6040bcc9201fb009c2dd9fff9 Mon Sep 17 00:00:00 2001 From: Kirill Artamonov Date: Sat, 31 Oct 2020 15:39:45 +0100 Subject: [PATCH 1077/4969] Bump Python mkdocs tool dependency to address CVE-2019-10906 (#3379) Co-authored-by: Richard North --- Pipfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipfile.lock b/Pipfile.lock index 852b507f886..899f8c82170 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -28,7 +28,7 @@ "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" ], - "version": "==2.10" + "version": "==2.11.2" }, "livereload": { "hashes": [ From 44e8e9ab279cad2cd9d0c9fc5bb6e7799c409999 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Nov 2020 19:19:08 +0000 Subject: [PATCH 1078/4969] Image substitution (#3102) * Refactor Testcontainers configuration to allow config by env var * Add Image substitution mechanism Builds upon #3021 and #3411: * adds a pluggable image substitution mechanism using ServiceLoader, enabling users to perform custom substitution/auditing of images being used by their tests * provides a default implementation that behaves similarly to legacy `TestcontainersConfiguration` approach (`testcontainers.properties`) Notes: * behaviour is similar but not quite identical to `TestcontainersConfiguration`: use of a configured custom image for, e.g. Kafka/Pulsar that does not have a tag specified causes the substitution to take effect for all usages. It seems very unlikely that people would be using a mix of the config file image overrides in some places _and_ specific images specified in code in others. * Duplication of default image names in modules vs `TestcontainersConfiguration` class is intentional: specifying image overrides in `testcontainers.properties` should be removed in the future. * ~Add log deprecation warnings when `testcontainers.properties` image overrides are used.~ Defer to a future release? * Remove extraneous change * Un-ignore docs example test by implementing a 'reversing' image name substitutor * Use configuration, not service loader, to select an ImageNameSubstitutor * Add check for order of config setting precedence * Extract classpath scanner and support finding of multiple resources * Introduce deterministic merging of classpath properties files * Update docs * Update docs * Remove service loader reference * Chain substitution through default and configured implementations * Small tweaks following review * Fix test compile error * Add UnstableAPI annotation * Move TestSpecificImageNameSubstitutor back to original package and remove duplicate use of default substitutor --- .../testcontainers/DockerClientFactory.java | 11 +- .../containers/DockerComposeContainer.java | 5 +- .../containers/GenericContainer.java | 6 +- .../containers/PortForwardingContainer.java | 6 +- .../containers/SocatContainer.java | 8 +- .../containers/VncRecordingContainer.java | 4 +- .../DockerClientProviderStrategy.java | 2 +- .../images/RemoteDockerImage.java | 10 +- .../utility/ClasspathScanner.java | 59 ++++++++ ...ConfigurationFileImageNameSubstitutor.java | 44 ++++++ .../utility/DefaultImageNameSubstitutor.java | 35 +++++ .../utility/ImageNameSubstitutor.java | 130 ++++++++++++++++++ .../utility/ResourceReaper.java | 4 +- .../utility/TestcontainersConfiguration.java | 68 +++------ .../DockerClientFactoryTest.java | 9 +- .../java/org/testcontainers/TestImages.java | 3 +- .../utility/AuthenticatedImagePullTest.java | 26 ++-- .../utility/ClasspathScannerTest.java | 114 +++++++++++++++ .../DefaultImageNameSubstitutorTest.java | 38 +++++ .../DockerImageNameCompatibilityTest.java | 3 +- .../utility/FakeImageSubstitutor.java | 13 ++ .../utility/ImageNameSubstitutorTest.java | 75 ++++++++++ .../TestcontainersConfigurationTest.java | 63 +++++++++ .../test/resources/expectedClasspathFile.txt | 1 + docs/examples/junit4/generic/build.gradle | 3 + .../generic/ExampleImageNameSubstitutor.java | 24 ++++ .../generic/ImageNameSubstitutionTest.java | 48 +++++++ .../TestSpecificImageNameSubstitutor.java | 26 ++++ .../src/test/resources/logback-test.xml | 14 ++ .../test/resources/testcontainers.properties | 1 + docs/features/configuration.md | 45 ++++-- docs/features/image_name_substitution.md | 117 ++++++++++++++++ docs/features/pull_rate_limiting.md | 19 +++ .../containers/KafkaContainer.java | 5 +- .../containers/KafkaContainerTest.java | 2 +- .../localstack/LocalStackContainer.java | 5 +- .../containers/OracleContainer.java | 3 +- .../containers/PulsarContainer.java | 5 +- .../spock/SpockTestImages.groovy | 5 +- 39 files changed, 936 insertions(+), 123 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/utility/ClasspathScanner.java create mode 100644 core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java create mode 100644 core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java create mode 100644 core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java create mode 100644 core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java create mode 100644 core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java create mode 100644 core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java create mode 100644 core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java create mode 100644 core/src/test/resources/expectedClasspathFile.txt create mode 100644 docs/examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java create mode 100644 docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java create mode 100644 docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java create mode 100644 docs/examples/junit4/generic/src/test/resources/logback-test.xml create mode 100644 docs/examples/junit4/generic/src/test/resources/testcontainers.properties create mode 100644 docs/features/image_name_substitution.md create mode 100644 docs/features/pull_rate_limiting.md diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 571b18fbcce..d44cd3b5b6f 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -25,6 +25,8 @@ import org.testcontainers.dockerclient.TransportConfig; import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; import org.testcontainers.utility.ComparableVersion; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.ImageNameSubstitutor; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.ResourceReaper; import org.testcontainers.utility.TestcontainersConfiguration; @@ -61,7 +63,7 @@ public class DockerClientFactory { TESTCONTAINERS_SESSION_ID_LABEL, SESSION_ID ); - private static final String TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyDockerImageName().asCanonicalNameString(); + private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.5"); private static DockerClientFactory instance; // Cached client configuration @@ -343,8 +345,11 @@ public T runInsideDocker(Consumer createContainerCmdCons } private T runInsideDocker(DockerClient client, Consumer createContainerCmdConsumer, BiFunction block) { - checkAndPullImage(client, TINY_IMAGE); - CreateContainerCmd createContainerCmd = client.createContainerCmd(TINY_IMAGE) + + final String tinyImage = ImageNameSubstitutor.instance().apply(TINY_IMAGE).asCanonicalNameString(); + + checkAndPullImage(client, tinyImage); + CreateContainerCmd createContainerCmd = client.createContainerCmd(tinyImage) .withLabels(DEFAULT_LABELS); createContainerCmdConsumer.accept(createContainerCmd); String id = createContainerCmd.exec().getId(); diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index bd06083644d..7a67073e383 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -29,11 +29,11 @@ import org.testcontainers.utility.AuditLogger; import org.testcontainers.utility.Base58; import org.testcontainers.utility.CommandLine; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.LogUtils; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.ResourceReaper; -import org.testcontainers.utility.TestcontainersConfiguration; import org.zeroturnaround.exec.InvalidExitValueException; import org.zeroturnaround.exec.ProcessExecutor; import org.zeroturnaround.exec.stream.slf4j.Slf4jStream; @@ -608,10 +608,11 @@ interface DockerCompose { class ContainerisedDockerCompose extends GenericContainer implements DockerCompose { public static final char UNIX_PATH_SEPERATOR = ':'; + public static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker/compose:1.24.1"); public ContainerisedDockerCompose(List composeFiles, String identifier) { - super(TestcontainersConfiguration.getInstance().getDockerComposeDockerImageName()); + super(DEFAULT_IMAGE_NAME); addEnv(ENV_PROJECT_NAME, identifier); // Map the docker compose file into the container diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 95050d8f8ee..641096a0779 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -239,13 +239,9 @@ public GenericContainer(@NonNull final RemoteDockerImage image) { */ @Deprecated public GenericContainer() { - this(TestcontainersConfiguration.getInstance().getTinyDockerImageName().asCanonicalNameString()); + this(TestcontainersConfiguration.getInstance().getTinyImage()); } - /** - * @deprecated use {@link GenericContainer(DockerImageName)} instead - */ - @Deprecated public GenericContainer(@NonNull final String dockerImageName) { this.setDockerImageName(dockerImageName); } diff --git a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java index e42f2681675..b3f020500a1 100644 --- a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java @@ -5,15 +5,15 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.SneakyThrows; -import org.testcontainers.utility.TestcontainersConfiguration; +import org.testcontainers.utility.DockerImageName; import java.time.Duration; import java.util.AbstractMap; import java.util.Collections; +import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.UUID; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; public enum PortForwardingContainer { @@ -29,7 +29,7 @@ public enum PortForwardingContainer { @SneakyThrows private Connection createSSHSession() { String password = UUID.randomUUID().toString(); - container = new GenericContainer<>(TestcontainersConfiguration.getInstance().getSSHdDockerImageName()) + container = new GenericContainer<>(DockerImageName.parse("testcontainers/sshd:1.0.0")) .withExposedPorts(22) .withEnv("PASSWORD", password) .withCommand( diff --git a/core/src/main/java/org/testcontainers/containers/SocatContainer.java b/core/src/main/java/org/testcontainers/containers/SocatContainer.java index fbca73eb29d..7592d9f4d1f 100644 --- a/core/src/main/java/org/testcontainers/containers/SocatContainer.java +++ b/core/src/main/java/org/testcontainers/containers/SocatContainer.java @@ -1,12 +1,10 @@ package org.testcontainers.containers; -import org.testcontainers.utility.Base58; -import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.TestcontainersConfiguration; - import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; +import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; /** * A socat container is used as a TCP proxy, enabling any TCP port of another container to be exposed @@ -17,7 +15,7 @@ public class SocatContainer extends GenericContainer { private final Map targets = new HashMap<>(); public SocatContainer() { - this(TestcontainersConfiguration.getInstance().getSocatDockerImageName()); + this(DockerImageName.parse("alpine/socat:1.7.3.4-r0")); } public SocatContainer(final DockerImageName dockerImageName) { diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index 8ac060c2af6..de720110a51 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -6,7 +6,7 @@ import lombok.ToString; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; -import org.testcontainers.utility.TestcontainersConfiguration; +import org.testcontainers.utility.DockerImageName; import java.io.File; import java.io.InputStream; @@ -52,7 +52,7 @@ public VncRecordingContainer(@NonNull GenericContainer targetContainer) { * Create a sidekick container and attach it to another container. The VNC output of that container will be recorded. */ public VncRecordingContainer(@NonNull Network network, @NonNull String targetNetworkAlias) throws IllegalStateException { - super(TestcontainersConfiguration.getInstance().getVncDockerImageName()); + super(DockerImageName.parse("testcontainers/vnc-recorder:1.1.0")); this.targetNetworkAlias = targetNetworkAlias; withNetwork(network); diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index e21c75a581d..1bd51da1263 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -171,7 +171,7 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List imageFuture) { @@ -100,7 +101,10 @@ protected final String resolve() { } private DockerImageName getImageName() throws InterruptedException, ExecutionException { - return imageNameFuture.get(); + final DockerImageName specifiedImageName = imageNameFuture.get(); + + // Allow the image name to be substituted + return ImageNameSubstitutor.instance().apply(specifiedImageName); } @ToString.Include(name = "imageName", rank = 1) diff --git a/core/src/main/java/org/testcontainers/utility/ClasspathScanner.java b/core/src/main/java/org/testcontainers/utility/ClasspathScanner.java new file mode 100644 index 00000000000..76716cfdb7c --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/ClasspathScanner.java @@ -0,0 +1,59 @@ +package org.testcontainers.utility; + +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; + +import java.net.URL; +import java.util.Collections; +import java.util.Comparator; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * Utility for identifying resource files on classloaders. + */ +@Slf4j +class ClasspathScanner { + + @VisibleForTesting + static Stream scanFor(final String name, ClassLoader... classLoaders) { + return Stream + .of(classLoaders) + .flatMap(classLoader -> getAllPropertyFilesOnClassloader(classLoader, name)) + .filter(Objects::nonNull) + .sorted( + Comparator + .comparing(ClasspathScanner::filesFileSchemeFirst) // resolve 'local' files first + .thenComparing(URL::toString) // sort alphabetically for the sake of determinism + ) + .distinct(); + } + + private static Integer filesFileSchemeFirst(final URL t) { + return t.getProtocol().equals("file") ? 0 : 1; + } + + /** + * @param name the resource name to search for + * @return distinct, ordered stream of resources found by searching this class' classloader and the current thread's + * context classloader. Results are currently alphabetically sorted. + */ + static Stream scanFor(final String name) { + return scanFor( + name, + ClasspathScanner.class.getClassLoader(), + Thread.currentThread().getContextClassLoader() + ); + } + + @Nullable + private static Stream getAllPropertyFilesOnClassloader(final ClassLoader it, final String s) { + try { + return Collections.list(it.getResources(s)).stream(); + } catch (Exception e) { + log.error("Unable to read configuration from classloader {} - this is probably a bug", it, e); + return Stream.empty(); + } + } +} diff --git a/core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java new file mode 100644 index 00000000000..530d5a76118 --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java @@ -0,0 +1,44 @@ +package org.testcontainers.utility; + +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; + +/** + * {@link ImageNameSubstitutor} which takes replacement image names from configuration. + * See {@link TestcontainersConfiguration} for the subset of image names which can be substituted using this mechanism. + */ +@Slf4j +final class ConfigurationFileImageNameSubstitutor extends ImageNameSubstitutor { + + private final TestcontainersConfiguration configuration; + + public ConfigurationFileImageNameSubstitutor() { + this(TestcontainersConfiguration.getInstance()); + } + + @VisibleForTesting + ConfigurationFileImageNameSubstitutor(TestcontainersConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public DockerImageName apply(final DockerImageName original) { + final DockerImageName result = configuration + .getConfiguredSubstituteImage(original) + .asCompatibleSubstituteFor(original); + + if (!result.equals(original)) { + log.warn("Image name {} was substituted by configuration to {}. This approach is deprecated and will be removed in the future", + original, + result + ); + } + + return result; + } + + @Override + protected String getDescription() { + return getClass().getSimpleName(); + } +} diff --git a/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java new file mode 100644 index 00000000000..bcc7c96ba18 --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java @@ -0,0 +1,35 @@ +package org.testcontainers.utility; + +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; + +/** + * Testcontainers' default implementation of {@link ImageNameSubstitutor}. + * Delegates to {@link ConfigurationFileImageNameSubstitutor}. + */ +@Slf4j +final class DefaultImageNameSubstitutor extends ImageNameSubstitutor { + + private final ConfigurationFileImageNameSubstitutor configurationFileImageNameSubstitutor; + + public DefaultImageNameSubstitutor() { + configurationFileImageNameSubstitutor = new ConfigurationFileImageNameSubstitutor(); + } + + @VisibleForTesting + DefaultImageNameSubstitutor( + final ConfigurationFileImageNameSubstitutor configurationFileImageNameSubstitutor + ) { + this.configurationFileImageNameSubstitutor = configurationFileImageNameSubstitutor; + } + + @Override + public DockerImageName apply(final DockerImageName original) { + return configurationFileImageNameSubstitutor.apply(original); + } + + @Override + protected String getDescription() { + return "DefaultImageNameSubstitutor (" + configurationFileImageNameSubstitutor.getDescription() + ")"; + } +} diff --git a/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java new file mode 100644 index 00000000000..645b717a562 --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java @@ -0,0 +1,130 @@ +package org.testcontainers.utility; + +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.UnstableAPI; + +import java.util.function.Function; + +/** + * An image name substitutor converts a Docker image name, as may be specified in code, to an alternative name. + * This is intended to provide a way to override image names, for example to enforce pulling of images from a private + * registry. + *

+ * This is marked as @{@link UnstableAPI} as this API is new. While we do not think major changes will be required, we + * will react to feedback if necessary. + */ +@Slf4j +@UnstableAPI +public abstract class ImageNameSubstitutor implements Function { + + @VisibleForTesting + static ImageNameSubstitutor instance; + + @VisibleForTesting + static ImageNameSubstitutor defaultImplementation = new DefaultImageNameSubstitutor(); + + public synchronized static ImageNameSubstitutor instance() { + if (instance == null) { + final String configuredClassName = TestcontainersConfiguration.getInstance().getImageSubstitutorClassName(); + + if (configuredClassName != null) { + log.debug("Attempting to instantiate an ImageNameSubstitutor with class: {}", configuredClassName); + ImageNameSubstitutor configuredInstance; + try { + configuredInstance = (ImageNameSubstitutor) Class.forName(configuredClassName).getConstructor().newInstance(); + } catch (Exception e) { + throw new IllegalArgumentException("Configured Image Substitutor could not be loaded: " + configuredClassName, e); + } + + log.info("Found configured ImageNameSubstitutor: {}", configuredInstance.getDescription()); + + instance = new ChainedImageNameSubstitutor( + wrapWithLogging(defaultImplementation), + wrapWithLogging(configuredInstance) + ); + } else { + instance = wrapWithLogging(defaultImplementation); + } + + log.info("Image name substitution will be performed by: {}", instance.getDescription()); + } + + return instance; + } + + private static ImageNameSubstitutor wrapWithLogging(final ImageNameSubstitutor wrappedInstance) { + return new LogWrappedImageNameSubstitutor(wrappedInstance); + } + + /** + * Substitute a {@link DockerImageName} for another, for example to replace a generic Docker Hub image name with a + * private registry copy of the image. + * + * @param original original name to be replaced + * @return a replacement name, or the original, as appropriate + */ + public abstract DockerImageName apply(DockerImageName original); + + /** + * @return a human-readable description of the substitutor + */ + protected abstract String getDescription(); + + /** + * Wrapper substitutor which logs which substitutions have been performed. + */ + static class LogWrappedImageNameSubstitutor extends ImageNameSubstitutor { + @VisibleForTesting + final ImageNameSubstitutor wrappedInstance; + + public LogWrappedImageNameSubstitutor(final ImageNameSubstitutor wrappedInstance) { + this.wrappedInstance = wrappedInstance; + } + + @Override + public DockerImageName apply(final DockerImageName original) { + final DockerImageName replacementImage = wrappedInstance.apply(original); + + if (!replacementImage.equals(original)) { + log.info("Using {} as a substitute image for {} (using image substitutor: {})", replacementImage.asCanonicalNameString(), original.asCanonicalNameString(), wrappedInstance.getDescription()); + return replacementImage; + } else { + log.debug("Did not find a substitute image for {} (using image substitutor: {})", original.asCanonicalNameString(), wrappedInstance.getDescription()); + return original; + } + } + + @Override + protected String getDescription() { + return wrappedInstance.getDescription(); + } + } + + /** + * Wrapper substitutor that passes the original image name through a default substitutor and then the configured one + */ + static class ChainedImageNameSubstitutor extends ImageNameSubstitutor { + private final ImageNameSubstitutor defaultInstance; + private final ImageNameSubstitutor configuredInstance; + + public ChainedImageNameSubstitutor(ImageNameSubstitutor defaultInstance, ImageNameSubstitutor configuredInstance) { + this.defaultInstance = defaultInstance; + this.configuredInstance = configuredInstance; + } + + @Override + public DockerImageName apply(DockerImageName original) { + return defaultInstance.andThen(configuredInstance).apply(original); + } + + @Override + protected String getDescription() { + return String.format( + "Chained substitutor of '%s' and then '%s'", + defaultInstance.getDescription(), + configuredInstance.getDescription() + ); + } + } +} diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index c37e6660654..3b0cfa1e289 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -72,7 +72,9 @@ private ResourceReaper() { @SneakyThrows(InterruptedException.class) public static String start(String hostIpAddress, DockerClient client) { - String ryukImage = TestcontainersConfiguration.getInstance().getRyukDockerImageName().asCanonicalNameString(); + String ryukImage = ImageNameSubstitutor.instance() + .apply(DockerImageName.parse("testcontainers/ryuk:0.3.0")) + .asCanonicalNameString(); DockerClientFactory.instance().checkAndPullImage(client, ryukImage); List binds = new ArrayList<>(); diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index b3c8e88a328..987301fbfb9 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -23,7 +23,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; @@ -104,37 +103,21 @@ public String getSocatContainerImage() { return getImage(SOCAT_IMAGE).asCanonicalNameString(); } - public DockerImageName getSocatDockerImageName() { - return getImage(SOCAT_IMAGE); - } - @Deprecated public String getVncRecordedContainerImage() { return getImage(VNC_RECORDER_IMAGE).asCanonicalNameString(); } - public DockerImageName getVncDockerImageName() { - return getImage(VNC_RECORDER_IMAGE); - } - @Deprecated public String getDockerComposeContainerImage() { return getImage(COMPOSE_IMAGE).asCanonicalNameString(); } - public DockerImageName getDockerComposeDockerImageName() { - return getImage(COMPOSE_IMAGE); - } - @Deprecated public String getTinyImage() { return getImage(ALPINE_IMAGE).asCanonicalNameString(); } - public DockerImageName getTinyDockerImageName() { - return getImage(ALPINE_IMAGE); - } - public boolean isRyukPrivileged() { return Boolean .parseBoolean(getEnvVarOrProperty("ryuk.container.privileged", "false")); @@ -145,19 +128,11 @@ public String getRyukImage() { return getImage(RYUK_IMAGE).asCanonicalNameString(); } - public DockerImageName getRyukDockerImageName() { - return getImage(RYUK_IMAGE); - } - @Deprecated public String getSSHdImage() { return getImage(SSHD_IMAGE).asCanonicalNameString(); } - public DockerImageName getSSHdDockerImageName() { - return getImage(SSHD_IMAGE); - } - public Integer getRyukTimeout() { return Integer.parseInt(getEnvVarOrProperty("ryuk.container.timeout", "30")); } @@ -167,11 +142,6 @@ public String getKafkaImage() { return getImage(KAFKA_IMAGE).asCanonicalNameString(); } - public DockerImageName getKafkaDockerImageName() { - return getImage(KAFKA_IMAGE); - } - - @Deprecated public String getOracleImage() { return getEnvVarOrUserProperty("oracle.container.image", null); @@ -182,20 +152,11 @@ public String getPulsarImage() { return getImage(PULSAR_IMAGE).asCanonicalNameString(); } - public DockerImageName getPulsarDockerImageName() { - return getImage(PULSAR_IMAGE); - } - @Deprecated public String getLocalStackImage() { return getImage(LOCALSTACK_IMAGE).asCanonicalNameString(); } - public DockerImageName getLocalstackDockerImageName() { - return getImage(LOCALSTACK_IMAGE); - } - - public boolean isDisableChecks() { return Boolean.parseBoolean(getEnvVarOrUserProperty("checks.disable", "false")); } @@ -218,6 +179,10 @@ public Integer getImagePullPauseTimeout() { return Integer.parseInt(getEnvVarOrProperty("pull.pause.timeout", "30")); } + public String getImageSubstitutorClassName() { + return getEnvVarOrProperty("image.substitutor", null); + } + @Nullable @Contract("_, !null, _ -> !null") private String getConfigurable(@NotNull final String propertyName, @Nullable final String defaultValue, Properties... propertiesSources) { @@ -279,6 +244,13 @@ public String getUserProperty(@NotNull final String propertyName, @Nullable fina return getConfigurable(propertyName, defaultValue); } + /** + * @return properties values available from user properties and classpath properties. Values set by environment + * variable are NOT included. + * @deprecated usages should be removed ASAP. See {@link TestcontainersConfiguration#getEnvVarOrProperty(String, String)}, + * {@link TestcontainersConfiguration#getEnvVarOrUserProperty(String, String)} or {@link TestcontainersConfiguration#getUserProperty(String, String)} + * for suitable replacements. + */ @Deprecated public Properties getProperties() { return Stream.of(userProperties, classpathProperties) @@ -320,17 +292,13 @@ public boolean updateUserConfig(@NonNull String prop, @NonNull String value) { private static TestcontainersConfiguration loadConfiguration() { return new TestcontainersConfiguration( readProperties(USER_CONFIG_FILE.toURI().toURL()), - Stream - .of( - TestcontainersConfiguration.class.getClassLoader(), - Thread.currentThread().getContextClassLoader() - ) - .map(it -> it.getResource(PROPERTIES_FILE_NAME)) - .filter(Objects::nonNull) + ClasspathScanner.scanFor(PROPERTIES_FILE_NAME) .map(TestcontainersConfiguration::readProperties) .reduce(new Properties(), (a, b) -> { - a.putAll(b); - return a; + // first-write-wins merging - URLs appearing first on the classpath alphabetically will take priority. + // Note that this means that file: URLs will always take priority over jar: URLs. + b.putAll(a); + return b; }), System.getenv()); } @@ -341,9 +309,9 @@ private static Properties readProperties(URL url) { try (InputStream inputStream = url.openStream()) { properties.load(inputStream); } catch (FileNotFoundException e) { - log.warn("Testcontainers config override was found on {} but the file was not found. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); + log.warn("Attempted to read Testcontainers configuration file at {} but the file was not found. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); } catch (IOException e) { - log.warn("Testcontainers config override was found on {} but could not be loaded. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); + log.warn("Attempted to read Testcontainers configuration file at {} but could it not be loaded. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); } return properties; } diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index 030e4164f00..d484cc92eaf 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -1,5 +1,9 @@ package org.testcontainers; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.testcontainers.TestImages.TINY_IMAGE; + import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.NotFoundException; @@ -12,9 +16,6 @@ import org.testcontainers.utility.MockTestcontainersConfigurationRule; import org.testcontainers.utility.TestcontainersConfiguration; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - /** * Test for {@link DockerClientFactory}. */ @@ -30,7 +31,7 @@ public void runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally() { try { //remove tiny image, so it will be pulled during next command run dockFactory.client() - .removeImageCmd(TestcontainersConfiguration.getInstance().getTinyDockerImageName().asCanonicalNameString()) + .removeImageCmd(TINY_IMAGE.asCanonicalNameString()) .withForce(true).exec(); } catch (NotFoundException ignored) { // Do not fail if it's not pulled yet diff --git a/core/src/test/java/org/testcontainers/TestImages.java b/core/src/test/java/org/testcontainers/TestImages.java index 3f16e88d882..7052f7e8f9d 100644 --- a/core/src/test/java/org/testcontainers/TestImages.java +++ b/core/src/test/java/org/testcontainers/TestImages.java @@ -1,7 +1,6 @@ package org.testcontainers; import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.TestcontainersConfiguration; public interface TestImages { DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:3.0.2"); @@ -9,5 +8,5 @@ public interface TestImages { DockerImageName MONGODB_IMAGE = DockerImageName.parse("mongo:3.1.5"); DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.2"); DockerImageName DOCKER_REGISTRY_IMAGE = DockerImageName.parse("registry:2.7.0"); - DockerImageName TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyDockerImageName(); + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.5"); } diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index e49ff2880df..c99770c4fbf 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -1,9 +1,21 @@ package org.testcontainers.utility; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; +import static org.testcontainers.TestImages.TINY_IMAGE; + import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.model.AuthConfig; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; import org.intellij.lang.annotations.Language; import org.junit.AfterClass; import org.junit.Before; @@ -18,18 +30,6 @@ import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.images.builder.ImageFromDockerfile; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.concurrent.TimeUnit; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; - /** * This test checks the integration between Testcontainers and an authenticated registry, but uses * a mock instance of {@link RegistryAuthLocator} - the purpose of the test is solely to ensure that @@ -165,7 +165,7 @@ private Path getLocalTempFile(String s) throws IOException { private static void putImageInRegistry() throws InterruptedException { // It doesn't matter which image we use for this test, but use one that's likely to have been pulled already - final String dummySourceImage = TestcontainersConfiguration.getInstance().getRyukDockerImageName().asCanonicalNameString(); + final String dummySourceImage = TINY_IMAGE.asCanonicalNameString(); client.pullImageCmd(dummySourceImage) .exec(new PullImageResultCallback()) diff --git a/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java b/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java new file mode 100644 index 00000000000..bdd71b0db9f --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java @@ -0,0 +1,114 @@ +package org.testcontainers.utility; + +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class ClasspathScannerTest { + + private static URL FILE_A; + private static URL FILE_B; + private static URL JAR_A; + private static URL JAR_B; + private static URL FILE_C; + + @BeforeClass + public static void setUp() throws Exception { + FILE_A = new URL("file:///a/someName"); + FILE_B = new URL("file:///b/someName"); + FILE_C = new URL("file:///c/someName"); + JAR_A = new URL("jar:file:a!/someName"); + JAR_B = new URL("jar:file:b!/someName"); + } + + @Test + public void realClassLoaderLookupOccurs() { + // look for a resource that we know exists only once + final List foundURLs = ClasspathScanner.scanFor("expectedClasspathFile.txt").collect(toList()); + + assertEquals("Exactly one resource was found", 1, foundURLs.size()); + } + + @Test + public void multipleResultsOnOneClassLoaderAreFound() throws IOException { + final ClassLoader firstMockClassLoader = mock(ClassLoader.class); + when(firstMockClassLoader.getResources(eq("someName"))).thenReturn( + Collections.enumeration( + asList( + FILE_A, + FILE_B + ) + ) + ); + + final List foundURLs = ClasspathScanner.scanFor("someName", firstMockClassLoader).collect(toList()); + assertEquals( + "The expected URLs are found", + asList(FILE_A, FILE_B), + foundURLs + ); + } + + @Test + public void orderIsAlphabeticalForDeterminism() throws IOException { + final ClassLoader firstMockClassLoader = mock(ClassLoader.class); + when(firstMockClassLoader.getResources(eq("someName"))).thenReturn( + Collections.enumeration( + asList( + FILE_B, + JAR_A, + JAR_B, + FILE_A + ) + ) + ); + + final List foundURLs = ClasspathScanner.scanFor("someName", firstMockClassLoader).collect(toList()); + assertEquals( + "The expected URLs are found in the expected order", + asList(FILE_A, FILE_B, JAR_A, JAR_B), + foundURLs + ); + } + + @Test + public void multipleClassLoadersAreQueried() throws IOException { + final ClassLoader firstMockClassLoader = mock(ClassLoader.class); + when(firstMockClassLoader.getResources(eq("someName"))).thenReturn( + Collections.enumeration( + asList( + FILE_A, + FILE_B + ) + ) + ); + final ClassLoader secondMockClassLoader = mock(ClassLoader.class); + when(secondMockClassLoader.getResources(eq("someName"))).thenReturn( + Collections.enumeration( + asList( + FILE_B, // duplicate + FILE_C + ) + ) + ); + + final List foundURLs = ClasspathScanner.scanFor("someName", firstMockClassLoader, secondMockClassLoader).collect(toList()); + + assertEquals( + "The expected URLs are found", + asList(FILE_A, FILE_B, FILE_C), + foundURLs + ); + } +} diff --git a/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java new file mode 100644 index 00000000000..a6f7813c3d3 --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java @@ -0,0 +1,38 @@ +package org.testcontainers.utility; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; + +public class DefaultImageNameSubstitutorTest { + + public static final DockerImageName ORIGINAL_IMAGE = DockerImageName.parse("foo"); + public static final DockerImageName SUBSTITUTE_IMAGE = DockerImageName.parse("bar"); + private ConfigurationFileImageNameSubstitutor underTest; + + @Rule + public MockTestcontainersConfigurationRule config = new MockTestcontainersConfigurationRule(); + + @Before + public void setUp() { + underTest = new ConfigurationFileImageNameSubstitutor(TestcontainersConfiguration.getInstance()); + } + + @Test + public void testConfigurationLookup() { + Mockito + .doReturn(SUBSTITUTE_IMAGE) + .when(TestcontainersConfiguration.getInstance()) + .getConfiguredSubstituteImage(eq(ORIGINAL_IMAGE)); + + final DockerImageName substitute = underTest.apply(ORIGINAL_IMAGE); + + assertEquals("match is found", SUBSTITUTE_IMAGE, substitute); + assertTrue("compatibility is automatically set", substitute.isCompatibleWith(ORIGINAL_IMAGE)); + } +} diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java index 9e7136ea6d3..7c794814faf 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java @@ -26,9 +26,8 @@ public void testNoTagTreatedAsWildcard() { /* foo:1.2.3 != foo:4.5.6 foo:1.2.3 ~= foo - foo:1.2.3 ~= foo:latest - The test is effectively making sure that no tag and `latest` tag are equivalent + The test is effectively making sure that 'no tag' is treated as a wildcard */ assertFalse("foo:4.5.6 != foo:1.2.3", subject.isCompatibleWith(DockerImageName.parse("foo:1.2.3"))); assertTrue("foo:4.5.6 ~= foo", subject.isCompatibleWith(DockerImageName.parse("foo"))); diff --git a/core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java b/core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java new file mode 100644 index 00000000000..f74a6c942b3 --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java @@ -0,0 +1,13 @@ +package org.testcontainers.utility; + +public class FakeImageSubstitutor extends ImageNameSubstitutor { + @Override + public DockerImageName apply(final DockerImageName original) { + return DockerImageName.parse("transformed-" + original.asCanonicalNameString()); + } + + @Override + protected String getDescription() { + return "test implementation"; + } +} diff --git a/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java new file mode 100644 index 00000000000..97ee0213f21 --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java @@ -0,0 +1,75 @@ +package org.testcontainers.utility; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.eq; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; + +public class ImageNameSubstitutorTest { + + @Rule + public MockTestcontainersConfigurationRule config = new MockTestcontainersConfigurationRule(); + private ImageNameSubstitutor originalInstance; + private ImageNameSubstitutor originalDefaultImplementation; + + @Before + public void setUp() throws Exception { + originalInstance = ImageNameSubstitutor.instance; + originalDefaultImplementation = ImageNameSubstitutor.defaultImplementation; + ImageNameSubstitutor.instance = null; + ImageNameSubstitutor.defaultImplementation = Mockito.mock(ImageNameSubstitutor.class); + + Mockito + .doReturn(DockerImageName.parse("substituted-image")) + .when(ImageNameSubstitutor.defaultImplementation) + .apply(eq(DockerImageName.parse("original"))); + Mockito + .doReturn("default implementation") + .when(ImageNameSubstitutor.defaultImplementation) + .getDescription(); + } + + @After + public void tearDown() throws Exception { + ImageNameSubstitutor.instance = originalInstance; + ImageNameSubstitutor.defaultImplementation = originalDefaultImplementation; + } + + @Test + public void simpleConfigurationTest() { + Mockito + .doReturn(FakeImageSubstitutor.class.getCanonicalName()) + .when(TestcontainersConfiguration.getInstance()) + .getImageSubstitutorClassName(); + + final ImageNameSubstitutor imageNameSubstitutor = ImageNameSubstitutor.instance(); + + DockerImageName result = imageNameSubstitutor.apply(DockerImageName.parse("original")); + assertEquals( + "the image has been substituted by default then configured implementations", + "transformed-substituted-image:latest", + result.asCanonicalNameString() + ); + } + + @Test + public void testWorksWithoutConfiguredImplementation() { + Mockito + .doReturn(null) + .when(TestcontainersConfiguration.getInstance()) + .getImageSubstitutorClassName(); + + final ImageNameSubstitutor imageNameSubstitutor = ImageNameSubstitutor.instance(); + + DockerImageName result = imageNameSubstitutor.apply(DockerImageName.parse("original")); + assertEquals( + "the image has been substituted by default then configured implementations", + "substituted-image:latest", + result.asCanonicalNameString() + ); + } +} diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index e48a2a6fdf9..ae07e2d9131 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -25,6 +25,69 @@ public void setUp() { environment = new HashMap<>(); } + @Test + public void shouldSubstituteImageNamesFromClasspathProperties() { + classpathProperties.setProperty("ryuk.container.image", "foo:version"); + assertEquals( + "an image name can be pulled from classpath properties", + DockerImageName.parse("foo:version"), + newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any")) + ); + } + + @Test + public void shouldSubstituteImageNamesFromUserProperties() { + userProperties.setProperty("ryuk.container.image", "foo:version"); + assertEquals( + "an image name can be pulled from user properties", + DockerImageName.parse("foo:version"), + newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any")) + ); + } + + @Test + public void shouldSubstituteImageNamesFromEnvironmentVariables() { + environment.put("TESTCONTAINERS_RYUK_CONTAINER_IMAGE", "foo:version"); + assertEquals( + "an image name can be pulled from an environment variable", + DockerImageName.parse("foo:version"), + newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any")) + ); + } + + @Test + public void shouldApplySettingsInOrder() { + assertEquals( + "precedence order for multiple sources of the same value is correct", + "default", + newConfig().getEnvVarOrProperty("key", "default") + ); + + classpathProperties.setProperty("key", "foo"); + + assertEquals( + "precedence order for multiple sources of the same value is correct", + "foo", + newConfig().getEnvVarOrProperty("key", "default") + ); + + userProperties.setProperty("key", "bar"); + + assertEquals( + "precedence order for multiple sources of the same value is correct", + "bar", + newConfig().getEnvVarOrProperty("key", "default") + ); + + environment.put("TESTCONTAINERS_KEY", "baz"); + + assertEquals( + "precedence order for multiple sources of the same value is correct", + "baz", + newConfig().getEnvVarOrProperty("key", "default") + ); + } + @Test public void shouldNotReadChecksFromClasspathProperties() { assertFalse("checks enabled by default", newConfig().isDisableChecks()); diff --git a/core/src/test/resources/expectedClasspathFile.txt b/core/src/test/resources/expectedClasspathFile.txt new file mode 100644 index 00000000000..e13c06f078f --- /dev/null +++ b/core/src/test/resources/expectedClasspathFile.txt @@ -0,0 +1 @@ +This file exists for org.testcontainers.utility.ClasspathScannerTest diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle index 5ce878c7ba2..ff1b11f142e 100644 --- a/docs/examples/junit4/generic/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -4,6 +4,9 @@ dependencies { testCompile "junit:junit:4.12" testCompile project(":testcontainers") testCompile project(":selenium") + testCompile project(":mysql") + + testCompile 'mysql:mysql-connector-java:8.0.21' testCompile "org.seleniumhq.selenium:selenium-api:3.141.59" testCompile 'org.assertj:assertj-core:3.15.0' } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java b/docs/examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java new file mode 100644 index 00000000000..f6355312b3f --- /dev/null +++ b/docs/examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java @@ -0,0 +1,24 @@ +package generic; + +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.ImageNameSubstitutor; + +public class ExampleImageNameSubstitutor extends ImageNameSubstitutor { + + @Override + public DockerImageName apply(DockerImageName original) { + // convert the original name to something appropriate for + // our build environment + return DockerImageName.parse( + // your code goes here - silly example of capitalising + // the original name is shown + original.asCanonicalNameString().toUpperCase() + ); + } + + @Override + protected String getDescription() { + // used in logs + return "example image name substitutor"; + } +} diff --git a/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java b/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java new file mode 100644 index 00000000000..edc622a4104 --- /dev/null +++ b/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java @@ -0,0 +1,48 @@ +package generic; + + +import generic.support.TestSpecificImageNameSubstitutor; +import org.junit.Test; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.utility.DockerImageName; + +public class ImageNameSubstitutionTest { + + @Test + public void simpleExample() { + try ( + // directDockerHubReference { + // Referring directly to an image on Docker Hub (mysql:8.0.22) + final MySQLContainer mysql = new MySQLContainer<>( + DockerImageName.parse("mysql:8.0.22") + ) + + // start the container and use it for testing + // } + ) { + mysql.start(); + } + } + + /** + * Note that this test uses a fake image name, which will only work because + * {@link TestSpecificImageNameSubstitutor} steps in to override the substitution for this exact + * image name. + */ + @Test + public void substitutedExample() { + try ( + // hardcodedMirror { + // Referring directly to an image on a private registry - image name will vary + final MySQLContainer mysql = new MySQLContainer<>( + DockerImageName.parse("registry.mycompany.com/mirror/mysql:8.0.22") + .asCompatibleSubstituteFor("mysql") + ) + + // start the container and use it for testing + // } + ) { + mysql.start(); + } + } +} diff --git a/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java b/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java new file mode 100644 index 00000000000..5f9e92c0add --- /dev/null +++ b/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java @@ -0,0 +1,26 @@ +package generic.support; + +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.ImageNameSubstitutor; + +/** + * An {@link ImageNameSubstitutor} which makes it possible to use fake image names in + * {@link generic.ImageNameSubstitutionTest}. This implementation simply reverses a fake image name when presented, and + * is hardcoded to act upon the specific fake name in that test. + */ +public class TestSpecificImageNameSubstitutor extends ImageNameSubstitutor { + + @Override + public DockerImageName apply(final DockerImageName original) { + if (original.equals(DockerImageName.parse("registry.mycompany.com/mirror/mysql:8.0.22"))) { + return DockerImageName.parse("mysql"); + } else { + return original; + } + } + + @Override + protected String getDescription() { + return TestSpecificImageNameSubstitutor.class.getSimpleName(); + } +} diff --git a/docs/examples/junit4/generic/src/test/resources/logback-test.xml b/docs/examples/junit4/generic/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..1378a823a63 --- /dev/null +++ b/docs/examples/junit4/generic/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + + + diff --git a/docs/examples/junit4/generic/src/test/resources/testcontainers.properties b/docs/examples/junit4/generic/src/test/resources/testcontainers.properties new file mode 100644 index 00000000000..19bf8288d33 --- /dev/null +++ b/docs/examples/junit4/generic/src/test/resources/testcontainers.properties @@ -0,0 +1 @@ +image.substitutor=generic.support.TestSpecificImageNameSubstitutor diff --git a/docs/features/configuration.md b/docs/features/configuration.md index e3ac0fb6ac3..b567a8f564f 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -2,14 +2,26 @@ You can override some default properties if your environment requires that. -## Configuration file location +## Configuration locations The configuration will be loaded from multiple locations. Properties are considered in the following order: -1. `.testcontainers.properties` in user's home folder. Example locations: +1. Environment variables +2. `.testcontainers.properties` in user's home folder. Example locations: **Linux:** `/home/myuser/.testcontainers.properties` **Windows:** `C:/Users/myuser/.testcontainers.properties` **macOS:** `/Users/myuser/.testcontainers.properties` -2. `testcontainers.properties` on classpath +3. `testcontainers.properties` on the classpath. + +Note that when using environment variables, configuration property names should be set in upper +case with underscore separators, preceded by `TESTCONTAINERS_` - e.g. `checks.disable` becomes +`TESTCONTAINERS_CHECKS_DISABLE`. + +The classpath `testcontainers.properties` file may exist within the local codebase (e.g. within the `src/test/resources` directory) or within library dependencies that you may have. +Any such configuration files will have their contents merged. +If any keys conflict, the value will be taken on the basis of the first value found in: + +* 'local' classpath (i.e. where the URL of the file on the classpath begins with `file:`), then +* other classpath locations (i.e. JAR files) - considered in _alphabetical order of path_ to provide deterministic ordering. ## Disabling the startup checks > **checks.disable = [true|false]** @@ -26,18 +38,30 @@ It takes a couple of seconds, but if you want to speed up your tests, you can di ## Customizing images +!!! note + This approach is discouraged and deprecated, but is documented for completeness. + Overriding individual image names via configuration may be removed in 2021. + See [Image Name Substitution](./image_name_substitution.md) for other strategies for substituting image names to pull from other registries. + + Testcontainers uses public Docker images to perform different actions like startup checks, VNC recording and others. Some companies disallow the usage of Docker Hub, but you can override `*.image` properties with your own images from your private registry to workaround that. +> **ryuk.container.image = testcontainers/ryuk:0.3.0** +> Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) + > **tinyimage.container.image = alpine:3.5** -> Used by Testcontainers' core +> Used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](#disabling-the-startup-checks)) + +> **sshd.container.image = testcontainers/sshd:1.0.0** +> Required if [exposing host ports to containers](./networking.md#exposing-host-ports-to-the-container) > **vncrecorder.container.image = testcontainers/vnc-recorder:1.1.0** -> Used by VNC recorder in Testcontainers' Seleniun integration +> Used by VNC recorder in Testcontainers' Selenium integration -> **ambassador.container.image = richnorth/ambassador:latest** +> **socat.container.image = alpine/socat** > **compose.container.image = docker/compose:1.8.0** -> Used by Docker Compose integration +> Required if using [Docker Compose](../modules/docker_compose.md) > **kafka.container.image = confluentinc/cp-kafka** > Used by KafkaContainer @@ -45,11 +69,8 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **localstack.container.image = localstack/localstack** > Used by LocalStack -Another possibility is to set up a registry mirror in your environment so that all images are pulled from there and not directly from Docker Hub. -For more information, see the [official Docker documentation about "Registry as a pull through cache"](https://docs.docker.com/registry/recipes/mirror/). - -!!!tip - Registry mirror currently only works for Docker images with image name that has no registry specified (for example, for Docker image `mariadb:10.3.6`, it works, for Docker image `quay.io/something/else`, not). +> **pulsar.container.image = apachepulsar/pulsar:2.2.0** +> Used by Apache Pulsar ## Customizing Ryuk resource reaper diff --git a/docs/features/image_name_substitution.md b/docs/features/image_name_substitution.md new file mode 100644 index 00000000000..0cf2d4cf8f0 --- /dev/null +++ b/docs/features/image_name_substitution.md @@ -0,0 +1,117 @@ +# Image name substitution + +Testcontainers supports automatic substitution of Docker image names. + +This allows replacement of an image name specified in test code with an alternative name - for example, to replace the +name of a Docker Hub image dependency with an alternative hosted on a private image registry. + +This is advisable to avoid [Docker Hub rate limiting](./pull_rate_limiting.md), and some companies will prefer this for policy reasons. + +This page describes four approaches for image name substitution: + +* [Manual substitution](#manual-substitution) - not relying upon an automated approach +* Using an Image Name Substitutor: + * [Developing a custom function for transforming image names on the fly](#developing-a-custom-function-for-transforming-image-names-on-the-fly) + * [Overriding image names individually in configuration](#overriding-image-names-individually-in-configuration) + +It is assumed that you have already set up a private registry hosting [all the Docker images your build requires](./pull_rate_limiting.md#which-images-are-used-by-testcontainers). + + + + +## Manual substitution + +Consider this if: + +* You use only a few images and updating code is not a chore +* All developers and CI machines in your organisation have access to a common registry server +* You also use one of the automated mechanisms to substitute [the images that Testcontainers itself requires](./pull_rate_limiting.md#which-images-are-used-by-testcontainers) + +This approach simply entails modifying test code manually, e.g. changing: + +For example, you may have a test that uses the `mysql` container image from Docker Hub: + + +[Direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference + + +to: + + +[Private registry image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:hardcodedMirror + + + + + + + + + + +## Developing a custom function for transforming image names on the fly + +Consider this if: + +* You have complex rules about which private registry images should be used as substitutes, e.g.: + * non-deterministic mapping of names meaning that a [name prefix](#adding-a-registry-url-prefix-to-image-names-automatically) cannot be used + * rules depending upon developer identity or location +* or you wish to add audit logging of images used in the build +* or you wish to prevent accidental usage of images that are not on an approved list + +In this case, image name references in code are **unchanged**. +i.e. you would leave as-is: + + +[Unchanged direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference + + +You can implement a custom image name substitutor by: + +* subclassing `org.testcontainers.utility.ImageNameSubstitutor` +* configuring Testcontainers to use your custom implementation + +The following is an example image substitutor implementation: + + +[Example Image Substitutor](../examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java) block:ExampleImageNameSubstitutor + + +Testcontainers can be configured to find it at runtime via configuration. +To do this, create or modify a file on the classpath named `testcontainers.properties`. + +For example: + +```text tab="src/test/resources/testcontainers.properties" +image.substitutor=com.mycompany.testcontainers.ExampleImageNameSubstitutor +``` + +Note that it is also possible to provide this same configuration property: + +* in a `testcontainers.properties` file at the root of a library JAR file (useful if you wish to distribute a drop-in image substitutor JAR within an organization) +* in a properties file in the user's home directory (`~/.testcontainers.properties`; note the leading `.`) +* or as an environment variable (e.g. `TESTCONTAINERS_IMAGE_SUBSTITUTOR=com.mycompany.testcontainers.ExampleImageNameSubstitutor`). + +Please see [the documentation on configuration mechanisms](./configuration.md) for more information. + + +## Overriding image names individually in configuration + +!!! note + This approach is discouraged and deprecated, but is documented for completeness. + Please consider one of the other approaches outlined in this page instead. + Overriding individual image names via configuration may be removed in 2021. + +Consider this if: + +* You have many references to image names in code and changing them is impractical, and +* None of the other options are practical for you + +In this case, image name references in code are left **unchanged**. +i.e. you would leave as-is: + + +[Unchanged direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference + + +You can force Testcontainers to substitute in a different image [using a configuration file](./configuration.md), which allows some (but not all) container names to be substituted. diff --git a/docs/features/pull_rate_limiting.md b/docs/features/pull_rate_limiting.md new file mode 100644 index 00000000000..be266545afb --- /dev/null +++ b/docs/features/pull_rate_limiting.md @@ -0,0 +1,19 @@ +# Image Registry rate limiting + +As of November 2020 Docker Hub pulls are rate limited. +As Testcontainers uses Docker Hub for standard images, some users may hit these rate limits and should mitigate accordingly. + +Suggested mitigations are noted in [this issue](https://github.com/testcontainers/testcontainers-java/issues/3099) at present. + +## Which images are used by Testcontainers? + +As of the current version of Testcontainers ({{latest_version}}): + +* every image directly used by your tests +* images pulled by Testcontainers itself to support functionality: + * [`testcontainers/ryuk`](https://hub.docker.com/r/testcontainers/ryuk) - performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](./configuration.md#disabling-ryuk)) + * [`alpine`](https://hub.docker.com/r/_/alpine) - used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](./configuration.md#disabling-the-startup-checks)) + * [`testcontainers/sshd`](https://hub.docker.com/r/testcontainers/sshd) - required if [exposing host ports to containers](./networking.md#exposing-host-ports-to-the-container) + * [`testcontainers/vnc-recorder`](https://hub.docker.com/r/testcontainers/vnc-recorder) - required if using [Webdriver containers](../modules/webdriver_containers.md) and using the screen recording feature + * [`docker/compose`](https://hub.docker.com/r/docker/compose) - required if using [Docker Compose](../modules/docker_compose.md) + * [`alpine/socat`](https://hub.docker.com/r/alpine/socat) - required if using [Docker Compose](../modules/docker_compose.md) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 37f99bf970b..12867239251 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -4,7 +4,6 @@ import lombok.SneakyThrows; import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.TestcontainersConfiguration; import java.nio.charset.StandardCharsets; import java.util.stream.Collectors; @@ -36,7 +35,7 @@ public class KafkaContainer extends GenericContainer { */ @Deprecated public KafkaContainer() { - this(TestcontainersConfiguration.getInstance().getKafkaDockerImageName().withTag(DEFAULT_TAG)); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** @@ -44,7 +43,7 @@ public KafkaContainer() { */ @Deprecated public KafkaContainer(String confluentPlatformVersion) { - this(TestcontainersConfiguration.getInstance().getKafkaDockerImageName().withTag(confluentPlatformVersion)); + this(DEFAULT_IMAGE_NAME.withTag(confluentPlatformVersion)); } public KafkaContainer(final DockerImageName dockerImageName) { diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 4f721424bb6..263653822e6 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -61,7 +61,7 @@ public void testUsageWithSpecificImage() throws Exception { @Test public void testUsageWithVersion() throws Exception { try ( - KafkaContainer kafka = new KafkaContainer("5.4.3") + KafkaContainer kafka = new KafkaContainer("5.5.1") ) { kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 7532ebe0b3d..b8416afb1ed 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -14,7 +14,6 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.TestcontainersConfiguration; import java.net.InetAddress; import java.net.URI; @@ -65,7 +64,7 @@ public class LocalStackContainer extends GenericContainer { */ @Deprecated public LocalStackContainer() { - this(TestcontainersConfiguration.getInstance().getLocalstackDockerImageName().withTag(DEFAULT_TAG)); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** @@ -73,7 +72,7 @@ public LocalStackContainer() { */ @Deprecated public LocalStackContainer(String version) { - this(TestcontainersConfiguration.getInstance().getLocalstackDockerImageName().withTag(version)); + this(DEFAULT_IMAGE_NAME.withTag(version)); } /** diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index b5700c1e84e..0a66ad6fd27 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -22,8 +22,7 @@ public class OracleContainer extends JdbcDatabaseContainer { private String password = "oracle"; private static String resolveImageName() { - String image = TestcontainersConfiguration.getInstance() - .getProperties().getProperty("oracle.container.image"); + String image = TestcontainersConfiguration.getInstance().getOracleImage(); if (image == null) { throw new IllegalStateException("An image to use for Oracle containers must be configured. " + diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index bceff8927d7..b3c836b56a5 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -3,7 +3,6 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.TestcontainersConfiguration; /** * This container wraps Apache Pulsar running in standalone mode @@ -25,7 +24,7 @@ public class PulsarContainer extends GenericContainer { */ @Deprecated public PulsarContainer() { - this(TestcontainersConfiguration.getInstance().getPulsarDockerImageName().withTag(DEFAULT_TAG)); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } /** @@ -33,7 +32,7 @@ public PulsarContainer() { */ @Deprecated public PulsarContainer(String pulsarVersion) { - this(TestcontainersConfiguration.getInstance().getPulsarDockerImageName().withTag(pulsarVersion)); + this(DEFAULT_IMAGE_NAME.withTag(pulsarVersion)); } public PulsarContainer(final DockerImageName dockerImageName) { diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy index 526c1fe5c42..9698e7d433a 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy @@ -1,11 +1,10 @@ -package org.testcontainers.spock; +package org.testcontainers.spock import org.testcontainers.utility.DockerImageName -import org.testcontainers.utility.TestcontainersConfiguration; interface SpockTestImages { DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.22") DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") - DockerImageName TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyDockerImageName() + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.5") } From b28f6efafa8f60e70f95670fecfde29eafbf4e4b Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 5 Nov 2020 20:12:57 +0000 Subject: [PATCH 1079/4969] Fix missing links to new docs from site menu --- docs/features/image_name_substitution.md | 6 +++--- .../image_registry_rate_limiting.md} | 6 +++--- mkdocs.yml | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) rename docs/{features/pull_rate_limiting.md => supported_docker_environment/image_registry_rate_limiting.md} (81%) diff --git a/docs/features/image_name_substitution.md b/docs/features/image_name_substitution.md index 0cf2d4cf8f0..45ea6038b49 100644 --- a/docs/features/image_name_substitution.md +++ b/docs/features/image_name_substitution.md @@ -5,7 +5,7 @@ Testcontainers supports automatic substitution of Docker image names. This allows replacement of an image name specified in test code with an alternative name - for example, to replace the name of a Docker Hub image dependency with an alternative hosted on a private image registry. -This is advisable to avoid [Docker Hub rate limiting](./pull_rate_limiting.md), and some companies will prefer this for policy reasons. +This is advisable to avoid [Docker Hub rate limiting](../supported_docker_environment/image_registry_rate_limiting.md), and some companies will prefer this for policy reasons. This page describes four approaches for image name substitution: @@ -14,7 +14,7 @@ This page describes four approaches for image name substitution: * [Developing a custom function for transforming image names on the fly](#developing-a-custom-function-for-transforming-image-names-on-the-fly) * [Overriding image names individually in configuration](#overriding-image-names-individually-in-configuration) -It is assumed that you have already set up a private registry hosting [all the Docker images your build requires](./pull_rate_limiting.md#which-images-are-used-by-testcontainers). +It is assumed that you have already set up a private registry hosting [all the Docker images your build requires](../supported_docker_environment/image_registry_rate_limiting.md#which-images-are-used-by-testcontainers). @@ -25,7 +25,7 @@ Consider this if: * You use only a few images and updating code is not a chore * All developers and CI machines in your organisation have access to a common registry server -* You also use one of the automated mechanisms to substitute [the images that Testcontainers itself requires](./pull_rate_limiting.md#which-images-are-used-by-testcontainers) +* You also use one of the automated mechanisms to substitute [the images that Testcontainers itself requires](../supported_docker_environment/image_registry_rate_limiting.md#which-images-are-used-by-testcontainers) This approach simply entails modifying test code manually, e.g. changing: diff --git a/docs/features/pull_rate_limiting.md b/docs/supported_docker_environment/image_registry_rate_limiting.md similarity index 81% rename from docs/features/pull_rate_limiting.md rename to docs/supported_docker_environment/image_registry_rate_limiting.md index be266545afb..a136a12b25e 100644 --- a/docs/features/pull_rate_limiting.md +++ b/docs/supported_docker_environment/image_registry_rate_limiting.md @@ -11,9 +11,9 @@ As of the current version of Testcontainers ({{latest_version}}): * every image directly used by your tests * images pulled by Testcontainers itself to support functionality: - * [`testcontainers/ryuk`](https://hub.docker.com/r/testcontainers/ryuk) - performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](./configuration.md#disabling-ryuk)) - * [`alpine`](https://hub.docker.com/r/_/alpine) - used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](./configuration.md#disabling-the-startup-checks)) - * [`testcontainers/sshd`](https://hub.docker.com/r/testcontainers/sshd) - required if [exposing host ports to containers](./networking.md#exposing-host-ports-to-the-container) + * [`testcontainers/ryuk`](https://hub.docker.com/r/testcontainers/ryuk) - performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](../features/configuration.md#disabling-ryuk)) + * [`alpine`](https://hub.docker.com/r/_/alpine) - used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](../features/configuration.md#disabling-the-startup-checks)) + * [`testcontainers/sshd`](https://hub.docker.com/r/testcontainers/sshd) - required if [exposing host ports to containers](../features/networking.md#exposing-host-ports-to-the-container) * [`testcontainers/vnc-recorder`](https://hub.docker.com/r/testcontainers/vnc-recorder) - required if using [Webdriver containers](../modules/webdriver_containers.md) and using the screen recording feature * [`docker/compose`](https://hub.docker.com/r/docker/compose) - required if using [Docker Compose](../modules/docker_compose.md) * [`alpine/socat`](https://hub.docker.com/r/alpine/socat) - required if using [Docker Compose](../modules/docker_compose.md) diff --git a/mkdocs.yml b/mkdocs.yml index 0fa9b2b4c91..90404a80749 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -36,6 +36,7 @@ nav: - features/container_logs.md - features/creating_images.md - features/configuration.md + - features/image_name_substitution.md - features/advanced_options.md - Modules: - Databases: @@ -86,6 +87,7 @@ nav: - supported_docker_environment/continuous_integration/bitbucket_pipelines.md - supported_docker_environment/windows.md - supported_docker_environment/logging_config.md + - supported_docker_environment/image_registry_rate_limiting.md - Getting help: getting_help.md - Contributing: - contributing.md From c9be54f7ee5a47692f3cc875452cc63bf0a92004 Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Fri, 6 Nov 2020 14:04:28 +0100 Subject: [PATCH 1080/4969] Add Presto project to the list of Testcontainers users (#3435) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 28ca2453993..22fa9c93738 100644 --- a/docs/index.md +++ b/docs/index.md @@ -162,6 +162,7 @@ A huge thank you to our sponsors: * [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) * [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) * [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS +* [Presto](http://prestosql.io/) - Integration testing all Presto core & connectors, including tests of multi-node deployments and security configurations. ## License From d57a2bbada8c25f8f380b6258e5b259e02f34954 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 6 Nov 2020 14:05:10 +0100 Subject: [PATCH 1081/4969] Update mkdocs.yml to the latest release --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 90404a80749..618b9679291 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -94,4 +94,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.15.0-rc2 + latest_version: 1.15.0 From e2c55a236b39b515bfe32294e875bf83cc3251bd Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 8 Nov 2020 11:42:26 +0000 Subject: [PATCH 1082/4969] Selenium: Restore getDockerImageForCapabilities method to public scope (#3441) --- .../containers/BrowserWebDriverContainer.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 884cd33a9dd..1ceaf67ad2c 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -189,7 +189,7 @@ protected void configure() { customImageName.assertCompatibleWith(COMPATIBLE_IMAGES); super.setDockerImageName(customImageName.asCanonicalNameString()); } else { - DockerImageName standardImageForCapabilities = getImageForCapabilities(capabilities, seleniumVersion); + DockerImageName standardImageForCapabilities = getStandardImageForCapabilities(capabilities, seleniumVersion); super.setDockerImageName(standardImageForCapabilities.asCanonicalNameString()); } @@ -218,7 +218,22 @@ protected void configure() { setStartupAttempts(3); } - private static DockerImageName getImageForCapabilities(Capabilities capabilities, String seleniumVersion) { + /** + * @param capabilities a {@link Capabilities} object for either Chrome or Firefox + * @param seleniumVersion the version of selenium in use + * @return an image name for the default standalone Docker image for the appropriate browser + * + * @deprecated note that this method is deprecated and may be removed in the future. The no-args + * {@link BrowserWebDriverContainer#BrowserWebDriverContainer()} combined with the + * {@link BrowserWebDriverContainer#withCapabilities(Capabilities)} method should be considered. A decision on + * removal of this deprecated method will be taken at a future date. + */ + @Deprecated + public static String getDockerImageForCapabilities(Capabilities capabilities, String seleniumVersion) { + return getStandardImageForCapabilities(capabilities, seleniumVersion).asCanonicalNameString(); + } + + private static DockerImageName getStandardImageForCapabilities(Capabilities capabilities, String seleniumVersion) { String browserName = capabilities.getBrowserName(); switch (browserName) { case BrowserType.CHROME: From aa01d7a7f8305d068f6e60113ca1b454d0a83759 Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Sun, 8 Nov 2020 12:55:48 +0100 Subject: [PATCH 1083/4969] Update Presto URL to use https in 'Who is using' list (#3438) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 22fa9c93738..2351837f8af 100644 --- a/docs/index.md +++ b/docs/index.md @@ -162,7 +162,7 @@ A huge thank you to our sponsors: * [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) * [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) * [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS -* [Presto](http://prestosql.io/) - Integration testing all Presto core & connectors, including tests of multi-node deployments and security configurations. +* [Presto](https://prestosql.io) - Integration testing all Presto core & connectors, including tests of multi-node deployments and security configurations. ## License From dc9e9c14199caca9d3b130d058cd3de7677ea404 Mon Sep 17 00:00:00 2001 From: eyalkoren <41850454+eyalkoren@users.noreply.github.com> Date: Sat, 21 Nov 2020 18:08:26 +0200 Subject: [PATCH 1084/4969] Search Oracle image name in classpath (#3439) Not sure why the new code looks for the Oracle image name only in the user home directory and not in the config file placed in the classpath. This brakes my test. --- .../org/testcontainers/utility/TestcontainersConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 987301fbfb9..47c274c05e6 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -144,7 +144,7 @@ public String getKafkaImage() { @Deprecated public String getOracleImage() { - return getEnvVarOrUserProperty("oracle.container.image", null); + return getEnvVarOrProperty("oracle.container.image", null); } @Deprecated From 47c2988ef04c3d1ba7df8b5437d792e189b048f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Nov 2020 16:10:01 +0000 Subject: [PATCH 1085/4969] Bump aws-java-sdk-dynamodb from 1.11.882 to 1.11.901 in /modules/dynalite (#3472) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.882 to 1.11.901. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.882...1.11.901) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 8aa9959ea13..5f6ab14d939 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.882' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.901' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.882' } From 9ceca91d672e814e338a1ec5073b14144e188dfd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Nov 2020 16:10:19 +0000 Subject: [PATCH 1086/4969] Bump elasticsearch-rest-client from 7.9.2 to 7.10.0 in /modules/elasticsearch (#3474) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.9.2 to 7.10.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.9.2...v7.10.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 126722759ec..3b7ef456875 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.9.2" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.10.0" testCompile "org.elasticsearch.client:transport:7.9.2" } From 4f053283075e21f32044286d0237c749d3733dcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Nov 2020 16:10:27 +0000 Subject: [PATCH 1087/4969] Bump assertj-core from 3.18.0 to 3.18.1 in /modules/neo4j (#3477) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.0 to 3.18.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.0...assertj-core-3.18.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 8d7f59e564e..9aab6b18298 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.18.0' + testCompile 'org.assertj:assertj-core:3.18.1' } From 60018dfa586eb62d46060c0ad6403295a238df8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Nov 2020 16:10:51 +0000 Subject: [PATCH 1088/4969] Bump assertj-core from 3.17.2 to 3.18.1 in /modules/database-commons (#3479) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.17.2 to 3.18.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.17.2...assertj-core-3.18.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index e6d6a1812da..dacd8a500ac 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.17.2' + testCompile 'org.assertj:assertj-core:3.18.1' } From c381a64a6623fe71e95cfb73173907246a21e685 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 23 Nov 2020 11:32:25 +0100 Subject: [PATCH 1089/4969] Update to docker-java 3.2.6 (#3498) --- core/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 723b14fd0e6..6e3df56758a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -173,9 +173,9 @@ dependencies { compile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compile "com.github.docker-java:docker-java-api:3.2.5" + compile "com.github.docker-java:docker-java-api:3.2.6" - shaded ('com.github.docker-java:docker-java-core:3.2.5') { + shaded ('com.github.docker-java:docker-java-core:3.2.6') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') @@ -184,13 +184,13 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.5') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.6') { exclude(group: 'com.github.docker-java', module: 'docker-java-core') exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } - compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.5' + compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.6' shaded "org.yaml:snakeyaml:1.27" From 4e27522e9348059e3ee516c3eaf021da493762a7 Mon Sep 17 00:00:00 2001 From: sullis Date: Tue, 24 Nov 2020 11:24:59 -0800 Subject: [PATCH 1090/4969] Add toxiproxy to dependabot.yml (#3502) --- .github/dependabot.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8abda8d8c5a..d854a9aa823 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -122,6 +122,11 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/toxiproxy" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/vault" schedule: From e9a8ac9e3a9a9db6134ff07232c7e2363a5a99cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:28:02 +0000 Subject: [PATCH 1091/4969] Bump tomcat-jdbc from 9.0.39 to 9.0.40 in /modules/jdbc-test (#3513) Bumps tomcat-jdbc from 9.0.39 to 9.0.40. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 99841c1d62a..8523ca5a3d8 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -15,7 +15,7 @@ dependencies { } compile 'commons-dbutils:commons-dbutils:1.7' - compile 'org.apache.tomcat:tomcat-jdbc:9.0.39' + compile 'org.apache.tomcat:tomcat-jdbc:9.0.40' compile 'org.vibur:vibur-dbcp:25.0' compile 'mysql:mysql-connector-java:8.0.22' } From 1a2aa0e662669b86e7c285f8ca485ab5b22f558e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:28:09 +0000 Subject: [PATCH 1092/4969] Bump tomcat-jdbc from 9.0.39 to 9.0.40 in /modules/jdbc (#3509) Bumps tomcat-jdbc from 9.0.39 to 9.0.40. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 2045461785e..12a53f7cfbc 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:20.1.0' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.39' + testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.40' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' } From 1a2820fa344cbb60a4b156874bcaa04536824f78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:30:07 +0000 Subject: [PATCH 1093/4969] Bump assertj-core from 3.17.2 to 3.18.1 in /modules/pulsar (#3475) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.17.2 to 3.18.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.17.2...assertj-core-3.18.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 2d2ded0c765..e09ff42f357 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.1' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.17.2' + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.18.1' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.1' } From 6565fd2f5b020d341ac30bd353c2390396928ff2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:30:15 +0000 Subject: [PATCH 1094/4969] Bump assertj-core from 3.17.2 to 3.18.1 in /modules/kafka (#3469) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.17.2 to 3.18.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.17.2...assertj-core-3.18.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 95d844c7a41..4454823bda4 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { compile project(':testcontainers') testCompile 'org.apache.kafka:kafka-clients:2.6.0' - testCompile 'org.assertj:assertj-core:3.17.2' + testCompile 'org.assertj:assertj-core:3.18.1' testCompile 'com.google.guava:guava:23.0' } From 9ccb4432f7cbb827a8a0fdd6b918369646a55258 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:30:23 +0000 Subject: [PATCH 1095/4969] Bump assertj-core from 3.18.0 to 3.18.1 in /modules/junit-jupiter (#3470) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.0 to 3.18.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.0...assertj-core-3.18.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7986c067c89..520cff37254 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile ('org.mockito:mockito-core:3.5.15') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.18.0' + testCompile 'org.assertj:assertj-core:3.18.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' testRuntime 'org.postgresql:postgresql:42.2.18' From a3f0a16d3825a69aa446bd6462f99a2ecda4d756 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:30:56 +0000 Subject: [PATCH 1096/4969] Bump assertj-core from 3.17.2 to 3.18.1 in /core (#3471) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.17.2 to 3.18.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.17.2...assertj-core-3.18.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 6e3df56758a..ed0fc00d4f6 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -211,12 +211,12 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.assertj:assertj-core:3.17.2' + testCompile 'org.assertj:assertj-core:3.18.1' testCompile project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestCompile 'junit:junit:4.12' - jarFileTestCompile 'org.assertj:assertj-core:3.17.1' + jarFileTestCompile 'org.assertj:assertj-core:3.18.1' jarFileTestCompile 'org.ow2.asm:asm-debug-all:5.2' } From cf8c349e43ff05f7364c645cebb9061fda90aabf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:44:04 +0000 Subject: [PATCH 1097/4969] Bump transport from 7.9.2 to 7.10.0 in /modules/elasticsearch (#3473) Bumps [transport](https://github.com/elastic/elasticsearch) from 7.9.2 to 7.10.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.9.2...v7.10.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 3b7ef456875..bfbfbfae9ce 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.10.0" - testCompile "org.elasticsearch.client:transport:7.9.2" + testCompile "org.elasticsearch.client:transport:7.10.0" } From cb5e416504e74dfdf5d26640a9f0076f44df1d05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Nov 2020 09:42:59 +0000 Subject: [PATCH 1098/4969] Bump toxiproxy-java from 2.1.3 to 2.1.4 in /modules/toxiproxy (#3524) Bumps [toxiproxy-java](https://github.com/trekawek/toxiproxy-java) from 2.1.3 to 2.1.4. - [Release notes](https://github.com/trekawek/toxiproxy-java/releases) - [Changelog](https://github.com/trekawek/toxiproxy-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/trekawek/toxiproxy-java/compare/toxiproxy-java-2.1.3...toxiproxy-java-2.1.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/toxiproxy/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index 293b8f8f190..47221d68e40 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Toxiproxy" dependencies { compile project(':testcontainers') - compile 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.3' + compile 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.4' testCompile 'redis.clients:jedis:3.0.1' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 1d551b664c5b0f4f46a2ddfd22041f5afcd1e09a Mon Sep 17 00:00:00 2001 From: Ray Tsang Date: Tue, 1 Dec 2020 23:56:15 -0800 Subject: [PATCH 1099/4969] More examples in the gcloud module doc (#3463) * updated gcloud module doc * document container images to use * updated example links * fixed links --- docs/modules/gcloud.md | 110 ++++++++++++++++-- .../FirestoreEmulatorContainerTest.java | 8 +- .../PubSubEmulatorContainerTest.java | 13 ++- .../SpannerEmulatorContainerTest.java | 12 +- 4 files changed, 130 insertions(+), 13 deletions(-) diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 3400ad881a9..041129919ee 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -3,29 +3,119 @@ !!! note This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. -Testcontainers module for the Google's [Cloud SDK](https://cloud.google.com/sdk/). +Testcontainers module for the Google Cloud Platform's [Cloud SDK](https://cloud.google.com/sdk/). -Currently, the module supports `Datastore`, `Firestore`, `Pub/Sub` and `Spanner` emulators. In order to use it, you should use the following classes: +Currently, the module supports `Datastore`, `Firestore`, `Spanner`, and `Pub/Sub` emulators. In order to use it, you should use the following classes: -* DatastoreEmulatorContainer -* FirestoreEmulatorContainer -* PubSubEmulatorContainer -* SpannerEmulatorContainer +Class | Container Image +-|- +DatastoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/cloud-sdk:emulators](https://gcr.io/google.com/cloudsdktool/cloud-sdk) +FirestoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/cloud-sdk:emulators](https://gcr.io/google.com/cloudsdktool/cloud-sdk) +SpannerEmulatorContainer | [gcr.io/cloud-spanner-emulator/emulator](https://gcr.io/cloud-spanner-emulator/emulator) +PubSubEmulatorContainer | [gcr.io/google.com/cloudsdktool/cloud-sdk:emulators](https://gcr.io/google.com/cloudsdktool/cloud-sdk) ## Usage example -Running GCloud as a stand-in for Google Datastore during a test: +### Datastore + +Start Datastore Emulator during a test: + + +[Starting a Datastore Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) inside_block:creatingDatastoreEmulatorContainer + + +And test against the Emulator: + + +[Testing with a Datastore Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) inside_block:startingDatastoreEmulatorContainer + + +See more examples: + + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) + * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/datastore-example/src/test/java/com/example/springboot/datastore) + +### Firestore + +Start Firestore Emulator during a test: + + +[Starting a Firestore Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java) inside_block:emulatorContainer + + +And test against the Emulator: + + +[Testing with a Firestore Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java) inside_block:testWithEmulatorContainer + + +See more examples: + + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java) + * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/firestore-example/src/test/java/com/example/springboot/firestore/FirestoreIntegrationTests.java) + +### Spanner + +Start Spanner Emulator during a test: + + +[Starting a Spanner Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java) inside_block:emulatorContainer + + +Create a test Spanner Instance in the Emulator: + + +[Create a test Spanner instance](../../modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java) inside_block:createInstance + + +Create a test Database in the Emulator: + + +[Creating a test Spanner database](../../modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java) inside_block:createDatabase + + +And test against the Emulator: + + +[Testing with a Firestore Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java) inside_block:testWithEmulatorContainer + + +See more examples: + + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java) + * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/spanner-example/src/test/java/com/example/springboot/spanner/SpannerIntegrationTests.java) + +### Pub/Sub + +Start Pub/Sub Emulator during a test: + + +[Starting a Pub/Sub Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) inside_block:emulatorContainer + + +Create a test Pub/Sub topic the Emulator: -[Creating a Datastore container](../../modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) inside_block:creatingDatastoreEmulatorContainer +[Create a test topic](../../modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) inside_block:createTopic -And how to start it: +Create a test Pub/Sub subscription in the Emulator: -[Starting a Datastore container](../../modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) inside_block:startingDatastoreEmulatorContainer +[Create a test subscription](../../modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) inside_block:createSubscription +And test against the Emulator: + + +[Testing with a Pub/Sub Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) inside_block:testWithEmulatorContainer + + +See more examples: + + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) + * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/pubsub-example/src/test/java/com/example/springboot/pubsub/PubSubIntegrationTests.java) + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java index 4003ebdd342..138ff946f6f 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java @@ -20,8 +20,13 @@ public class FirestoreEmulatorContainerTest { @Rule - public FirestoreEmulatorContainer emulator = new FirestoreEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators")); + // emulatorContainer { + public FirestoreEmulatorContainer emulator = new FirestoreEmulatorContainer( + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") + ); + // } + // testWithEmulatorContainer { @Test public void testSimple() throws ExecutionException, InterruptedException { FirestoreOptions options = FirestoreOptions.getDefaultInstance().toBuilder() @@ -44,5 +49,6 @@ public void testSimple() throws ExecutionException, InterruptedException { assertThat(querySnapshot.getDocuments().get(0).getData()).containsEntry("first", "Ada"); } + // } } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java index 3ea9f831d8e..2e692956418 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java @@ -33,9 +33,15 @@ public class PubSubEmulatorContainerTest { public static final String PROJECT_ID = "my-project-id"; @Rule - public PubSubEmulatorContainer emulator = new PubSubEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators")); + // emulatorContainer { + public PubSubEmulatorContainer emulator = new PubSubEmulatorContainer( + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") + ); + // } + @Test + // testWithEmulatorContainer { public void testSimple() throws IOException { String hostport = emulator.getEmulatorEndpoint(); ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build(); @@ -76,7 +82,9 @@ public void testSimple() throws IOException { channel.shutdown(); } } + // } + // createTopic { private void createTopic(String topicId, TransportChannelProvider channelProvider, NoCredentialsProvider credentialsProvider) throws IOException { TopicAdminSettings topicAdminSettings = TopicAdminSettings.newBuilder() .setTransportChannelProvider(channelProvider) @@ -87,7 +95,9 @@ private void createTopic(String topicId, TransportChannelProvider channelProvide topicAdminClient.createTopic(topicName); } } + // } + // createSubscription { private void createSubscription(String subscriptionId, String topicId, TransportChannelProvider channelProvider, NoCredentialsProvider credentialsProvider) throws IOException { SubscriptionAdminSettings subscriptionAdminSettings = SubscriptionAdminSettings.newBuilder() .setTransportChannelProvider(channelProvider) @@ -97,5 +107,6 @@ private void createSubscription(String subscriptionId, String topicId, Transport ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(PROJECT_ID, subscriptionId); subscriptionAdminClient.createSubscription(subscriptionName, TopicName.of(PROJECT_ID, topicId), PushConfig.getDefaultInstance(), 10); } + // } } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java index 5a47f9429ad..f801ca5b547 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java @@ -25,12 +25,17 @@ public class SpannerEmulatorContainerTest { @Rule - public SpannerEmulatorContainer emulator = new SpannerEmulatorContainer(DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.1.0")); + // emulatorContainer { + public SpannerEmulatorContainer emulator = new SpannerEmulatorContainer( + DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.1.0") + ); + // } private static final String PROJECT_NAME = "test-project"; private static final String INSTANCE_NAME = "test-instance"; private static final String DATABASE_NAME = "test-database"; + // testWithEmulatorContainer { @Test public void testSimple() throws ExecutionException, InterruptedException { SpannerOptions options = SpannerOptions.newBuilder() @@ -62,12 +67,16 @@ public void testSimple() throws ExecutionException, InterruptedException { assertThat(resultSet.getLong(0)).isEqualTo(1); assertThat(resultSet.getString(1)).isEqualTo("Java"); } + // } + // createDatabase { private void createDatabase(Spanner spanner) throws InterruptedException, ExecutionException { DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient(); Database database = dbAdminClient.createDatabase(INSTANCE_NAME, DATABASE_NAME, Arrays.asList("CREATE TABLE TestTable (Key INT64, Value STRING(MAX)) PRIMARY KEY (Key)")).get(); } + // } + // createInstance { private InstanceId createInstance(Spanner spanner) throws InterruptedException, ExecutionException { InstanceConfigId instanceConfig = InstanceConfigId.of(PROJECT_NAME, "emulator-config"); InstanceId instanceId = InstanceId.of(PROJECT_NAME, INSTANCE_NAME); @@ -75,5 +84,6 @@ private InstanceId createInstance(Spanner spanner) throws InterruptedException, Instance instance = insAdminClient.createInstance(InstanceInfo.newBuilder(instanceId).setNodeCount(1).setDisplayName("Test instance").setInstanceConfigId(instanceConfig).build()).get(); return instanceId; } + // } } From dc0588e8a1272193e7f2ea59d2ac97d1f4110c39 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 2 Dec 2020 18:02:37 +0100 Subject: [PATCH 1100/4969] Pre-resolve LazyDockerClient from `GenericContainer#start()` (#3530) --- .../java/org/testcontainers/containers/GenericContainer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 641096a0779..bece4ef3378 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -305,6 +305,8 @@ public void start() { return; } Startables.deepStart(dependencies).get(); + // trigger LazyDockerClient's resolve so that we fail fast here and not in getDockerImageName() + dockerClient.authConfig(); doStart(); } From 602343a87c06c53618b666e3b774652aa16e3dda Mon Sep 17 00:00:00 2001 From: Philip Graf Date: Tue, 8 Dec 2020 15:29:09 +0100 Subject: [PATCH 1101/4969] Support timestamps with offset from "inspect image" (#3055) The command "inspect image" can return a "created" timestamp without a time zone offset (e.g. "2020-07-27T18:23:31.365190246Z") or with a time zone offset (e.g. "2020-07-27T18:23:31.365190246+02:00"). This change adds support for timestamps with a time zone offset. Co-authored-by: Sergei Egorov --- .../org/testcontainers/images/ImageData.java | 3 ++- .../testcontainers/images/ImageDataTest.java | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/org/testcontainers/images/ImageDataTest.java diff --git a/core/src/main/java/org/testcontainers/images/ImageData.java b/core/src/main/java/org/testcontainers/images/ImageData.java index 54b07d5acf2..345b5939268 100644 --- a/core/src/main/java/org/testcontainers/images/ImageData.java +++ b/core/src/main/java/org/testcontainers/images/ImageData.java @@ -7,6 +7,7 @@ import lombok.Value; import java.time.Instant; +import java.time.ZonedDateTime; @Value @Builder @@ -17,7 +18,7 @@ public class ImageData { static ImageData from(InspectImageResponse inspectImageResponse) { return ImageData.builder() - .createdAt(Instant.parse(inspectImageResponse.getCreated())) + .createdAt(ZonedDateTime.parse(inspectImageResponse.getCreated()).toInstant()) .build(); } diff --git a/core/src/test/java/org/testcontainers/images/ImageDataTest.java b/core/src/test/java/org/testcontainers/images/ImageDataTest.java new file mode 100644 index 00000000000..3b473cf7ffd --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/ImageDataTest.java @@ -0,0 +1,27 @@ +package org.testcontainers.images; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Instant; + +import org.junit.Test; + +import com.github.dockerjava.api.command.InspectImageResponse; + +public class ImageDataTest { + + @Test + public void shouldReadTimestampWithoutOffsetFromInspectImageResponse() { + final String timestamp = "2020-07-27T18:23:31.365190246Z"; + final ImageData imageData = ImageData.from(new InspectImageResponse().withCreated(timestamp)); + assertThat(imageData.getCreatedAt()).isEqualTo(Instant.parse(timestamp)); + } + + @Test + public void shouldReadTimestampWithOffsetFromInspectImageResponse() { + final String timestamp = "2020-07-27T18:23:31.365190246+02:00"; + final ImageData imageData = ImageData.from(new InspectImageResponse().withCreated(timestamp)); + assertThat(imageData.getCreatedAt()).isEqualTo(Instant.parse("2020-07-27T16:23:31.365190246Z")); + } + +} From b0cc476550e12396030e5c819d5556f050e3db38 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 9 Dec 2020 23:15:56 +0100 Subject: [PATCH 1102/4969] Avoid using the image name filter. Fixes #3574 (#3575) * filter images by reference. Fixes #3574 * Use `inspectImageCmd` --- .../main/java/org/testcontainers/DockerClientFactory.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index d44cd3b5b6f..192a6b06ddb 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.ListImagesCmd; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AccessMode; @@ -36,6 +37,7 @@ import java.io.InputStream; import java.net.URI; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; @@ -326,8 +328,9 @@ private boolean checkMountableFile() { */ @SneakyThrows public void checkAndPullImage(DockerClient client, String image) { - List images = client.listImagesCmd().withImageNameFilter(image).exec(); - if (images.isEmpty()) { + try { + client.inspectImageCmd(image).exec(); + } catch (NotFoundException e) { client.pullImageCmd(image).exec(new TimeLimitedLoggedPullImageResultCallback(log)).awaitCompletion(); } } From d8df52e2168398b76392fce56f99e886253f8b44 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 10 Dec 2020 09:44:24 +0100 Subject: [PATCH 1103/4969] avoid code duplication by using `ContainerState` in `ResourceReaper` (#3573) --- .../testcontainers/DockerClientFactory.java | 6 +-- .../utility/ResourceReaper.java | 49 ++++++++++++++----- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 192a6b06ddb..98e8249e4e5 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -177,8 +177,7 @@ public DockerClient client() { final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); - String hostIpAddress = strategy.getDockerHostIpAddress(); - log.info("Docker host IP address is {}", hostIpAddress); + log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); final DockerClient client = new DelegatingDockerClient(strategy.getDockerClient()) { @Override public void close() { @@ -202,7 +201,8 @@ public void close() { if (useRyuk) { log.debug("Ryuk is enabled"); try { - ryukContainerId = ResourceReaper.start(hostIpAddress, client); + //noinspection deprecation + ryukContainerId = ResourceReaper.start(client); } catch (RuntimeException e) { cachedClientFailure = e; throw e; diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 3b0cfa1e289..f409dbbc865 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -9,7 +9,6 @@ import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Network; -import com.github.dockerjava.api.model.Ports; import com.github.dockerjava.api.model.Volume; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; @@ -21,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.ContainerState; import java.io.BufferedReader; import java.io.IOException; @@ -70,8 +70,23 @@ private ResourceReaper() { dockerClient = DockerClientFactory.instance().client(); } - @SneakyThrows(InterruptedException.class) + + /** + * + * @deprecated internal API + */ + @Deprecated public static String start(String hostIpAddress, DockerClient client) { + return start(client); + } + + /** + * + * @deprecated internal API + */ + @Deprecated + @SneakyThrows(InterruptedException.class) + public static String start(DockerClient client) { String ryukImage = ImageNameSubstitutor.instance() .apply(DockerImageName.parse("testcontainers/ryuk:0.3.0")) .asCanonicalNameString(); @@ -107,14 +122,22 @@ public void onNext(Frame frame) { } }); - InspectContainerResponse inspectedContainer = client.inspectContainerCmd(ryukContainerId).exec(); + ContainerState containerState = new ContainerState() { - Integer ryukPort = inspectedContainer.getNetworkSettings().getPorts().getBindings().values().stream() - .flatMap(Stream::of) - .findFirst() - .map(Ports.Binding::getHostPortSpec) - .map(Integer::parseInt) - .get(); + final InspectContainerResponse inspectedContainer = client.inspectContainerCmd(ryukContainerId).exec(); + + @Override + public List getExposedPorts() { + return Stream.of(getContainerInfo().getConfig().getExposedPorts()) + .map(ExposedPort::getPort) + .collect(Collectors.toList()); + } + + @Override + public InspectContainerResponse getContainerInfo() { + return inspectedContainer; + } + }; CountDownLatch ryukScheduledLatch = new CountDownLatch(1); @@ -126,13 +149,15 @@ public void onNext(Frame frame) { ); } + String host = containerState.getHost(); + Integer ryukPort = containerState.getFirstMappedPort(); Thread kiraThread = new Thread( DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { while (true) { RYUK_ACK_RATE_LIMITER.doWhenReady(() -> { int index = 0; - try(Socket clientSocket = new Socket(hostIpAddress, ryukPort)) { + try(Socket clientSocket = new Socket(host, ryukPort)) { FilterRegistry registry = new FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); synchronized (DEATH_NOTE) { @@ -157,7 +182,7 @@ public void onNext(Frame frame) { } } } catch (IOException e) { - log.warn("Can not connect to Ryuk at {}:{}", hostIpAddress, ryukPort, e); + log.warn("Can not connect to Ryuk at {}:{}", host, ryukPort, e); } }); } @@ -170,7 +195,7 @@ public void onNext(Frame frame) { // We need to wait before we can start any containers to make sure that we delete them if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { log.error("Timed out waiting for Ryuk container to start. Ryuk's logs:\n{}", ryukLog); - throw new IllegalStateException(String.format("Could not connect to Ryuk at %s:%s", hostIpAddress, ryukPort)); + throw new IllegalStateException(String.format("Could not connect to Ryuk at %s:%s", host, ryukPort)); } } finally { try { From 0e263f296556c2357f0d4ea99d120a3a2880ceb3 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 10 Dec 2020 10:53:33 +0000 Subject: [PATCH 1104/4969] Default prefixing image substitutor (#3413) Co-authored-by: Sergei Egorov --- .../utility/DefaultImageNameSubstitutor.java | 14 +- .../utility/DockerImageName.java | 27 ++-- .../PrefixingImageNameSubstitutor.java | 58 ++++++++ .../utility/TestcontainersConfiguration.java | 3 - .../testcontainers/utility/Versioning.java | 1 + ...estcontainers.utility.ImageNameSubstitutor | 1 + .../DockerImageNameCompatibilityTest.java | 8 +- .../PrefixingImageNameSubstitutorTest.java | 140 ++++++++++++++++++ docs/features/image_name_substitution.md | 32 +++- 9 files changed, 257 insertions(+), 27 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java create mode 100644 core/src/main/resources/META-INF/services/org.testcontainers.utility.ImageNameSubstitutor create mode 100644 core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java diff --git a/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java index bcc7c96ba18..840b8a77b40 100644 --- a/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java +++ b/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java @@ -5,31 +5,37 @@ /** * Testcontainers' default implementation of {@link ImageNameSubstitutor}. - * Delegates to {@link ConfigurationFileImageNameSubstitutor}. + * Delegates to {@link ConfigurationFileImageNameSubstitutor} followed by {@link PrefixingImageNameSubstitutor}. */ @Slf4j final class DefaultImageNameSubstitutor extends ImageNameSubstitutor { private final ConfigurationFileImageNameSubstitutor configurationFileImageNameSubstitutor; + private final PrefixingImageNameSubstitutor prefixingImageNameSubstitutor; public DefaultImageNameSubstitutor() { configurationFileImageNameSubstitutor = new ConfigurationFileImageNameSubstitutor(); + prefixingImageNameSubstitutor = new PrefixingImageNameSubstitutor(); } @VisibleForTesting DefaultImageNameSubstitutor( - final ConfigurationFileImageNameSubstitutor configurationFileImageNameSubstitutor + final ConfigurationFileImageNameSubstitutor configurationFileImageNameSubstitutor, + final PrefixingImageNameSubstitutor prefixingImageNameSubstitutor ) { this.configurationFileImageNameSubstitutor = configurationFileImageNameSubstitutor; + this.prefixingImageNameSubstitutor = prefixingImageNameSubstitutor; } @Override public DockerImageName apply(final DockerImageName original) { - return configurationFileImageNameSubstitutor.apply(original); + return configurationFileImageNameSubstitutor + .andThen(prefixingImageNameSubstitutor) + .apply(original); } @Override protected String getDescription() { - return "DefaultImageNameSubstitutor (" + configurationFileImageNameSubstitutor.getDescription() + ")"; + return "DefaultImageNameSubstitutor (composite of '" + configurationFileImageNameSubstitutor.getDescription() + "' and '" + prefixingImageNameSubstitutor.getDescription() + "')"; } } diff --git a/core/src/main/java/org/testcontainers/utility/DockerImageName.java b/core/src/main/java/org/testcontainers/utility/DockerImageName.java index af8e5300863..b9d266a41ca 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerImageName.java +++ b/core/src/main/java/org/testcontainers/utility/DockerImageName.java @@ -5,6 +5,7 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; +import lombok.Getter; import lombok.With; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -24,8 +25,8 @@ public final class DockerImageName { private static final Pattern REPO_NAME = Pattern.compile(REPO_NAME_PART + "(/" + REPO_NAME_PART + ")*"); private final String rawName; - private final String registry; - private final String repo; + @With @Getter private final String registry; + @With @Getter private final String repository; @NotNull @With(AccessLevel.PRIVATE) private final Versioning versioning; @Nullable @With(AccessLevel.PRIVATE) @@ -68,13 +69,13 @@ public DockerImageName(String fullImageName) { } if (remoteName.contains("@sha256:")) { - repo = remoteName.split("@sha256:")[0]; + repository = remoteName.split("@sha256:")[0]; versioning = new Sha256Versioning(remoteName.split("@sha256:")[1]); } else if (remoteName.contains(":")) { - repo = remoteName.split(":")[0]; + repository = remoteName.split(":")[0]; versioning = new TagVersioning(remoteName.split(":")[1]); } else { - repo = remoteName; + repository = remoteName; versioning = Versioning.ANY; } @@ -110,10 +111,10 @@ public DockerImageName(String nameWithoutTag, @NotNull String version) { } if (version.startsWith("sha256:")) { - repo = remoteName; + repository = remoteName; versioning = new Sha256Versioning(version.replace("sha256:", "")); } else { - repo = remoteName; + repository = remoteName; versioning = new TagVersioning(version); } @@ -125,9 +126,9 @@ public DockerImageName(String nameWithoutTag, @NotNull String version) { */ public String getUnversionedPart() { if (!"".equals(registry)) { - return registry + "/" + repo; + return registry + "/" + repository; } else { - return repo; + return repository; } } @@ -158,18 +159,14 @@ public String toString() { public void assertValid() { //noinspection UnstableApiUsage HostAndPort.fromString(registry); // return value ignored - this throws if registry is not a valid host:port string - if (!REPO_NAME.matcher(repo).matches()) { - throw new IllegalArgumentException(repo + " is not a valid Docker image name (in " + rawName + ")"); + if (!REPO_NAME.matcher(repository).matches()) { + throw new IllegalArgumentException(repository + " is not a valid Docker image name (in " + rawName + ")"); } if (!versioning.isValid()) { throw new IllegalArgumentException(versioning + " is not a valid image versioning identifier (in " + rawName + ")"); } } - public String getRegistry() { - return registry; - } - /** * @param newTag version tag for the copy to use * @return an immutable copy of this {@link DockerImageName} with the new version tag diff --git a/core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java new file mode 100644 index 00000000000..c720416deac --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java @@ -0,0 +1,58 @@ +package org.testcontainers.utility; + +import com.google.common.annotations.VisibleForTesting; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * An {@link ImageNameSubstitutor} which applies a prefix to all image names, e.g. a private registry host and path. + * The prefix may be set via an environment variable (TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX) or an equivalent + * configuration file entry (see {@link TestcontainersConfiguration}). + */ +@NoArgsConstructor +@Slf4j +final class PrefixingImageNameSubstitutor extends ImageNameSubstitutor { + + @VisibleForTesting + static final String PREFIX_PROPERTY_KEY = "hub.image.name.prefix"; + + private TestcontainersConfiguration configuration = TestcontainersConfiguration.getInstance(); + + @VisibleForTesting + PrefixingImageNameSubstitutor(final TestcontainersConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public DockerImageName apply(DockerImageName original) { + final String configuredPrefix = configuration.getEnvVarOrProperty(PREFIX_PROPERTY_KEY, ""); + + if (configuredPrefix.isEmpty()) { + log.debug("No prefix is configured"); + return original; + } + + boolean isAHubImage = original.getRegistry().isEmpty(); + if (!isAHubImage) { + log.debug("Image {} is not a Docker Hub image - not applying registry/repository change", original); + return original; + } + + log.debug( + "Applying changes to image name {}: applying prefix '{}'", + original, + configuredPrefix + ); + + DockerImageName prefixAsImage = DockerImageName.parse(configuredPrefix); + + return original + .withRegistry(prefixAsImage.getRegistry()) + .withRepository(prefixAsImage.getRepository() + original.getRepository()); + } + + @Override + protected String getDescription() { + return getClass().getSimpleName(); + } +} diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 47c274c05e6..3b4d9f8f70c 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -212,7 +212,6 @@ private String getConfigurable(@NotNull final String propertyName, @Nullable fin * @param propertyName name of configuration file property (dot-separated lower case) * @return the found value, or null if not set */ - @Nullable @Contract("_, !null -> !null") public String getEnvVarOrProperty(@NotNull final String propertyName, @Nullable final String defaultValue) { return getConfigurable(propertyName, defaultValue, userProperties, classpathProperties); @@ -225,7 +224,6 @@ public String getEnvVarOrProperty(@NotNull final String propertyName, @Nullable * @param propertyName name of configuration file property (dot-separated lower case) * @return the found value, or null if not set */ - @Nullable @Contract("_, !null -> !null") public String getEnvVarOrUserProperty(@NotNull final String propertyName, @Nullable final String defaultValue) { return getConfigurable(propertyName, defaultValue, userProperties); @@ -238,7 +236,6 @@ public String getEnvVarOrUserProperty(@NotNull final String propertyName, @Nulla * @param propertyName name of configuration file property (dot-separated lower case) * @return the found value, or null if not set */ - @Nullable @Contract("_, !null -> !null") public String getUserProperty(@NotNull final String propertyName, @Nullable final String defaultValue) { return getConfigurable(propertyName, defaultValue); diff --git a/core/src/main/java/org/testcontainers/utility/Versioning.java b/core/src/main/java/org/testcontainers/utility/Versioning.java index 84dcf46274e..4b1da407440 100644 --- a/core/src/main/java/org/testcontainers/utility/Versioning.java +++ b/core/src/main/java/org/testcontainers/utility/Versioning.java @@ -46,6 +46,7 @@ public int hashCode() { @EqualsAndHashCode class TagVersioning implements Versioning { public static final String TAG_REGEX = "[\\w][\\w.\\-]{0,127}"; + static final TagVersioning LATEST = new TagVersioning("latest"); private final String tag; TagVersioning(String tag) { diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.utility.ImageNameSubstitutor b/core/src/main/resources/META-INF/services/org.testcontainers.utility.ImageNameSubstitutor new file mode 100644 index 00000000000..069dc7ee710 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.testcontainers.utility.ImageNameSubstitutor @@ -0,0 +1 @@ +org.testcontainers.utility.DefaultImageNameSubstitutor diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java index 7c794814faf..22d67de5785 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java @@ -1,13 +1,13 @@ package org.testcontainers.utility; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - import static org.hamcrest.core.StringContains.containsString; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + public class DockerImageNameCompatibilityTest { diff --git a/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java new file mode 100644 index 00000000000..d2c33989deb --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java @@ -0,0 +1,140 @@ +package org.testcontainers.utility; + +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.testcontainers.utility.PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY; + +public class PrefixingImageNameSubstitutorTest { + + private TestcontainersConfiguration mockConfiguration; + private PrefixingImageNameSubstitutor underTest; + + @Before + public void setUp() { + mockConfiguration = mock(TestcontainersConfiguration.class); + underTest = new PrefixingImageNameSubstitutor(mockConfiguration); + } + + @Test + public void testHappyPath() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); + + assertEquals( + "The prefix is applied", + "someregistry.com/our-mirror/some/image:tag", + result.asCanonicalNameString() + ); + } + + @Test + public void hubIoRegistryIsNotChanged() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("docker.io/some/image:tag")); + + assertEquals( + "The prefix is applied", + "docker.io/some/image:tag", + result.asCanonicalNameString() + ); + } + + @Test + public void hubComRegistryIsNotChanged() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("registry.hub.docker.com/some/image:tag")); + + assertEquals( + "The prefix is applied", + "registry.hub.docker.com/some/image:tag", + result.asCanonicalNameString() + ); + } + + @Test + public void thirdPartyRegistriesNotAffected() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("gcr.io/something/image:tag")); + + assertEquals( + "The prefix is not applied if a third party registry is used", + "gcr.io/something/image:tag", + result.asCanonicalNameString() + ); + } + + @Test + public void testNoDoublePrefixing() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("someregistry.com/some/image:tag")); + + assertEquals( + "The prefix is not applied if already present", + "someregistry.com/some/image:tag", + result.asCanonicalNameString() + ); + } + + @Test + public void testHandlesEmptyValue() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn(""); + + final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); + + assertEquals( + "The prefix is not applied if the env var is not set", + "some/image:tag", + result.asCanonicalNameString() + ); + } + + @Test + public void testHandlesRegistryOnlyWithTrailingSlash() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); + + assertEquals( + "The prefix is applied", + "someregistry.com/some/image:tag", + result.asCanonicalNameString() + ); + } + + @Test + public void testCombinesLiterallyForRegistryOnlyWithoutTrailingSlash() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); + + assertEquals( + "The prefix is applied", + "someregistry.comsome/image:tag", // treating the prefix literally, for predictability + result.asCanonicalNameString() + ); + } + + @Test + public void testCombinesLiterallyForBothPartsWithoutTrailingSlash() { + when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror"); + + final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); + + assertEquals( + "The prefix is applied", + "someregistry.com/our-mirrorsome/image:tag", // treating the prefix literally, for predictability + result.asCanonicalNameString() + ); + } +} diff --git a/docs/features/image_name_substitution.md b/docs/features/image_name_substitution.md index 45ea6038b49..37088473d72 100644 --- a/docs/features/image_name_substitution.md +++ b/docs/features/image_name_substitution.md @@ -45,7 +45,37 @@ to: +## Automatically modifying Docker Hub image names +Testcontainers can be configured to modify Docker Hub image names on the fly to apply a prefix string. + +Consider this if: + +* Developers and CI machines need to use different image names. For example, developers are able to pull images from Docker Hub, but CI machines need to pull from a private registry +* Your private registry has copies of images from Docker Hub where the names are predictable, and just adding a prefix is enough. + For example, `registry.mycompany.com/mirror/mysql:8.0.22` can be derived from the original Docker Hub image name (`mysql:8.0.22`) with a consistent prefix string: `registry.mycompany.com/mirror/` + +In this case, image name references in code are **unchanged**. +i.e. you would leave as-is: + + +[Unchanged direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference + + +You can then configure Testcontainers to apply the prefix `registry.mycompany.com/mirror/` to every image that it tries to pull from Docker Hub. +This can be done in one of two ways: + +* Setting environment variables `TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX=registry.mycompany.com/mirror/` +* Via config file, setting `hub.image.name.prefix` in either: + * the `~/.testcontainers.properties` file in your user home directory, or + * a file named `testcontainers.properties` on the classpath + +Testcontainers will automatically apply the prefix to every image that it pulls from Docker Hub - please verify that all [the required images](../supported_docker_environment/image_registry_rate_limiting.md#which-images-are-used-by-testcontainers) exist in your registry. + +Testcontainers will not apply the prefix to: + +* non-Hub image names (e.g. where another registry is set) +* Docker Hub image names where the hub registry is explicitly part of the name (i.e. anything with a `docker.io` or `registry.hub.docker.com` host part) @@ -54,7 +84,7 @@ to: Consider this if: * You have complex rules about which private registry images should be used as substitutes, e.g.: - * non-deterministic mapping of names meaning that a [name prefix](#adding-a-registry-url-prefix-to-image-names-automatically) cannot be used + * non-deterministic mapping of names meaning that a [name prefix](#automatically-modifying-docker-hub-image-names) cannot be used * rules depending upon developer identity or location * or you wish to add audit logging of images used in the build * or you wish to prevent accidental usage of images that are not on an approved list From f76970f570fd1f1dcd0a6087162de8a3e7733d29 Mon Sep 17 00:00:00 2001 From: Ray Tsang Date: Thu, 10 Dec 2020 18:59:21 +0800 Subject: [PATCH 1105/4969] Added Bigtable emulator container support (#3466) * Added Bigtable emulator container support * changed port to be consistent w/ other emulators * Update modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java Co-authored-by: Sergei Egorov * Removed `getEmulatorHost` Co-authored-by: Sergei Egorov --- modules/gcloud/build.gradle | 1 + .../containers/BigtableEmulatorContainer.java | 44 +++++++++ .../BigtableEmulatorContainerTest.java | 95 +++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java create mode 100644 modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index a5737648a4b..aa42d7dc560 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,5 +7,6 @@ dependencies { testCompile 'com.google.cloud:google-cloud-firestore:1.33.0' testCompile 'com.google.cloud:google-cloud-pubsub:1.105.0' testCompile 'com.google.cloud:google-cloud-spanner:1.50.0' + testCompile 'com.google.cloud:google-cloud-bigtable:1.17.3' testCompile 'org.assertj:assertj-core:3.15.0' } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java new file mode 100644 index 00000000000..4b81e3964ce --- /dev/null +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java @@ -0,0 +1,44 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; + +/** + * A Bigtable container that relies in google cloud sdk. + * + * Default port is 9000. + * + * @author Eddú Meléndez + * @author Ray Tsang + */ +public class BigtableEmulatorContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + + private static final String CMD = "gcloud beta emulators bigtable start --host-port 0.0.0.0:9000"; + private static final int PORT = 9000; + + public BigtableEmulatorContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(PORT); + setWaitStrategy(new LogMessageWaitStrategy() + .withRegEx("(?s).*running.*$")); + withCommand("/bin/sh", "-c", CMD); + } + + /** + * @return a host:port pair corresponding to the address on which the emulator is + * reachable from the test host machine. Directly usable as a parameter to the + * com.google.cloud.ServiceOptions.Builder#setHost(java.lang.String) method. + */ + public String getEmulatorEndpoint() { + return getHost() + ":" + getEmulatorPort(); + } + + public int getEmulatorPort() { + return getMappedPort(PORT); + } +} diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java new file mode 100644 index 00000000000..0cc44afcc77 --- /dev/null +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java @@ -0,0 +1,95 @@ +package org.testcontainers.containers; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.api.core.ApiFuture; +import com.google.api.gax.batching.Batcher; +import com.google.api.gax.core.CredentialsProvider; +import com.google.api.gax.core.NoCredentialsProvider; +import com.google.api.gax.grpc.GrpcTransportChannel; +import com.google.api.gax.rpc.FixedTransportChannelProvider; +import com.google.api.gax.rpc.TransportChannelProvider; +import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminClient; +import com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient; +import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest; +import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest; +import com.google.cloud.bigtable.admin.v2.models.Instance; +import com.google.cloud.bigtable.admin.v2.models.Table; +import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub; +import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStubSettings; +import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings; +import com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub; +import com.google.cloud.bigtable.data.v2.BigtableDataClient; +import com.google.cloud.bigtable.data.v2.BigtableDataSettings; +import com.google.cloud.bigtable.data.v2.models.Row; +import com.google.cloud.bigtable.data.v2.models.RowCell; +import com.google.cloud.bigtable.data.v2.models.RowMutation; +import com.google.cloud.bigtable.data.v2.models.RowMutationEntry; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import java.io.IOException; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; + +public class BigtableEmulatorContainerTest { + + public static final String PROJECT_ID = "test-project"; + public static final String INSTANCE_ID = "test-instance"; + + @Rule + // emulatorContainer { + public BigtableEmulatorContainer emulator = new BigtableEmulatorContainer( + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") + ); + // } + + @Test + // testWithEmulatorContainer { + public void testSimple() throws IOException, InterruptedException, ExecutionException { + ManagedChannel channel = ManagedChannelBuilder.forTarget(emulator.getEmulatorEndpoint()) + .usePlaintext().build(); + + TransportChannelProvider channelProvider = FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel)); + NoCredentialsProvider credentialsProvider = NoCredentialsProvider.create(); + + try { + createTable(channelProvider, credentialsProvider, "test-table" ); + + BigtableDataClient client = BigtableDataClient.create(BigtableDataSettings + .newBuilderForEmulator(emulator.getHost(), emulator.getEmulatorPort()) + .setProjectId(PROJECT_ID) + .setInstanceId(INSTANCE_ID) + .build()); + + client.mutateRow(RowMutation.create("test-table", "1") + .setCell("name", "firstName", "Ray")); + + Row row = client.readRow("test-table", "1"); + List cells = row.getCells("name", "firstName"); + + assertThat(cells).isNotNull().hasSize(1); + assertThat(cells.get(0).getValue().toStringUtf8()).isEqualTo("Ray"); + } finally { + channel.shutdown(); + } + } + // } + + // createTable { + private void createTable(TransportChannelProvider channelProvider, CredentialsProvider credentialsProvider, String tableName) throws IOException { + EnhancedBigtableTableAdminStub stub = EnhancedBigtableTableAdminStub + .createEnhanced(BigtableTableAdminStubSettings.newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build()); + + try (BigtableTableAdminClient client = BigtableTableAdminClient.create(PROJECT_ID, INSTANCE_ID, stub)) { + Table table = client.createTable(CreateTableRequest.of(tableName).addFamily("name")); + } + } + // } +} From d60d490733a9646f8f6eff12d928909afcac86d7 Mon Sep 17 00:00:00 2001 From: Michal Hlavac Date: Thu, 10 Dec 2020 12:01:43 +0100 Subject: [PATCH 1106/4969] `PostgisContainerProvider` ignores tag parameter and uses `DEFAULT_TAG` (#3465) Co-authored-by: Michal Hlavac --- .../org/testcontainers/containers/PostgisContainerProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java index 76c213f0931..e41a349365c 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java @@ -27,7 +27,7 @@ public JdbcDatabaseContainer newInstance() { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new PostgreSQLContainer<>(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); + return new PostgreSQLContainer<>(DEFAULT_IMAGE_NAME.withTag(tag)); } @Override From 1b2d228e3099488c0e5de0c1e3a5dacbf4d3f88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavi=20Arias=20Segu=C3=AD?= <876579+xaviarias@users.noreply.github.com> Date: Thu, 10 Dec 2020 11:18:26 +0000 Subject: [PATCH 1107/4969] Add `HttpWaitStrategy#withMethod` (#3533) --- .../containers/wait/strategy/HttpWaitStrategy.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java index 5fd7834b12d..a2bf4c4899e 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java @@ -35,6 +35,7 @@ public class HttpWaitStrategy extends AbstractWaitStrategy { private static final String AUTH_BASIC = "Basic "; private String path = "/"; + private String method = "GET"; private Set statusCodes = new HashSet<>(); private boolean tlsEnabled; private String username; @@ -97,6 +98,17 @@ public HttpWaitStrategy usingTls() { return this; } + /** + * Indicates the HTTP method to use (GET by default). + * + * @param method the HTTP method. + * @return this + */ + public HttpWaitStrategy withMethod(String method) { + this.method = method; + return this; + } + /** * Authenticate with HTTP Basic Authorization credentials. * @@ -167,7 +179,7 @@ protected void waitUntilReady() { connection.setUseCaches(false); } - connection.setRequestMethod("GET"); + connection.setRequestMethod(method); connection.connect(); log.trace("Get response code {}", connection.getResponseCode()); From af678a3463e21a0b4d5118e507177d12759ae339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Artigao=20Carre=C3=B1o?= Date: Thu, 10 Dec 2020 12:28:28 +0100 Subject: [PATCH 1108/4969] Expose Toxiproxy control port and proxy name (#3454) * Expose Toxiproxy control port and proxy name In order to work with and external Toxiproxy client we need the control port to get the mapped port and the proxy names to interact with. * Accessor for Toxiproxy mapped control port Hidden the port constant again and created accessor for Toxiproxy mapped control port. --- .../containers/ToxiproxyContainer.java | 11 +++++++++++ .../testcontainers/containers/ToxiproxyTest.java | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index e6c143fa358..e22cc1fdd55 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -63,6 +63,13 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { client = new ToxiproxyClient(getHost(), getMappedPort(TOXIPROXY_CONTROL_PORT)); } + /** + * @return Publicly exposed Toxiproxy HTTP API control port. + */ + public int getControlPort() { + return getMappedPort(TOXIPROXY_CONTROL_PORT); + } + /** * Obtain a {@link ContainerProxy} instance for target container that is managed by Testcontainers. The target * container should be routable from this from this {@link ToxiproxyContainer} instance (e.g. on the same @@ -130,6 +137,10 @@ public static class ContainerProxy { @Getter private final int originalProxyPort; private boolean isCurrentlyCut; + public String getName() { + return toxi.getName(); + } + public ToxicList toxics() { return toxi.toxics(); } diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index 87f9758ebf1..3177fb2e8e8 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -149,6 +149,20 @@ public void testOriginalAndMappedPorts() { assertEquals("mapped port is correct", toxiproxy.getMappedPort(proxy2.getOriginalProxyPort()), proxy2.getProxyPort()); } + @Test + public void testProxyName() { + final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy("hostname", 7070); + + assertEquals("proxy name is hostname and port", "hostname:7070", proxy.getName()); + } + + @Test + public void testControlPort() { + final int controlPort = toxiproxy.getControlPort(); + + assertEquals("control port is mapped from port 8474", toxiproxy.getMappedPort(8474), controlPort); + } + private void checkCallWithLatency(Jedis jedis, final String description, int expectedMinLatency, long expectedMaxLatency) { final long start = System.currentTimeMillis(); String s = jedis.get("somekey"); From c3a8ca76d0ed69f71c94e5bc2f7f1e0eef1a2259 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 10 Dec 2020 20:58:26 +0100 Subject: [PATCH 1109/4969] Update to docker-java 3.2.7 (#3577) --- core/build.gradle | 8 ++++---- .../dockerclient/DockerClientProviderStrategy.java | 8 +++++++- .../testcontainers/containers/GenericContainerTest.java | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index ed0fc00d4f6..db624e555d9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -173,9 +173,9 @@ dependencies { compile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compile "com.github.docker-java:docker-java-api:3.2.6" + compile "com.github.docker-java:docker-java-api:3.2.7" - shaded ('com.github.docker-java:docker-java-core:3.2.6') { + shaded ('com.github.docker-java:docker-java-core:3.2.7') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') @@ -184,13 +184,13 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.6') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.7') { exclude(group: 'com.github.docker-java', module: 'docker-java-core') exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } - compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.6' + compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.7' shaded "org.yaml:snakeyaml:1.27" diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 1bd51da1263..35e3b6eabb8 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -5,6 +5,7 @@ import com.github.dockerjava.api.model.Network; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.core.RemoteApiVersion; import com.github.dockerjava.okhttp.OkDockerHttpClient; import com.github.dockerjava.transport.DockerHttpClient; import com.github.dockerjava.zerodep.ZerodepDockerHttpClient; @@ -236,9 +237,14 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) { throw new IllegalArgumentException("Unknown transport type '" + transportType + "'"); } + DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder(); + + if (configBuilder.build().getApiVersion() == RemoteApiVersion.UNKNOWN_VERSION) { + configBuilder.withApiVersion(RemoteApiVersion.VERSION_1_30); + } return DockerClientImpl.getInstance( new AuthDelegatingDockerClientConfig( - DefaultDockerClientConfig.createDefaultConfigBuilder() + configBuilder .withDockerHost(transportConfig.getDockerHost().toString()) .build() ), diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 5008ba5baca..e059a48709f 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -27,7 +27,7 @@ public class GenericContainerTest { public void shouldReportOOMAfterWait() { Info info = DockerClientFactory.instance().client().infoCmd().exec(); // Poor man's rootless Docker detection :D - Assumptions.assumeThat(info.getDriver()).doesNotContain("vfs"); + Assumptions.assumeThat(info.getSecurityOptions()).doesNotContain("rootless"); try ( GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new NoopStartupCheckStrategy()) From f033c13086d99d01f398d86187ee6a9a465b6ee2 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 11 Dec 2020 12:49:40 +0100 Subject: [PATCH 1110/4969] Always use Path for MountableFile (#3514) Also, be conscious on Windows when adding host bind for Docker socket. Make sure ContainerisedDockerCompose consciously uses Unix path when necessary. Fixes #3493 --- .../containers/DockerComposeContainer.java | 10 +++++++++- .../testcontainers/containers/GenericContainer.java | 10 ++++++++-- .../java/org/testcontainers/utility/MountableFile.java | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 7a67073e383..3d58ad53b3b 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -33,6 +33,7 @@ import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.LogUtils; import org.testcontainers.utility.MountableFile; +import org.testcontainers.utility.PathUtils; import org.testcontainers.utility.ResourceReaper; import org.zeroturnaround.exec.InvalidExitValueException; import org.zeroturnaround.exec.ProcessExecutor; @@ -618,12 +619,13 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { // Map the docker compose file into the container final File dockerComposeBaseFile = composeFiles.get(0); final String pwd = dockerComposeBaseFile.getAbsoluteFile().getParentFile().getAbsolutePath(); - final String containerPwd = MountableFile.forHostPath(pwd).getFilesystemPath(); + final String containerPwd = convertToUnixFilesystemPath(pwd); final List absoluteDockerComposeFiles = composeFiles.stream() .map(File::getAbsolutePath) .map(MountableFile::forHostPath) .map(MountableFile::getFilesystemPath) + .map(this::convertToUnixFilesystemPath) .collect(toList()); final String composeFileEnvVariableValue = Joiner.on(UNIX_PATH_SEPERATOR).join(absoluteDockerComposeFiles); // we always need the UNIX path separator logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); @@ -669,6 +671,12 @@ public void invoke() { StringUtils.join(this.getCommandParts(), ' ')); } } + + private String convertToUnixFilesystemPath(String path) { + return SystemUtils.IS_OS_WINDOWS + ? PathUtils.createMinGWPath(path).substring(1) + : path; + } } /** diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index bece4ef3378..0a0962cd6c0 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -63,6 +63,7 @@ import lombok.SneakyThrows; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.SystemUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.runner.Description; @@ -946,9 +947,14 @@ public void addEnv(String key, String value) { */ @Override public void addFileSystemBind(final String hostPath, final String containerPath, final BindMode mode, final SelinuxContext selinuxContext) { + if (SystemUtils.IS_OS_WINDOWS && hostPath.startsWith("/")) { + // e.g. Docker socket mount + binds.add(new Bind(hostPath, new Volume(containerPath), mode.accessMode, selinuxContext.selContext)); - final MountableFile mountableFile = MountableFile.forHostPath(hostPath); - binds.add(new Bind(mountableFile.getResolvedPath(), new Volume(containerPath), mode.accessMode, selinuxContext.selContext)); + } else { + final MountableFile mountableFile = MountableFile.forHostPath(hostPath); + binds.add(new Bind(mountableFile.getResolvedPath(), new Volume(containerPath), mode.accessMode, selinuxContext.selContext)); + } } /** diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 7b7367b9290..1982538f45d 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -105,7 +105,7 @@ public static MountableFile forClasspathResource(@NotNull final String resourceN * @return a {@link MountableFile} that may be used to obtain a mountable path */ public static MountableFile forHostPath(@NotNull final String path, Integer mode) { - return new MountableFile(new File(path).toURI().toString(), mode); + return forHostPath(Paths.get(path), mode); } /** From 16c82a4ab24b2a4b9d530ccd566d3ee386a92e9c Mon Sep 17 00:00:00 2001 From: Kirill Merkushev Date: Fri, 11 Dec 2020 15:06:55 +0100 Subject: [PATCH 1111/4969] Make MockServer compatible with newer (5.11.x) versions (#3437) Co-authored-by: Sergei Egorov --- docs/modules/mockserver.md | 6 +- .../containers/MockServerContainer.java | 5 +- .../MockServerContainerRuleTest.java | 40 +++++++++++++ .../containers/MockServerContainerTest.java | 56 +++++-------------- .../containers/SimpleHttpClient.java | 17 ++++++ 5 files changed, 80 insertions(+), 44 deletions(-) create mode 100644 modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java create mode 100644 modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java diff --git a/docs/modules/mockserver.md b/docs/modules/mockserver.md index 051cecf076e..ead9d123915 100644 --- a/docs/modules/mockserver.md +++ b/docs/modules/mockserver.md @@ -7,13 +7,13 @@ Mock Server can be used to mock HTTP services by matching requests against user- The following example shows how to start Mockserver. -[Creating a MockServer container](../../modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java) inside_block:creatingProxy +[Creating a MockServer container](../../modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java) inside_block:creatingProxy And how to set a simple expectation using the Java MockServerClient. -[Setting a simple expectation](../../modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java) inside_block:testSimpleExpectation +[Setting a simple expectation](../../modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java) inside_block:testSimpleExpectation ## Adding this module to your project dependencies @@ -33,3 +33,5 @@ testCompile "org.testcontainers:mockserver:{{latest_version}}" ``` +Additionally, don't forget to add a [client dependency `org.mock-server:mockserver-client-java`](https://search.maven.org/search?q=mockserver-client-java) +to be able to set expectations, it's not provided by the testcontainers module. Client version should match to the version in a container tag. diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index 451a4710b20..0502469208e 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import lombok.extern.slf4j.Slf4j; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; @Slf4j @@ -33,7 +34,9 @@ public MockServerContainer(String version) { public MockServerContainer(DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, DockerImageName.parse("mockserver/mockserver")); + + waitingFor(Wait.forHttp("/mockserver/status").withMethod("PUT").forStatusCode(200)); withCommand("-logLevel INFO -serverPort " + PORT); addExposedPorts(PORT); diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java new file mode 100644 index 00000000000..d0c290ad46a --- /dev/null +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java @@ -0,0 +1,40 @@ +package org.testcontainers.containers; + +import org.junit.Rule; +import org.junit.Test; +import org.mockserver.client.MockServerClient; +import org.testcontainers.utility.DockerImageName; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; + +public class MockServerContainerRuleTest { + + public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse("jamesdbloom/mockserver:mockserver-5.5.4"); + + // creatingProxy { + @Rule + public MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE); + // } + + @Test + public void shouldReturnExpectation() throws Exception { + // testSimpleExpectation { + new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) + .when(request() + .withPath("/person") + .withQueryStringParameter("name", "peter")) + .respond(response() + .withBody("Peter the person!")); + + // ...a GET request to '/person?name=peter' returns "Peter the person!" + // } + + assertThat("Expectation returns expected response body", + SimpleHttpClient.responseFromMockserver(mockServer, "/person?name=peter"), + containsString("Peter the person") + ); + } +} diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index e4d11ed3f39..61a5c33c630 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -1,57 +1,19 @@ package org.testcontainers.containers; -import lombok.Cleanup; -import org.junit.Rule; import org.junit.Test; import org.mockserver.client.MockServerClient; import org.testcontainers.utility.DockerImageName; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLConnection; - -import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class MockServerContainerTest { public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse("jamesdbloom/mockserver:mockserver-5.5.4"); - // creatingProxy { - @Rule - public MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE); - // } - - private static String responseFromMockserver(MockServerContainer mockServer, String path) throws IOException { - URLConnection urlConnection = new URL(mockServer.getEndpoint() + path).openConnection(); - @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - return reader.readLine(); - } - - @Test - public void shouldReturnExpectation() throws Exception { - // testSimpleExpectation { - new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) - .when(request() - .withPath("/person") - .withQueryStringParameter("name", "peter")) - .respond(response() - .withBody("Peter the person!")); - - // ...a GET request to '/person?name=peter' returns "Peter the person!" - // } - - assertThat("Expectation returns expected response body", - responseFromMockserver(mockServer, "/person?name=peter"), - containsString("Peter the person") - ); - } - @Test public void shouldCallActualMockserverVersion() throws Exception { String actualVersion = MockServerClient.class.getPackage().getImplementationVersion(); @@ -60,14 +22,26 @@ public void shouldCallActualMockserverVersion() throws Exception { String expectedBody = "Hello World!"; - new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) + MockServerClient client = new MockServerClient(mockServer.getHost(), mockServer.getServerPort()); + + assertTrue("Mockserver running", client.isRunning()); + + client .when(request().withPath("/hello")) .respond(response().withBody(expectedBody)); assertThat("MockServer returns correct result", - responseFromMockserver(mockServer, "/hello"), + SimpleHttpClient.responseFromMockserver(mockServer, "/hello"), equalTo(expectedBody) ); } } + + @Test + public void newVersionStartsWithDefaultWaitStrategy() { + DockerImageName dockerImageName = DockerImageName.parse("mockserver/mockserver:mockserver-5.11.2"); + try (MockServerContainer mockServer = new MockServerContainer(dockerImageName)) { + mockServer.start(); + } + } } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java b/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java new file mode 100644 index 00000000000..cd5cb25cabb --- /dev/null +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java @@ -0,0 +1,17 @@ +package org.testcontainers.containers; + +import lombok.Cleanup; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; + +public class SimpleHttpClient { + public static String responseFromMockserver(MockServerContainer mockServer, String path) throws IOException { + URLConnection urlConnection = new URL(mockServer.getEndpoint() + path).openConnection(); + @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + return reader.readLine(); + } +} From 4fc04b64e474075bb88c1f4886a1189d89e01da4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 11 Dec 2020 15:16:05 +0100 Subject: [PATCH 1112/4969] Use lower Jackson version to avoid conflicts. (#3579) Helps with #3433 --- core/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/build.gradle b/core/build.gradle index db624e555d9..0dc6f07ddf9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -175,6 +175,10 @@ dependencies { compile "com.github.docker-java:docker-java-api:3.2.7" + // use lower Jackson version + shaded ('com.fasterxml.jackson.core:jackson-databind:2.8.8') { + exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') + } shaded ('com.github.docker-java:docker-java-core:3.2.7') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') From 6932c7aaf98cc17ee66ed5ab33f7a85456a5850d Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 11 Dec 2020 18:36:24 +0100 Subject: [PATCH 1113/4969] Update mkdocs.yml to the latest release --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 618b9679291..2457d06bcf0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -94,4 +94,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.15.0 + latest_version: 1.15.1 From 87da74e422c519cd0ac2fa124a0e47819145d5b0 Mon Sep 17 00:00:00 2001 From: jochenchrist Date: Sat, 12 Dec 2020 16:55:17 +0100 Subject: [PATCH 1114/4969] Startables#deepStart with varargs (#3261) Co-authored-by: Jochen Christ --- .../java/org/testcontainers/lifecycle/Startables.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startables.java b/core/src/main/java/org/testcontainers/lifecycle/Startables.java index 292e1ab17b3..5ec46f1edb9 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/Startables.java +++ b/core/src/main/java/org/testcontainers/lifecycle/Startables.java @@ -1,5 +1,6 @@ package org.testcontainers.lifecycle; +import java.util.Arrays; import lombok.experimental.UtilityClass; import java.util.Collection; @@ -42,6 +43,13 @@ public CompletableFuture deepStart(Iterable startable return deepStart(StreamSupport.stream(startables.spliterator(), false)); } + /** + * @see #deepStart(Stream) + */ + public CompletableFuture deepStart(Startable... startables) { + return deepStart(Arrays.stream(startables)); + } + /** * Start every {@link Startable} recursively and asynchronously and join on the result. * From 30f399eca0e4d56c5701cc2aa02bec85f875d6ec Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 29 Dec 2020 13:00:48 +0100 Subject: [PATCH 1115/4969] Remove ciMate (#3631) --- .circleci/config.yml | 9 --------- .github/workflows/ci-docker-wormhole.yml | 9 --------- .github/workflows/ci-examples.yml | 10 ---------- .github/workflows/ci-rootless.yml | 10 ---------- .github/workflows/ci.yml | 20 -------------------- azure-pipelines.yml | 2 -- 6 files changed, 60 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8f700dba2b5..b8f75aaf4db 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,15 +7,6 @@ jobs: - checkout - run: command: ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' - - run: - name: aggregate test reports with ciMate - when: always - environment: - CIMATE_PROJECT_ID: 2348n4vl - command: | - wget -q https://get.cimate.io/release/linux/cimate - chmod +x cimate - ./cimate "**/TEST-*.xml" - run: name: Save test results command: | diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index f9e106d56b7..d750d8b39e0 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -18,12 +18,3 @@ jobs: -w "$PWD" \ openjdk:8-jdk-alpine \ ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' - - name: aggregate test reports with ciMate - if: always() - continue-on-error: true - env: - CIMATE_PROJECT_ID: 2348n4vl - run: | - wget -q https://get.cimate.io/release/linux/cimate - chmod +x cimate - ./cimate "**/TEST-*.xml" diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 4f91341a4a6..d69aebcfa88 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -57,13 +57,3 @@ jobs: working-directory: ./examples/ run: | ./gradlew --no-daemon --continue --scan --info ${{matrix.gradle_args}} - - name: Aggregate Examples test reports with ciMate - if: always() - continue-on-error: true - env: - CIMATE_PROJECT_ID: 2348n4vl - CIMATE_CI_KEY: "Examples / ${{ runner.os }} / ${{matrix.gradle_args}}" - run: | - wget -q https://get.cimate.io/release/linux/cimate - chmod +x cimate - ./cimate "**/TEST-*.xml" diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index bf1fe08bbd2..71ded85cf53 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -32,13 +32,3 @@ jobs: DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock docker info || ls -la $XDG_RUNTIME_DIR - name: Build with Gradle run: ./gradlew --no-daemon --scan testcontainers:test --tests '*GenericContainerRuleTest' - - name: aggregate test reports with ciMate - if: always() - continue-on-error: true - env: - CIMATE_PROJECT_ID: 2348n4vl - CIMATE_CI_KEY: "CI / rootless Docker (${{ matrix.XDG_RUNTIME_DIR }})" - run: | - wget -q https://get.cimate.io/release/linux/cimate - chmod +x cimate - ./cimate "**/TEST-*.xml" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df38f3b8a4f..ef0f915972b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,16 +54,6 @@ jobs: - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} - - name: Aggregate test reports with ciMate - if: always() - continue-on-error: true - env: - CIMATE_PROJECT_ID: 2348n4vl - CIMATE_CI_KEY: "CI / ${{ runner.os }} / ${{matrix.gradle_args}}" - run: | - wget -q https://get.cimate.io/release/linux/cimate - chmod +x cimate - ./cimate "**/TEST-*.xml" httpclient5_test: runs-on: ubuntu-18.04 steps: @@ -73,13 +63,3 @@ jobs: echo "transport.type=httpclient5" > $HOME/.testcontainers.properties cat $HOME/.testcontainers.properties ./gradlew --no-daemon --scan testcontainers:test --tests '*EventStreamTest' - - name: aggregate test reports with ciMate - if: always() - continue-on-error: true - env: - CIMATE_PROJECT_ID: 2348n4vl - CIMATE_CI_KEY: "CI / Apache HttpClient5" - run: | - wget -q https://get.cimate.io/release/linux/cimate - chmod +x cimate - ./cimate "**/TEST-*.xml" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 185240ae7eb..1471f9948ca 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,8 +17,6 @@ jobs: tasks: "clean testcontainers:test --tests GenericContainerRuleTest" publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - - script: wget -q https://get.cimate.io/release/linux/cimate && chmod +x cimate && ./cimate "**/TEST-*.xml" - condition: and(succeededOrFailed(),eq(variables['Agent.OS'], 'Linux')) # Run all tests when running the Windows CI tests - task: Gradle@2 From 184afddf981b58497823fcfae0c51c008ad9d361 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 29 Dec 2020 12:44:10 +0000 Subject: [PATCH 1116/4969] Upgrade Ryuk to 0.3.1 (#3629) Co-authored-by: Sergei Egorov --- .../main/java/org/testcontainers/utility/ResourceReaper.java | 2 +- .../utility/TestcontainersConfigurationTest.java | 4 ++-- docs/features/configuration.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index f409dbbc865..71a4b49d0d3 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -88,7 +88,7 @@ public static String start(String hostIpAddress, DockerClient client) { @SneakyThrows(InterruptedException.class) public static String start(DockerClient client) { String ryukImage = ImageNameSubstitutor.instance() - .apply(DockerImageName.parse("testcontainers/ryuk:0.3.0")) + .apply(DockerImageName.parse("testcontainers/ryuk:0.3.1")) .asCanonicalNameString(); DockerClientFactory.instance().checkAndPullImage(client, ryukImage); diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index ae07e2d9131..e5300bce58d 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -160,8 +160,8 @@ public void shouldReadReuseFromEnvironment() { @Test public void shouldTrimImageNames() { - userProperties.setProperty("ryuk.container.image", " testcontainersofficial/ryuk:0.3.0 "); - assertEquals("trailing whitespace was not removed from image name property", "testcontainersofficial/ryuk:0.3.0",newConfig().getRyukImage()); + userProperties.setProperty("ryuk.container.image", " testcontainers/ryuk:0.3.1 "); + assertEquals("trailing whitespace was not removed from image name property", "testcontainers/ryuk:0.3.1",newConfig().getRyukImage()); } private TestcontainersConfiguration newConfig() { diff --git a/docs/features/configuration.md b/docs/features/configuration.md index b567a8f564f..da7bbd82d60 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -47,7 +47,7 @@ It takes a couple of seconds, but if you want to speed up your tests, you can di Testcontainers uses public Docker images to perform different actions like startup checks, VNC recording and others. Some companies disallow the usage of Docker Hub, but you can override `*.image` properties with your own images from your private registry to workaround that. -> **ryuk.container.image = testcontainers/ryuk:0.3.0** +> **ryuk.container.image = testcontainers/ryuk:0.3.1** > Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) > **tinyimage.container.image = alpine:3.5** @@ -74,7 +74,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` ## Customizing Ryuk resource reaper -> **ryuk.container.image = testcontainers/ryuk:0.3.0** +> **ryuk.container.image = testcontainers/ryuk:0.3.1** > The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown > **ryuk.container.privileged = false** From 84f6dd815b56bf9a089a8dfe9b74622dce57fad7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Dec 2020 13:51:30 +0000 Subject: [PATCH 1117/4969] Bump assertj-core from 3.18.0 to 3.18.1 in /modules/vault (#3486) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.0 to 3.18.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.0...assertj-core-3.18.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index caddc81d3a7..7db7fb2322a 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.1' - testCompile 'org.assertj:assertj-core:3.18.0' + testCompile 'org.assertj:assertj-core:3.18.1' } From 7c4e935578861c99b0f295f5d18162f745aa9247 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Dec 2020 13:51:46 +0000 Subject: [PATCH 1118/4969] Bump influxdb-java from 2.20 to 2.21 in /modules/influxdb (#3568) Bumps [influxdb-java](https://github.com/influxdata/influxdb-java) from 2.20 to 2.21. - [Release notes](https://github.com/influxdata/influxdb-java/releases) - [Changelog](https://github.com/influxdata/influxdb-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-java/compare/influxdb-java-2.20...influxdb-java-2.21) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/influxdb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index 40fa6e456ce..2e735e1137a 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { compile project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.20' - testCompile 'org.influxdb:influxdb-java:2.19' + compileOnly 'org.influxdb:influxdb-java:2.21' + testCompile 'org.influxdb:influxdb-java:2.21' } From 5f7bb3ae4f2edcfe79dd451f29cfed3c212a2577 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Dec 2020 13:52:07 +0000 Subject: [PATCH 1119/4969] Bump json from 20180813 to 20201115 in /examples (#3567) Bumps [json](https://github.com/douglascrockford/JSON-java) from 20180813 to 20201115. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Commits](https://github.com/douglascrockford/JSON-java/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index f5f21a57d21..5c7279dd09a 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.9.0' - implementation 'org.json:json:20180813' + implementation 'org.json:json:20201115' testImplementation 'org.postgresql:postgresql:42.2.18' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' From 850f72eeb7dd7584ae1b46a1a5ee175c9f252bc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Dec 2020 13:52:21 +0000 Subject: [PATCH 1120/4969] Bump pulsar-client from 2.6.1 to 2.7.0 in /modules/pulsar (#3565) Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.6.1 to 2.7.0. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.6.1...v2.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index e09ff42f357..00455fc6602 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.6.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.18.1' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.1' } From 7d683a1cb238d1c5c9eaf9916d010f5479182237 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Dec 2020 13:52:36 +0000 Subject: [PATCH 1121/4969] Bump pulsar-client-admin from 2.6.1 to 2.7.0 in /modules/pulsar (#3566) Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.6.1 to 2.7.0. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.6.1...v2.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 00455fc6602..b574519a939 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.0' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.18.1' - testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.6.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.0' } From bf16881fb9904afebc4bf15ab3a2ed0ea3bfdb99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Dec 2020 14:08:45 +0000 Subject: [PATCH 1122/4969] Bump mssql-jdbc from 9.1.0.jre8-preview to 9.1.1.jre8-preview in /modules/mssqlserver (#3563) Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 9.1.0.jre8-preview to 9.1.1.jre8-preview. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/dev/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 9aab7844148..765e1382180 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,12 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.4.RELEASE' testCompile project(':jdbc-test') - testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.0.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.1.jre8-preview' testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.3.RELEASE' // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) - testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.0.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.1.jre8-preview' } From d1217ab02e5994e88760e046c4ce0d74dfaeb1bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Dec 2020 14:43:52 +0000 Subject: [PATCH 1123/4969] Bump mockito-core from 3.5.13 to 3.6.28 in /core (#3542) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.13 to 3.6.28. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.13...v3.6.28) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 0dc6f07ddf9..35a8bb92f32 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -209,7 +209,7 @@ dependencies { testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' - testCompile ('org.mockito:mockito-core:3.5.13') { + testCompile ('org.mockito:mockito-core:3.6.28') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 96429538eb3a1f080030d79c36acf9275405d206 Mon Sep 17 00:00:00 2001 From: Martin Traverso Date: Thu, 31 Dec 2020 03:10:18 -0800 Subject: [PATCH 1124/4969] Rename Presto to Trino (#3649) PrestoSQL was rebranded as Trino: https://trino.io/blog/2020/12/27/announcing-trino.html --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 2351837f8af..bc6d1e64afe 100644 --- a/docs/index.md +++ b/docs/index.md @@ -162,7 +162,7 @@ A huge thank you to our sponsors: * [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) * [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) * [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS -* [Presto](https://prestosql.io) - Integration testing all Presto core & connectors, including tests of multi-node deployments and security configurations. +* [Trino (formerly Presto SQL)](https://trino.io) - Integration testing all Trino core & connectors, including tests of multi-node deployments and security configurations. ## License From 54000d9574213574df7e5b211f3b15a50d1dea3d Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Thu, 31 Dec 2020 12:19:54 +0100 Subject: [PATCH 1125/4969] add github actions to dependabot config (#3633) Co-authored-by: Richard North --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d854a9aa823..16b59da6dfa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -139,3 +139,10 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + +# GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 From 4e11573dcd0f9c19ceff519038c863ae807f20b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:39:08 +0000 Subject: [PATCH 1126/4969] Bump mockito-core from 3.5.15 to 3.6.28 in /modules/junit-jupiter (#3539) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.5.15 to 3.6.28. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.5.15...v3.6.28) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 520cff37254..12d4321d10f 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.13' - testCompile ('org.mockito:mockito-core:3.5.15') { + testCompile ('org.mockito:mockito-core:3.6.28') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.18.1' From 3a32e3fd98655e80d2f22dca4fa0944d1c84d1fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:39:16 +0000 Subject: [PATCH 1127/4969] Bump r2dbc-mssql from 0.8.4.RELEASE to 0.8.5.RELEASE in /modules/mssqlserver (#3397) Bumps [r2dbc-mssql](https://github.com/r2dbc/r2dbc-mssql) from 0.8.4.RELEASE to 0.8.5.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-mssql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-mssql/blob/v0.8.5.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-mssql/compare/v0.8.4.RELEASE...v0.8.5.RELEASE) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 765e1382180..c36f1e6ba84 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -7,13 +7,13 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-mssql:0.8.4.RELEASE' + compileOnly 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' testCompile project(':jdbc-test') testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.1.jre8-preview' testCompile project(':r2dbc') - testCompile 'io.r2dbc:r2dbc-mssql:0.8.3.RELEASE' + testCompile 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) From a475797c9706e7f2934b6201c81002095903c5c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:39:27 +0000 Subject: [PATCH 1128/4969] Bump rest-assured from 4.3.1 to 4.3.3 in /modules/vault (#3588) Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 4.3.1 to 4.3.3. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-4.3.1...rest-assured-4.3.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 7db7fb2322a..e75d1121131 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { compile project(':testcontainers') testCompile 'com.bettercloud:vault-java-driver:5.1.0' - testCompile 'io.rest-assured:rest-assured:4.3.1' + testCompile 'io.rest-assured:rest-assured:4.3.3' testCompile 'org.assertj:assertj-core:3.18.1' } From 4a03031d27d1de6f4903258df13480a21aa3fdbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:39:37 +0000 Subject: [PATCH 1129/4969] Bump jedis from 3.3.0 to 3.4.0 in /core (#3586) Bumps [jedis](https://github.com/xetorthio/jedis) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/xetorthio/jedis/releases) - [Commits](https://github.com/xetorthio/jedis/compare/jedis-3.3.0...jedis-3.4.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 35a8bb92f32..ef63ce62bda 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -205,7 +205,7 @@ dependencies { } testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testCompile 'redis.clients:jedis:3.3.0' + testCompile 'redis.clients:jedis:3.4.0' testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' From cb2c31005002eef20946f519b23136ae00969751 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:39:51 +0000 Subject: [PATCH 1130/4969] Bump elasticsearch-rest-client from 7.10.0 to 7.10.1 in /modules/elasticsearch (#3589) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.10.0 to 7.10.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.10.0...v7.10.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index bfbfbfae9ce..a3442f3234b 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.10.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.10.1" testCompile "org.elasticsearch.client:transport:7.10.0" } From 8e7fff80fe7d6e45f6170734979903f70a0e4655 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:40:10 +0000 Subject: [PATCH 1131/4969] Bump tomcat-jdbc from 9.0.40 to 10.0.0 in /modules/jdbc (#3592) Bumps tomcat-jdbc from 9.0.40 to 10.0.0. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 12a53f7cfbc..910dc29ebad 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:20.1.0' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.40' + testCompile 'org.apache.tomcat:tomcat-jdbc:10.0.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' } From 804116c18b52590b022e28b10a76e89866f3ed29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:40:18 +0000 Subject: [PATCH 1132/4969] Bump jedis from 3.3.0 to 3.4.0 in /examples (#3595) Bumps [jedis](https://github.com/xetorthio/jedis) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/xetorthio/jedis/releases) - [Commits](https://github.com/xetorthio/jedis/compare/jedis-3.3.0...jedis-3.4.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 6ef351764f5..76c245d5b51 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.3.0' + implementation 'redis.clients:jedis:3.4.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index b0b6865aea7..e63d494bcef 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.3.0' + implementation 'redis.clients:jedis:3.4.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 11e6cb2a31b..bbd35cabc49 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.3.0' + implementation 'redis.clients:jedis:3.4.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.30' From 463c3bb5d85be43f0950c7ae09f46e7882cfd5b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:40:30 +0000 Subject: [PATCH 1133/4969] Bump org.springframework.boot from 2.3.4.RELEASE to 2.4.1 in /examples (#3594) Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.3.4.RELEASE to 2.4.1. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.4.RELEASE...v2.4.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 2dca03f4004..1f05d7b5663 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.4.RELEASE' + id 'org.springframework.boot' version '2.4.1' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index f2d9d8d97ec..9c622648a20 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.1.5.RELEASE" + id("org.springframework.boot") version "2.4.1" id("org.jetbrains.kotlin.jvm") version "1.3.31" id("org.jetbrains.kotlin.plugin.spring") version "1.3.31" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 75907da4c0d..288a9226b90 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.3.4.RELEASE' + id 'org.springframework.boot' version '2.4.1' } apply plugin: 'io.spring.dependency-management' From cdd1837b7f40b749ad9576b141e3dc7f873f475b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:41:08 +0000 Subject: [PATCH 1134/4969] Bump r2dbc-mariadb from 0.8.4-rc to 1.0.0 in /modules/mariadb (#3593) Bumps [r2dbc-mariadb](https://github.com/mariadb-corporation/mariadb-connector-r2dbc) from 0.8.4-rc to 1.0.0. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index e5f19eed97b..915e14eb7ee 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,11 +7,11 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'org.mariadb:r2dbc-mariadb:0.8.4-rc' + compileOnly 'org.mariadb:r2dbc-mariadb:1.0.0' testCompile project(':jdbc-test') testCompile 'org.mariadb.jdbc:mariadb-java-client:2.7.0' testCompile testFixtures(project(':r2dbc')) - testCompile 'org.mariadb:r2dbc-mariadb:0.8.3-beta1' + testCompile 'org.mariadb:r2dbc-mariadb:1.0.0' } From 6eb362271ff94b519370f752fc3b9844ad47e2d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:41:16 +0000 Subject: [PATCH 1135/4969] Bump cucumber-java from 6.8.1 to 6.9.1 in /examples (#3624) Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 6.8.1 to 6.9.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.8.1...v6.9.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 57104731c7e..d3be66ddcc6 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:6.8.1' + testImplementation 'io.cucumber:cucumber-java:6.9.1' testImplementation 'io.cucumber:cucumber-junit:6.8.1' testImplementation 'org.testcontainers:selenium' } From 394cdce6827f5e785a233f7d67cbc72bd0e7ac84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:42:06 +0000 Subject: [PATCH 1136/4969] Bump solr-solrj from 8.6.3 to 8.7.0 in /examples (#3446) Bumps solr-solrj from 8.6.3 to 8.7.0. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 75524364100..fcdf93a9c53 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.16" annotationProcessor "org.projectlombok:lombok:1.18.16" - implementation 'org.apache.solr:solr-solrj:8.6.3' + implementation 'org.apache.solr:solr-solrj:8.7.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From 63d0290639e39084396d2eb4e4ff1be01a4a4abd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 15:10:00 +0000 Subject: [PATCH 1137/4969] Update actions/cache requirement to v2.1.3 (#3651) Updates the requirements on [actions/cache](https://github.com/actions/cache) to permit the latest version. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/commits/0781355a23dac32fd3bac414512f4b903437991a) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index d69aebcfa88..cea7180566d 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -19,7 +19,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v1 + uses: actions/cache@v2.1.3 continue-on-error: true with: path: ~/.gradle/caches @@ -46,7 +46,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v1 + uses: actions/cache@v2.1.3 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef0f915972b..f49b6426a2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v1 + uses: actions/cache@v2.1.3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -44,7 +44,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v2 + uses: actions/cache@v2.1.3 continue-on-error: true with: path: ~/.gradle/caches From c9528eea9477696fe75f7fb5a53015e039270272 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 15:11:20 +0000 Subject: [PATCH 1138/4969] Bump gradle/wrapper-validation-action from e2c57ac to 1.0.3 (#3657) Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from e2c57ac to 1.0.3. This release includes the previously tagged commit. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/e2c57ac...e2c57acffb2c9aa5a8dc6eda2bbae0b6e495bd4c) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index f3a01949324..883d6dd6cbc 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -17,4 +17,4 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies - - uses: gradle/wrapper-validation-action@e2c57ac + - uses: gradle/wrapper-validation-action@e2c57acffb2c9aa5a8dc6eda2bbae0b6e495bd4c From 3b07d82c18e6f65f8b9c0a443410eb6486aa7ff1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 15:13:30 +0000 Subject: [PATCH 1139/4969] Bump aws-java-sdk-dynamodb from 1.11.901 to 1.11.929 in /modules/dynalite (#3652) Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.901 to 1.11.929. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.901...1.11.929) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 5f6ab14d939..a09ef417159 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.901' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.882' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.929' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.929' } From 7d2e184b644b50d0ff964203708a8c82398aa836 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 15:20:56 +0000 Subject: [PATCH 1140/4969] Bump ad-m/github-push-action from 68af9897f2b021035ca3952bf354bbb4675c1762 to 0.6.0 (#3658) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index cce6e5b9bf1..d2eb803fda2 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -22,6 +22,6 @@ jobs: git add mkdocs.yml git commit -m "Update documentation version to ${GITHUB_REF##*/}" -m "skip-checks: true" || echo "not changed" - name: Push changes - uses: ad-m/github-push-action@68af9897f2b021035ca3952bf354bbb4675c1762 # v0.5.0 + uses: ad-m/github-push-action@40bf560936a8022e68a3c00e7d2abefaf01305a6 with: github_token: ${{ secrets.GITHUB_TOKEN }} From fac5e852a0b2ad999ae5ea9991777668c64adeaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 16:51:22 +0000 Subject: [PATCH 1141/4969] Bump guava from 30.0-jre to 30.1-jre in /core (#3627) Bumps [guava](https://github.com/google/guava) from 30.0-jre to 30.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index ef63ce62bda..4b42173cd0f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ buildscript { dependencies { // https://github.com/melix/japicmp-gradle-plugin/issues/36 - classpath 'com.google.guava:guava:30.0-jre' + classpath 'com.google.guava:guava:30.1-jre' } } From 288af58ed0425b1edc713c33d93eb5fb66492ee0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 16:51:31 +0000 Subject: [PATCH 1142/4969] Bump org.jetbrains.kotlin.jvm from 1.3.31 to 1.4.21-2 in /examples (#3645) Bumps org.jetbrains.kotlin.jvm from 1.3.31 to 1.4.21-2. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 9c622648a20..cc1083ee8d4 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.4.1" - id("org.jetbrains.kotlin.jvm") version "1.3.31" + id("org.jetbrains.kotlin.jvm") version "1.4.21-2" id("org.jetbrains.kotlin.plugin.spring") version "1.3.31" } From c64a8cd04a0b33fa949e19d93f31766cab021245 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 16:52:02 +0000 Subject: [PATCH 1143/4969] Bump s3 from 2.15.14 to 2.15.56 in /modules/localstack (#3650) Bumps s3 from 2.15.14 to 2.15.56. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 908f87de07d..dd66fb69547 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.884' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.15.14' + testCompile 'software.amazon.awssdk:s3:2.15.56' } From 52b467aa792f1c4a68f3ea79446261e4a726427b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 16:52:12 +0000 Subject: [PATCH 1144/4969] Bump aws-java-sdk-s3 from 1.11.882 to 1.11.929 in /modules/localstack (#3654) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.882 to 1.11.929. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.882...1.11.929) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index dd66fb69547..e67f6fe0632 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.882' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.880' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.929' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.884' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.15.56' From c5d462abad68933d3f3c9e651edfea25aef62a59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 16:52:45 +0000 Subject: [PATCH 1145/4969] Bump transport from 7.10.0 to 7.10.1 in /modules/elasticsearch (#3590) Bumps [transport](https://github.com/elastic/elasticsearch) from 7.10.0 to 7.10.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.10.0...v7.10.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index a3442f3234b..b4a64a405b7 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.10.1" - testCompile "org.elasticsearch.client:transport:7.10.0" + testCompile "org.elasticsearch.client:transport:7.10.1" } From 4daf4dba93cc428f07395400143c6a72605497c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 16:56:56 +0000 Subject: [PATCH 1146/4969] Bump testcontainers from 1.14.3 to 1.15.1 in /core (#3587) Bumps [testcontainers](https://github.com/testcontainers/testcontainers-java) from 1.14.3 to 1.15.1. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.14.3...1.15.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4b42173cd0f..ac174e8bc93 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -158,7 +158,7 @@ if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { } dependencies { - baseline 'org.testcontainers:testcontainers:1.14.3', { + baseline 'org.testcontainers:testcontainers:1.15.1', { exclude group: "*", module: "*" } From acbb0c540dd33e903dabeffbaa9327f1873b046f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 16:57:04 +0000 Subject: [PATCH 1147/4969] Bump cucumber-junit from 6.8.1 to 6.9.1 in /examples (#3625) Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 6.8.1 to 6.9.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.8.1...v6.9.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index d3be66ddcc6..ddffea03dfe 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.9.1' - testImplementation 'io.cucumber:cucumber-junit:6.8.1' + testImplementation 'io.cucumber:cucumber-junit:6.9.1' testImplementation 'org.testcontainers:selenium' } From 2a9c4ebaf32b4f385b4ebf72ebd06f21a64e41d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 17:03:05 +0000 Subject: [PATCH 1148/4969] Bump gradle-update/update-gradle-wrapper-action from 74a035c to 1.0.9 (#3653) Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 74a035c to 1.0.9. This release includes the previously tagged commit. - [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases) - [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/74a035c...74a035ce333f39c84811ce1167669bfa6c65f440) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 883d6dd6cbc..e8f4f130b12 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v2 - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@74a035c + uses: gradle-update/update-gradle-wrapper-action@74a035ce333f39c84811ce1167669bfa6c65f440 with: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies From d9ecb9813bca5b75cdc33dc4715a0c918eaf7c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mads=20M=C3=A6tzke=20Tandrup?= Date: Fri, 1 Jan 2021 19:54:46 +0100 Subject: [PATCH 1149/4969] Add init command parameter to Vault container (#3188) Co-authored-by: Richard North --- .../testcontainers/vault/VaultContainer.java | 37 +++++++++++++++++++ .../vault/VaultContainerTest.java | 13 ++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java index f47818d8c7d..37e78a14f95 100644 --- a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java +++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java @@ -7,10 +7,12 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.stream.Collectors; import static com.github.dockerjava.api.model.Capability.IPC_LOCK; @@ -30,6 +32,7 @@ public class VaultContainer> extends GenericCo private static final int VAULT_PORT = 8200; private Map> secretsMap = new HashMap<>(); + private List initCommands = new ArrayList<>(); private int port = VAULT_PORT; @@ -61,6 +64,7 @@ public VaultContainer(final DockerImageName dockerImageName) { @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { addSecrets(); + runInitCommands(); } private void addSecrets() { @@ -82,6 +86,23 @@ private String[] buildExecCommand(Map> map) { return new String[]{"/bin/sh", "-c", stringBuilder.toString().substring(4)}; } + private void runInitCommands() { + if (!initCommands.isEmpty()) { + String commands = initCommands.stream() + .map(command -> "vault " + command) + .collect(Collectors.joining(" && ")); + try { + ExecResult execResult = this.execInContainer(new String[]{"/bin/sh", "-c", commands}); + if (execResult.getExitCode() != 0) { + logger().error("Failed to execute these init commands {}. Exit code {}. Stdout {}. Stderr {}", + initCommands, execResult.getExitCode(), execResult.getStdout(), execResult.getStderr()); + } + } catch (IOException | InterruptedException e) { + logger().error("Failed to execute these init commands {}. Exception message: {}", initCommands, e.getMessage()); + } + } + } + /** * Sets the Vault root token for the container so application tests can source secrets using the token * @@ -142,4 +163,20 @@ public SELF withSecretInVault(String path, String firstSecret, String... remaini secretsMap.putIfAbsent(path, list); return self(); } + + /** + * Run initialization commands using the vault cli. + * + * Useful for enableing more secret engines like: + *

+     *     .withInitCommand("secrets enable pki")
+     *     .withInitCommand("secrets enable transit")
+     * 
+ * @param commands The commands to send to the vault cli + * @return this + */ + public SELF withInitCommand(String... commands) { + initCommands.addAll(Arrays.asList(commands)); + return self(); + } } diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java index b3dd788f053..9dee4c21416 100644 --- a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java @@ -27,7 +27,8 @@ public class VaultContainerTest { "secret_two=password2", "secret_three=password3", "secret_three=password3", - "secret_four=password4"); + "secret_four=password4") + .withInitCommand("secrets enable transit", "write -f transit/keys/my-key"); @Test public void readFirstSecretPathWithCli() throws IOException, InterruptedException { @@ -70,6 +71,16 @@ public void readSecondSecretPathOverHttpApi() throws InterruptedException { assertThat().body("data.data.secret_four", containsString("password4")); } + @Test + public void readTransitKeyOverHttpApi() throws InterruptedException { + given(). + header("X-Vault-Token", VAULT_TOKEN). + when(). + get("http://" + getHostAndPort() + "/v1/transit/keys/my-key"). + then(). + assertThat().body("data.name", equalTo("my-key")); + } + private String getHostAndPort() { return vaultContainer.getHost() + ":" + vaultContainer.getMappedPort(8200); } From e6089e86d605eb3120a3a282c11ae700e577c6fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 18:55:23 +0000 Subject: [PATCH 1150/4969] Bump org.jetbrains.kotlin.plugin.spring from 1.3.31 to 1.4.21-2 in /examples (#3646) Bumps org.jetbrains.kotlin.plugin.spring from 1.3.31 to 1.4.21-2. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index cc1083ee8d4..4675f907235 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.4.1" id("org.jetbrains.kotlin.jvm") version "1.4.21-2" - id("org.jetbrains.kotlin.plugin.spring") version "1.3.31" + id("org.jetbrains.kotlin.plugin.spring") version "1.4.21-2" } apply plugin: 'io.spring.dependency-management' From 40f96736fad1cccf34290294a1ced3cf941ba51a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 18:55:36 +0000 Subject: [PATCH 1151/4969] Bump aws-java-sdk-s3 from 1.11.929 to 1.11.930 in /modules/localstack (#3659) Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.929 to 1.11.930. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.929...1.11.930) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index e67f6fe0632..a0b30cc5844 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.929' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.930' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.884' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' From b6628c5a8fa837301c01b66454eec93b2d8b46ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 18:55:46 +0000 Subject: [PATCH 1152/4969] Bump guava from 30.0-jre to 30.1-jre in /modules/jdbc-test (#3622) Bumps [guava](https://github.com/google/guava) from 30.0-jre to 30.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 8523ca5a3d8..b6581d526a5 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -2,7 +2,7 @@ dependencies { compile project(':jdbc') compile project(':test-support') - compile 'com.google.guava:guava:30.0-jre' + compile 'com.google.guava:guava:30.1-jre' compile 'org.apache.commons:commons-lang3:3.11' compile 'com.zaxxer:HikariCP-java6:2.3.13' compile 'commons-dbutils:commons-dbutils:1.7' From 0e8523db9df728a31c2b951eeee08abf7196ec6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Jan 2021 16:11:50 +0000 Subject: [PATCH 1153/4969] Bump aws-java-sdk-sqs from 1.11.884 to 1.11.930 in /modules/localstack (#3660) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.884 to 1.11.930. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.884...1.11.930) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index a0b30cc5844..fdffc649a72 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.930' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.884' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.930' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.15.56' } From 39116c09169bcde50a9e4d62bf90c15e3df4dc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9da=20Housni=20Alaoui?= Date: Sun, 10 Jan 2021 13:23:23 +0100 Subject: [PATCH 1154/4969] Fix handling of locally built images when used with `hub.image.name.prefix` (#3666) --- .../org/testcontainers/images/builder/ImageFromDockerfile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 133b6e1c4b0..b36779f1b9e 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -54,7 +54,7 @@ public class ImageFromDockerfile extends LazyFuture implements private Set dependencyImageNames = Collections.emptySet(); public ImageFromDockerfile() { - this("testcontainers/" + Base58.randomString(16).toLowerCase()); + this("localhost/testcontainers/" + Base58.randomString(16).toLowerCase()); } public ImageFromDockerfile(String dockerImageName) { From d96dd815d2b8166b75a919c751681da3325e2014 Mon Sep 17 00:00:00 2001 From: "Junho, Kim" Date: Sun, 10 Jan 2021 21:31:39 +0900 Subject: [PATCH 1155/4969] Remove duplicated dependency in jdbc-test module (#3664) Co-authored-by: Junho, Kim --- modules/jdbc-test/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index b6581d526a5..05a96aaf333 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,6 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - compile 'commons-dbutils:commons-dbutils:1.7' compile 'org.apache.tomcat:tomcat-jdbc:9.0.40' compile 'org.vibur:vibur-dbcp:25.0' compile 'mysql:mysql-connector-java:8.0.22' From 97493b112f76711adc8f431f6f8e6f3245f05c47 Mon Sep 17 00:00:00 2001 From: Diego Lovison Date: Tue, 12 Jan 2021 13:58:27 -0300 Subject: [PATCH 1156/4969] Support Ryuk socket timeout (#3682) Fixes #3183 Co-authored-by: Sergei Egorov --- .../main/java/org/testcontainers/utility/ResourceReaper.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 71a4b49d0d3..7adbc95bb4c 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -28,6 +28,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; import java.net.Socket; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -157,7 +158,9 @@ public InspectContainerResponse getContainerInfo() { while (true) { RYUK_ACK_RATE_LIMITER.doWhenReady(() -> { int index = 0; - try(Socket clientSocket = new Socket(host, ryukPort)) { + // not set the read timeout, as Ryuk would not send anything unless a new filter is submitted, meaning that we would get a timeout exception pretty quick + try (Socket clientSocket = new Socket()) { + clientSocket.connect(new InetSocketAddress(host, ryukPort), 5 * 1000); FilterRegistry registry = new FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); synchronized (DEATH_NOTE) { From 864df2d50b0d5baf0ace24fba972444569d0e21e Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 6 Feb 2021 15:24:18 +0100 Subject: [PATCH 1157/4969] Force Jackson version to 2.8.8 (forward compatibility) (#3602) Co-authored-by: Richard North --- core/build.gradle | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index ac174e8bc93..7613ed58ccc 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -157,6 +157,13 @@ if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { project.tasks.check.dependsOn(japicmp) } +configurations.all { + resolutionStrategy { + // use lower Jackson version + force 'com.fasterxml.jackson.core:jackson-databind:2.8.8' + } +} + dependencies { baseline 'org.testcontainers:testcontainers:1.15.1', { exclude group: "*", module: "*" @@ -175,10 +182,6 @@ dependencies { compile "com.github.docker-java:docker-java-api:3.2.7" - // use lower Jackson version - shaded ('com.fasterxml.jackson.core:jackson-databind:2.8.8') { - exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') - } shaded ('com.github.docker-java:docker-java-core:3.2.7') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') From 7688d1bd808d4ce965cfd86f2053dd61a479f2ed Mon Sep 17 00:00:00 2001 From: Alexander Girke Date: Sat, 6 Feb 2021 15:49:21 +0100 Subject: [PATCH 1158/4969] Clarify usage of host port exporting (#3421) --- docs/features/networking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/networking.md b/docs/features/networking.md index 2fe039b74ef..e7d8493483e 100644 --- a/docs/features/networking.md +++ b/docs/features/networking.md @@ -69,7 +69,7 @@ We need to tell Testcontainers to prepare to expose this port to containers: !!! warning - Note that the above command should be invoked _before_ containers are started. + Note that the above command should be invoked _before_ containers are started, but _after_ the server on the host was started. Having done so, we can now access this port from any containers that are launched. From a container's perspective, the hostname will be `host.testcontainers.internal` and the port will be the same value as `localServerPort`. From ed8386c4cc2e38cc766eea30de68f3d559639a8a Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Sat, 6 Feb 2021 16:23:10 +0100 Subject: [PATCH 1159/4969] couchbase: wait until all services are part of the config (#3003) This changeset adds a predicate to the wait strategy to make sure that it not only returns a 200, but also that every enabled service is actually already exposed in the config. Since we are polling the server during bootstrap here, not all of them might show up at the same time. Also, while not contributing to the fix we poll the terse bucket http config "b" instead of the verbose one "buckets" since it is a little more efficient on the server side and actually the config the client internally works with. fixes #2993 Co-authored-by: Sergei Egorov --- .../couchbase/CouchbaseContainer.java | 54 +++++++++++++++---- .../couchbase/CouchbaseService.java | 17 ++++-- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 11960304ee6..3671608d324 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -36,10 +36,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; +import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; import java.util.stream.Collectors; /** @@ -181,7 +183,7 @@ protected void configure() { .map("healthy"::equals) .orElse(false); } catch (IOException e) { - logger().error("Unable to parse response {}", response, e); + logger().error("Unable to parse response: {}", response, e); return false; } }) @@ -254,15 +256,10 @@ private void renameNode() { private void initializeServices() { logger().debug("Initializing couchbase services on host: {}", enabledServices); - final String services = enabledServices.stream().map(s -> { - switch (s) { - case KV: return "kv"; - case QUERY: return "n1ql"; - case INDEX: return "index"; - case SEARCH: return "fts"; - default: throw new IllegalStateException("Unknown service!"); - } - }).collect(Collectors.joining(",")); + final String services = enabledServices + .stream() + .map(CouchbaseService::getIdentifier) + .collect(Collectors.joining(",")); @Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder() .add("services", services) @@ -363,10 +360,11 @@ private void createBuckets() { checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName()); new HttpWaitStrategy() - .forPath("/pools/default/buckets/" + bucket.getName()) + .forPath("/pools/default/b/" + bucket.getName()) .forPort(MGMT_PORT) .withBasicCredentials(username, password) .forStatusCode(200) + .forResponsePredicate(new AllServicesEnabledPredicate()) .waitUntilReady(this); if (enabledServices.contains(CouchbaseService.QUERY)) { @@ -472,4 +470,38 @@ private Response doHttpRequest(final int port, final String path, final String m throw new RuntimeException("Could not perform request against couchbase HTTP endpoint ", ex); } } + + /** + * In addition to getting a 200, we need to make sure that all services we need are enabled and available on + * the bucket. + *

+ * Fixes the issue observed in https://github.com/testcontainers/testcontainers-java/issues/2993 + */ + private class AllServicesEnabledPredicate implements Predicate { + + @Override + public boolean test(final String rawConfig) { + try { + for (JsonNode node : MAPPER.readTree(rawConfig).at("/nodesExt")) { + for (CouchbaseService enabledService : enabledServices) { + boolean found = false; + Iterator fieldNames = node.get("services").fieldNames(); + while (fieldNames.hasNext()) { + if (fieldNames.next().startsWith(enabledService.getIdentifier())) { + found = true; + } + } + if (!found) { + logger().trace("Service {} not yet part of config, retrying.", enabledService); + return false; + } + } + } + return true; + } catch (IOException ex) { + logger().error("Unable to parse response: {}", rawConfig, ex); + return false; + } + } + } } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java index d284c660709..c60fc6b71d0 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java @@ -24,21 +24,30 @@ public enum CouchbaseService { /** * Key-Value service. */ - KV, + KV("kv"), /** * Query (N1QL) service. */ - QUERY, + QUERY("n1ql"), /** * Search (FTS) service. */ - SEARCH, + SEARCH("fts"), /** * Indexing service (needed if QUERY is also used!). */ - INDEX + INDEX("index"); + private final String identifier; + + CouchbaseService(String identifier) { + this.identifier = identifier; + } + + String getIdentifier() { + return identifier; + } } From bf0e4836e0136bad3844abd5db24260e2451c8e3 Mon Sep 17 00:00:00 2001 From: Artjom Kalita Date: Sat, 6 Feb 2021 17:26:55 +0200 Subject: [PATCH 1160/4969] Improve logging for port listener (#3736) * Improve logging for port listener, additional clean up for string concatenation in loop Co-authored-by: akalita Co-authored-by: Sergei Egorov --- .../InternalCommandPortListeningCheck.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index 9b4be81b4c4..cd601e6a131 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -24,23 +24,23 @@ public class InternalCommandPortListeningCheck implements java.util.concurrent.C @Override public Boolean call() { - String command = "true"; + StringBuilder command = new StringBuilder("true"); for (int internalPort : internalPorts) { - command += " && "; - command += " ("; - command += format("cat /proc/net/tcp* | awk '{print $2}' | grep -i ':0*%x'", internalPort); - command += " || "; - command += format("nc -vz -w 1 localhost %d", internalPort); - command += " || "; - command += format("/bin/bash -c ' Date: Sat, 6 Feb 2021 18:27:51 +0300 Subject: [PATCH 1161/4969] Added documentation for Bigtable Emulator container (#3708) --- docs/modules/gcloud.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 041129919ee..33d50ee634f 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -5,10 +5,11 @@ Testcontainers module for the Google Cloud Platform's [Cloud SDK](https://cloud.google.com/sdk/). -Currently, the module supports `Datastore`, `Firestore`, `Spanner`, and `Pub/Sub` emulators. In order to use it, you should use the following classes: +Currently, the module supports `Bigtable`, `Datastore`, `Firestore`, `Spanner`, and `Pub/Sub` emulators. In order to use it, you should use the following classes: Class | Container Image -|- +BigtableEmulatorContainer | [gcr.io/google.com/cloudsdktool/cloud-sdk:emulators](https://gcr.io/google.com/cloudsdktool/cloud-sdk) DatastoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/cloud-sdk:emulators](https://gcr.io/google.com/cloudsdktool/cloud-sdk) FirestoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/cloud-sdk:emulators](https://gcr.io/google.com/cloudsdktool/cloud-sdk) SpannerEmulatorContainer | [gcr.io/cloud-spanner-emulator/emulator](https://gcr.io/cloud-spanner-emulator/emulator) @@ -16,6 +17,26 @@ PubSubEmulatorContainer | [gcr.io/google.com/cloudsdktool/cloud-sdk:emulators](h ## Usage example +### Bigtable + +Start Bigtable Emulator during a test: + + +[Starting a Bigtable Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java) inside_block:emulatorContainer + + +Create a test Bigtable table in the Emulator: + + +[Create a test table](../../modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java) inside_block:createTable + + +Test against the Emulator: + + +[Testing with a Bigtable Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java) inside_block:testWithEmulatorContainer + + ### Datastore Start Datastore Emulator during a test: @@ -93,7 +114,7 @@ Start Pub/Sub Emulator during a test: [Starting a Pub/Sub Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) inside_block:emulatorContainer -Create a test Pub/Sub topic the Emulator: +Create a test Pub/Sub topic in the Emulator: [Create a test topic](../../modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) inside_block:createTopic From fd7412fe15070a2ccf70f99c8d7edf829501f8e2 Mon Sep 17 00:00:00 2001 From: Per Lundberg Date: Sat, 6 Feb 2021 17:31:13 +0200 Subject: [PATCH 1162/4969] GenericContainer: fix typo in Javadoc (#3684) --- .../java/org/testcontainers/containers/GenericContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 0a0962cd6c0..4536a70789c 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1339,7 +1339,7 @@ public void copyFileFromContainer(String containerPath, String destinationPath) } /** - * Allow container startup to be attempted more than once if an error occurs. To be if containers are + * Allow container startup to be attempted more than once if an error occurs. To be used if containers are * 'flaky' but this flakiness is not something that should affect test outcomes. * * @param attempts number of attempts From 73da361f47d5c144665f7baf0b45919ec63a61c7 Mon Sep 17 00:00:00 2001 From: Alar Aule Date: Sat, 6 Feb 2021 17:34:18 +0200 Subject: [PATCH 1163/4969] PostGIS JDBC url sample version update (#3606) Latest Testcontainer versions are using new postgis/postgis images, which versioning is different (containing both PostgreSQL version - PostGIS version) Sample is from older mdillion/postgis versions, with copy-paste sample fails. --- docs/modules/databases/jdbc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 65db9aaf07f..6853cf44c5c 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -37,7 +37,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database #### Using PostGIS -`jdbc:tc:postgis:9.6:///databasename` +`jdbc:tc:postgis:9.6-2.5:///databasename` #### Using Presto From 625ddc374cac2447cbbcb59c9d7e07c49ac30e99 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sat, 6 Feb 2021 16:41:20 +0100 Subject: [PATCH 1164/4969] Kafka cluster example (#1984, #3758) Co-authored-by: Sean Glover --- examples/kafka-cluster/build.gradle | 17 +++ .../kafkacluster/KafkaContainerCluster.java | 102 ++++++++++++++++++ .../KafkaContainerClusterTest.java | 97 +++++++++++++++++ examples/settings.gradle | 1 + .../containers/KafkaContainer.java | 8 +- .../containers/KafkaContainerTest.java | 16 +++ 6 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 examples/kafka-cluster/build.gradle create mode 100644 examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java create mode 100644 examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle new file mode 100644 index 00000000000..db07c6859f3 --- /dev/null +++ b/examples/kafka-cluster/build.gradle @@ -0,0 +1,17 @@ +plugins { + id 'java' +} + +repositories { + jcenter() +} + +dependencies { + testCompileOnly "org.projectlombok:lombok:1.18.10" + testAnnotationProcessor "org.projectlombok:lombok:1.18.10" + testCompile 'org.testcontainers:kafka' + testCompile 'org.apache.kafka:kafka-clients:2.3.1' + testCompile 'org.assertj:assertj-core:3.14.0' + testCompile 'com.google.guava:guava:23.0' + testCompile 'org.slf4j:slf4j-simple:1.7.30' +} diff --git a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java new file mode 100644 index 00000000000..fd5b1a0a0b6 --- /dev/null +++ b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java @@ -0,0 +1,102 @@ +package com.example.kafkacluster; + +import lombok.SneakyThrows; +import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.containers.Container; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.lifecycle.Startable; +import org.testcontainers.lifecycle.Startables; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.utility.DockerImageName; + +import java.util.Collection; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Provides an easy way to launch a Kafka cluster with multiple brokers. + */ +public class KafkaContainerCluster implements Startable { + + private final int brokersNum; + private final Network network; + private final GenericContainer zookeeper; + private final Collection brokers; + + public KafkaContainerCluster(String confluentPlatformVersion, int brokersNum, int internalTopicsRf) { + if (brokersNum < 0) { + throw new IllegalArgumentException("brokersNum '" + brokersNum + "' must be greater than 0"); + } + if (internalTopicsRf < 0 || internalTopicsRf > brokersNum) { + throw new IllegalArgumentException("internalTopicsRf '" + internalTopicsRf + "' must be less than brokersNum and greater than 0"); + } + + this.brokersNum = brokersNum; + this.network = Network.newNetwork(); + + this.zookeeper = new GenericContainer<>(DockerImageName.parse("confluentinc/cp-zookeeper").withTag(confluentPlatformVersion)) + .withNetwork(network) + .withNetworkAliases("zookeeper") + .withEnv("ZOOKEEPER_CLIENT_PORT", String.valueOf(KafkaContainer.ZOOKEEPER_PORT)); + + this.brokers = IntStream + .range(0, this.brokersNum) + .mapToObj(brokerNum -> { + return new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka").withTag(confluentPlatformVersion)) + .withNetwork(this.network) + .withNetworkAliases("broker-" + brokerNum) + .dependsOn(this.zookeeper) + .withExternalZookeeper("zookeeper:" + KafkaContainer.ZOOKEEPER_PORT) + .withEnv("KAFKA_BROKER_ID", brokerNum + "") + .withEnv("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR", internalTopicsRf + "") + .withEnv("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS", internalTopicsRf + "") + .withEnv("KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR", internalTopicsRf + "") + .withEnv("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR", internalTopicsRf + ""); + }) + .collect(Collectors.toList()); + } + + public Collection getBrokers() { + return this.brokers; + } + + public String getBootstrapServers() { + return brokers.stream() + .map(KafkaContainer::getBootstrapServers) + .collect(Collectors.joining(",")); + } + + private Stream> allContainers() { + return Stream.concat( + this.brokers.stream(), + Stream.of(this.zookeeper) + ); + } + + @Override + @SneakyThrows + public void start() { + Stream startables = this.brokers.stream().map(Startable.class::cast); + Startables.deepStart(startables).get(60, SECONDS); + + Unreliables.retryUntilTrue(30, TimeUnit.SECONDS, () -> { + Container.ExecResult result = this.zookeeper.execInContainer( + "sh", "-c", + "zookeeper-shell zookeeper:" + KafkaContainer.ZOOKEEPER_PORT + " ls /brokers/ids | tail -n 1" + ); + String brokers = result.getStdout(); + + return brokers != null && brokers.split(",").length == this.brokersNum; + }); + } + + @Override + public void stop() { + allContainers().parallel().forEach(GenericContainer::stop); + } +} diff --git a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java new file mode 100644 index 00000000000..0756b24d58a --- /dev/null +++ b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java @@ -0,0 +1,97 @@ +package com.example.kafkacluster; + +import com.google.common.collect.ImmutableMap; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.Test; +import org.rnorth.ducttape.unreliables.Unreliables; + +import java.time.Duration; +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class KafkaContainerClusterTest { + + @Test + public void testKafkaContainerCluster() throws Exception { + try ( + KafkaContainerCluster cluster = new KafkaContainerCluster("5.2.1", 3, 2) + ) { + cluster.start(); + String bootstrapServers = cluster.getBootstrapServers(); + + assertThat(cluster.getBrokers()).hasSize(3); + + testKafkaFunctionality(bootstrapServers, 3, 2); + } + } + + protected void testKafkaFunctionality(String bootstrapServers, int partitions, int rf) throws Exception { + try ( + AdminClient adminClient = AdminClient.create(ImmutableMap.of( + AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers + )); + + KafkaProducer producer = new KafkaProducer<>( + ImmutableMap.of( + ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, + ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString() + ), + new StringSerializer(), + new StringSerializer() + ); + + KafkaConsumer consumer = new KafkaConsumer<>( + ImmutableMap.of( + ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, + ConsumerConfig.GROUP_ID_CONFIG, "tc-" + UUID.randomUUID(), + ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest" + ), + new StringDeserializer(), + new StringDeserializer() + ); + ) { + String topicName = "messages"; + + Collection topics = Collections.singletonList(new NewTopic(topicName, partitions, (short) rf)); + adminClient.createTopics(topics).all().get(30, TimeUnit.SECONDS); + + consumer.subscribe(Collections.singletonList(topicName)); + + producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); + + Unreliables.retryUntilTrue(10, TimeUnit.SECONDS, () -> { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + + if (records.isEmpty()) { + return false; + } + + assertThat(records) + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + + return true; + }); + + consumer.unsubscribe(); + } + } + +} diff --git a/examples/settings.gradle b/examples/settings.gradle index 25da14a0931..ea988b4ada8 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -19,6 +19,7 @@ includeBuild '..' // explicit include to allow Dependabot to autodiscover subprojects include 'disque-job-queue' +include 'kafka-cluster' include 'linked-container' include 'mongodb-container' include 'redis-backed-cache' diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 12867239251..b1bc3d735f9 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -24,6 +24,8 @@ public class KafkaContainer extends GenericContainer { public static final int ZOOKEEPER_PORT = 2181; + private static final String DEFAULT_INTERNAL_TOPIC_RF = "1"; + private static final int PORT_NOT_ASSIGNED = -1; protected String externalZookeeperConnect = null; @@ -60,8 +62,10 @@ public KafkaContainer(final DockerImageName dockerImageName) { withEnv("KAFKA_INTER_BROKER_LISTENER_NAME", "BROKER"); withEnv("KAFKA_BROKER_ID", "1"); - withEnv("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR", "1"); - withEnv("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS", "1"); + withEnv("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR", DEFAULT_INTERNAL_TOPIC_RF); + withEnv("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS", DEFAULT_INTERNAL_TOPIC_RF); + withEnv("KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR", DEFAULT_INTERNAL_TOPIC_RF); + withEnv("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR", DEFAULT_INTERNAL_TOPIC_RF); withEnv("KAFKA_LOG_FLUSH_INTERVAL_MESSAGES", Long.MAX_VALUE + ""); withEnv("KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS", "0"); } diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index 263653822e6..d219aa17b13 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -6,8 +6,12 @@ import com.google.common.collect.ImmutableMap; import java.time.Duration; +import java.util.Collection; import java.util.UUID; import java.util.concurrent.TimeUnit; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; @@ -110,7 +114,15 @@ public void testConfluentPlatformVersion6() throws Exception { } protected void testKafkaFunctionality(String bootstrapServers) throws Exception { + testKafkaFunctionality(bootstrapServers, 1, 1); + } + + protected void testKafkaFunctionality(String bootstrapServers, int partitions, int rf) throws Exception { try ( + AdminClient adminClient = AdminClient.create(ImmutableMap.of( + AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers + )); + KafkaProducer producer = new KafkaProducer<>( ImmutableMap.of( ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, @@ -131,6 +143,10 @@ protected void testKafkaFunctionality(String bootstrapServers) throws Exception ); ) { String topicName = "messages-" + UUID.randomUUID(); + + Collection topics = singletonList(new NewTopic(topicName, partitions, (short) rf)); + adminClient.createTopics(topics).all().get(30, TimeUnit.SECONDS); + consumer.subscribe(singletonList(topicName)); producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); From 140fd94b361786e777ae87a8a9643b954ed68e00 Mon Sep 17 00:00:00 2001 From: "Junho, Kim" Date: Sun, 7 Feb 2021 00:52:02 +0900 Subject: [PATCH 1165/4969] Change docker command (#3608) Closes #3571 This also includes changing default tag version (to v19.2.11) Co-authored-by: Junho, Kim Co-authored-by: Sergei Egorov --- .../org/testcontainers/containers/CockroachContainer.java | 4 ++-- .../test/java/org/testcontainers/CockroachDBTestImages.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index 2a7990413e4..333a6ca0158 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -8,7 +8,7 @@ public class CockroachContainer extends JdbcDatabaseContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("cockroachdb/cockroach"); - private static final String DEFAULT_TAG = "v19.1.1"; + private static final String DEFAULT_TAG = "v19.2.11"; public static final String NAME = "cockroach"; @@ -53,7 +53,7 @@ public CockroachContainer(final DockerImageName dockerImageName) { .forStatusCode(200) .withStartupTimeout(Duration.ofMinutes(1)) ); - withCommand("start --insecure"); + withCommand("start-single-node --insecure"); } @Override diff --git a/modules/cockroachdb/src/test/java/org/testcontainers/CockroachDBTestImages.java b/modules/cockroachdb/src/test/java/org/testcontainers/CockroachDBTestImages.java index a309f84e098..ac02b2f5d81 100644 --- a/modules/cockroachdb/src/test/java/org/testcontainers/CockroachDBTestImages.java +++ b/modules/cockroachdb/src/test/java/org/testcontainers/CockroachDBTestImages.java @@ -3,5 +3,5 @@ import org.testcontainers.utility.DockerImageName; public interface CockroachDBTestImages { - DockerImageName COCKROACHDB_IMAGE = DockerImageName.parse("cockroachdb/cockroach:v19.1.1"); + DockerImageName COCKROACHDB_IMAGE = DockerImageName.parse("cockroachdb/cockroach:v19.2.11"); } From 8f13e420f4d8934ad4c39b4104df1dac571b88a7 Mon Sep 17 00:00:00 2001 From: Andrew Guibert Date: Sat, 6 Feb 2021 09:55:42 -0600 Subject: [PATCH 1166/4969] Show port mappings in HttpWaitStrategy (#2341) * Show port mappings in HttpWaitStrategy * Use stream to un-map exposed port * Catch and log failures when logging Co-authored-by: Richard North --- .../wait/strategy/HttpWaitStrategy.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java index a2bf4c4899e..85216bcedf6 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java @@ -162,8 +162,20 @@ protected void waitUntilReady() { if (null == livenessCheckPort || -1 == livenessCheckPort) { return; } - final String uri = buildLivenessUri(livenessCheckPort).toString(); - log.info("{}: Waiting for {} seconds for URL: {}", containerName, startupTimeout.getSeconds(), uri); + final URI rawUri = buildLivenessUri(livenessCheckPort); + final String uri = rawUri.toString(); + + try { + // Un-map the port for logging + int originalPort = waitStrategyTarget.getExposedPorts().stream() + .filter(exposedPort -> rawUri.getPort() == waitStrategyTarget.getMappedPort(exposedPort)) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Target port " + rawUri.getPort() + " is not exposed")); + log.info("{}: Waiting for {} seconds for URL: {} (where port {} maps to container port {})", containerName, startupTimeout.getSeconds(), uri, rawUri.getPort(), originalPort); + } catch (RuntimeException e) { + // do not allow a failure in logging to prevent progress, but log for diagnosis + log.warn("Unexpected error occurred - will proceed to try to wait anyway", e); + } // try to connect to the URL try { @@ -243,7 +255,7 @@ private URI buildLivenessUri(int livenessCheckPort) { if ((tlsEnabled && 443 == livenessCheckPort) || (!tlsEnabled && 80 == livenessCheckPort)) { portSuffix = ""; } else { - portSuffix = ":" + String.valueOf(livenessCheckPort); + portSuffix = ":" + livenessCheckPort; } return URI.create(scheme + host + portSuffix + path); From 1f9b44e5b1c8785613191b925030d6be09b77826 Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Sat, 6 Feb 2021 16:59:29 +0100 Subject: [PATCH 1167/4969] update release drafter to v5.13.0 (#3632) * update release drafter to v5.13.0 * use commit sha Co-authored-by: Richard North Co-authored-by: Richard North --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 3123c3f6fac..8f88ac2231e 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -9,6 +9,6 @@ jobs: update_release_draft: runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@v5.9.0 + - uses: release-drafter/release-drafter@4d1215c #v5.13.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 51ee33bad751debcaf88a0e8b7d72818db3f6df1 Mon Sep 17 00:00:00 2001 From: Renato Mefi Date: Sat, 6 Feb 2021 17:28:35 +0100 Subject: [PATCH 1168/4969] Support HTTP headers on HttpWaitStrategy (#2549) This enables webservers that depend on headers for healthchecks to be able to correctly be queried by the HttpWaitStrategy. Co-authored-by: Sergei Egorov --- .../wait/strategy/HttpWaitStrategy.java | 26 ++++++++++++++++++ .../wait/strategy/HttpWaitStrategyTest.java | 27 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java index 85216bcedf6..c4751725707 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java @@ -2,6 +2,8 @@ import com.google.common.base.Strings; import com.google.common.io.BaseEncoding; +import java.util.HashMap; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.rnorth.ducttape.TimeoutException; import org.testcontainers.containers.ContainerLaunchException; @@ -40,6 +42,7 @@ public class HttpWaitStrategy extends AbstractWaitStrategy { private boolean tlsEnabled; private String username; private String password; + private final Map headers = new HashMap<>(); private Predicate responsePredicate; private Predicate statusCodePredicate = null; private Optional livenessPort = Optional.empty(); @@ -122,6 +125,27 @@ public HttpWaitStrategy withBasicCredentials(String username, String password) { return this; } + /** + * Add a custom HTTP Header to the call. + * @param name The HTTP Header name + * @param value The HTTP Header value + * @return this + */ + public HttpWaitStrategy withHeader(String name, String value) { + this.headers.put(name, value); + return this; + } + + /** + * Add multiple custom HTTP Headers to the call. + * @param headers Headers map of name/value + * @return this + */ + public HttpWaitStrategy withHeaders(Map headers) { + this.headers.putAll(headers); + return this; + } + /** * Set the HTTP connections read timeout. * @@ -191,6 +215,8 @@ protected void waitUntilReady() { connection.setUseCaches(false); } + // Add user configured headers + this.headers.forEach(connection::setRequestProperty); connection.setRequestMethod(method); connection.connect(); diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java index e048f4bccb8..c5a39a4538c 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java @@ -1,8 +1,13 @@ package org.testcontainers.junit.wait.strategy; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; + +import java.util.HashMap; import org.jetbrains.annotations.NotNull; import org.junit.Test; import org.rnorth.ducttape.RetryCountExceededException; +import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import java.time.Duration; @@ -30,6 +35,28 @@ public void testWaitUntilReadyWithSuccess() { waitUntilReadyAndSucceed(createShellCommand("200 OK", GOOD_RESPONSE_BODY)); } + /** + * Ensures that HTTP requests made with the HttpWaitStrategy can be enriched with user defined headers, + * although the test web server does not depend on the header to response with a 200, by checking the + * logs we can ensure the HTTP request was correctly sent. + */ + @Test + public void testWaitUntilReadyWithSuccessWithCustomHeaders() { + HashMap headers = new HashMap<>(); + headers.put("baz", "boo"); + GenericContainer container = startContainerWithCommand(createShellCommand("200 OK", GOOD_RESPONSE_BODY), + createHttpWaitStrategy(ready) + .withHeader("foo", "bar") + .withHeaders(headers) + ); + waitUntilReadyAndSucceed(container); + + String logs = container.getLogs(); + + assertThat(logs, containsString("foo: bar")); + assertThat(logs, containsString("baz: boo")); + } + /** * Expects that the WaitStrategy returns successfully after receiving an HTTP 401 response from the container. * This 401 response is checked with a lambda using {@link HttpWaitStrategy#forStatusCodeMatching(Predicate)} From a6f91e3b69a401159f88d9044cb557a12441d5f6 Mon Sep 17 00:00:00 2001 From: Oussama BADR Date: Wed, 10 Feb 2021 11:08:05 +0100 Subject: [PATCH 1169/4969] Make VNC recorded videos scrollable (#3180) This PR adds a second video recording mode, MP4, which is easier to consume and is scrollable. Fixes #512 Co-authored-by: Kevin Wittek Co-authored-by: Sergei Egorov --- .../containers/VncRecordingContainer.java | 65 ++++++++-- docs/modules/webdriver_containers.md | 9 +- .../containers/BrowserWebDriverContainer.java | 12 +- .../DefaultRecordingFileFactory.java | 13 +- .../containers/RecordingFileFactory.java | 6 + .../DefaultRecordingFileFactoryTest.java | 2 +- ...ChromeRecordingWebDriverContainerTest.java | 121 +++++++++++++++--- 7 files changed, 194 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index de720110a51..a171e6ba2f6 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -2,6 +2,7 @@ import lombok.Getter; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.ToString; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; @@ -9,6 +10,7 @@ import org.testcontainers.utility.DockerImageName; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.StandardCopyOption; @@ -25,26 +27,30 @@ @ToString public class VncRecordingContainer extends GenericContainer { - private static final String RECORDING_FILE_NAME = "/screen.flv"; + private static final String ORIGINAL_RECORDING_FILE_NAME = "/screen.flv"; public static final String DEFAULT_VNC_PASSWORD = "secret"; public static final int DEFAULT_VNC_PORT = 5900; + static final VncRecordingFormat DEFAULT_RECORDING_FORMAT = VncRecordingFormat.FLV; + private final String targetNetworkAlias; private String vncPassword = DEFAULT_VNC_PASSWORD; + private VncRecordingFormat videoFormat = DEFAULT_RECORDING_FORMAT; + private int vncPort = 5900; private int frameRate = 30; public VncRecordingContainer(@NonNull GenericContainer targetContainer) { this( - targetContainer.getNetwork(), - targetContainer.getNetworkAliases().stream() - .findFirst() - .orElseThrow(() -> new IllegalStateException("Target container must have a network alias")) + targetContainer.getNetwork(), + targetContainer.getNetworkAliases().stream() + .findFirst() + .orElseThrow(() -> new IllegalStateException("Target container must have a network alias")) ); } @@ -52,7 +58,7 @@ public VncRecordingContainer(@NonNull GenericContainer targetContainer) { * Create a sidekick container and attach it to another container. The VNC output of that container will be recorded. */ public VncRecordingContainer(@NonNull Network network, @NonNull String targetNetworkAlias) throws IllegalStateException { - super(DockerImageName.parse("testcontainers/vnc-recorder:1.1.0")); + super(DockerImageName.parse("testcontainers/vnc-recorder:1.2.0")); this.targetNetworkAlias = targetNetworkAlias; withNetwork(network); @@ -71,6 +77,13 @@ public VncRecordingContainer withVncPort(int vncPort) { return this; } + public VncRecordingContainer withVideoFormat(VncRecordingFormat videoFormat) { + if (videoFormat != null) { + this.videoFormat = videoFormat; + } + return this; + } + public VncRecordingContainer withFrameRate(int frameRate) { this.frameRate = frameRate; return this; @@ -81,25 +94,53 @@ protected void configure() { withCreateContainerCmdModifier(it -> it.withEntrypoint("/bin/sh")); String encodedPassword = Base64.getEncoder().encodeToString(vncPassword.getBytes()); setCommand( - "-c", - "echo '" + encodedPassword + "' | base64 -d > /vnc_password && " + - "flvrec.py -o " + RECORDING_FILE_NAME + " -d -r " + frameRate + " -P /vnc_password " + targetNetworkAlias + " " + vncPort + "-c", + "echo '" + encodedPassword + "' | base64 -d > /vnc_password && " + + "flvrec.py -o " + ORIGINAL_RECORDING_FILE_NAME + " -d -r " + frameRate + " -P /vnc_password " + targetNetworkAlias + " " + vncPort ); } @SneakyThrows public InputStream streamRecording() { + String newRecordingFileName = videoFormat.reencodeRecording(this, ORIGINAL_RECORDING_FILE_NAME); + TarArchiveInputStream archiveInputStream = new TarArchiveInputStream( - dockerClient.copyArchiveFromContainerCmd(getContainerId(), RECORDING_FILE_NAME).exec() + dockerClient.copyArchiveFromContainerCmd(getContainerId(), newRecordingFileName).exec() ); archiveInputStream.getNextEntry(); return archiveInputStream; } @SneakyThrows - public void saveRecordingToFile(File file) { - try(InputStream inputStream = streamRecording()) { + public void saveRecordingToFile(@NonNull File file) { + try (InputStream inputStream = streamRecording()) { Files.copy(inputStream, file.toPath(), StandardCopyOption.REPLACE_EXISTING); } } + + @RequiredArgsConstructor + public enum VncRecordingFormat { + FLV("flv") { + @Override + String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull String source) throws IOException, InterruptedException { + String newFileOutput = "/newScreen.flv"; + container.execInContainer("ffmpeg", "-i", source, "-vcodec", "libx264", newFileOutput); + return newFileOutput; + } + }, + MP4("mp4") { + @Override + String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull String source) throws IOException, InterruptedException { + String newFileOutput = "/newScreen.mp4"; + container.execInContainer("ffmpeg", "-i", source, "-vcodec", "libx264", "-movflags", "faststart", newFileOutput); + return newFileOutput; + } + }; + + abstract String reencodeRecording(VncRecordingContainer container, String source) throws IOException, InterruptedException; + + @Getter + private final String filenameExtension; + } + } diff --git a/docs/modules/webdriver_containers.md b/docs/modules/webdriver_containers.md index 40b27a5207f..41b7fb6bb23 100644 --- a/docs/modules/webdriver_containers.md +++ b/docs/modules/webdriver_containers.md @@ -63,7 +63,14 @@ just for failing tests. [Record failing Tests](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordFailing -Note that the seconds parameter to `withRecordingMode` should be a directory where recordings can be saved. +Note that the second parameter of `withRecordingMode` should be a directory where recordings can be saved. + +By default, the video will be recorded in [FLV](https://en.wikipedia.org/wiki/Flash_Video) format, but you can specify it explicitly or change it to [MP4](https://en.wikipedia.org/wiki/MPEG-4_Part_14) using `withRecordingMode` method with `VncRecordingFormat` option: + + +[Video Format in MP4](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordMp4 +[Video Format in FLV](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordFlv + If you would like to customise the file name of the recording, or provide a different directory at runtime based on the description of the test and/or its success or failure, you may provide a custom recording file factory as follows: diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 1ceaf67ad2c..4a25ae486cd 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -27,6 +27,7 @@ import org.rnorth.ducttape.unreliables.Unreliables; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; @@ -66,6 +67,7 @@ public class BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) .withRecordingMode(RECORD_ALL, target) @@ -40,25 +57,96 @@ public void recordingTestThatShouldBeRecordedAndRetained() { .withRecordingFileFactory(new DefaultRecordingFileFactory()) .withNetwork(NETWORK) ) { - chrome.start(); + File[] files = runSimpleExploreInContainer(chrome, "PASSED-.*\\.flv"); + assertEquals("Recorded file not found", 1, files.length); + } + } - doSimpleExplore(chrome); - chrome.afterTest(new TestDescription() { - @Override - public String getTestId() { - return getFilesystemFriendlyName(); - } + private File[] runSimpleExploreInContainer(BrowserWebDriverContainer container, String fileNamePattern) throws InterruptedException { + container.start(); - @Override - public String getFilesystemFriendlyName() { - return "ChromeThatRecordsAllTests-recordingTestThatShouldBeRecordedAndRetained"; - } - }, Optional.empty()); + TimeUnit.MILLISECONDS.sleep(MINIMUM_VIDEO_DURATION_MILLISECONDS); + doSimpleExplore(container); + container.afterTest(new TestDescription() { + @Override + public String getTestId() { + return getFilesystemFriendlyName(); + } + + @Override + public String getFilesystemFriendlyName() { + return "ChromeThatRecordsAllTests-recordingTestThatShouldBeRecordedAndRetained"; + } + }, Optional.empty()); + + return vncRecordingDirectory.getRoot().listFiles(new PatternFilenameFilter(fileNamePattern)); + } - String[] files = vncRecordingDirectory.getRoot().list(new PatternFilenameFilter("PASSED-.*\\.flv")); + @Test + public void recordingTestShouldHaveFlvExtension() throws InterruptedException { + File target = vncRecordingDirectory.getRoot(); + try ( + // recordFlv { + // Set (explicitly) FLV format for recorded video: + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() + .withCapabilities(new ChromeOptions()) + .withRecordingMode(RECORD_ALL, target, VncRecordingFormat.FLV) + // } + .withRecordingFileFactory(new DefaultRecordingFileFactory()) + .withNetwork(NETWORK) + ) { + File[] files = runSimpleExploreInContainer(chrome, "PASSED-.*\\.flv"); assertEquals("Recorded file not found", 1, files.length); } } + + @Test + public void recordingTestShouldHaveMp4Extension() throws InterruptedException { + File target = vncRecordingDirectory.getRoot(); + try ( + // recordMp4 { + // Set MP4 format for recorded video: + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() + .withCapabilities(new ChromeOptions()) + .withRecordingMode(RECORD_ALL, target, VncRecordingFormat.MP4) + // } + .withRecordingFileFactory(new DefaultRecordingFileFactory()) + .withNetwork(NETWORK) + ) { + File[] files = runSimpleExploreInContainer(chrome, "PASSED-.*\\.mp4"); + assertEquals("Recorded file not found", 1, files.length); + } + } + + @Test + public void recordingTestThatShouldHaveCorrectDuration() throws IOException, InterruptedException { + MountableFile mountableFile; + try ( + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() + .withCapabilities(new ChromeOptions()) + .withRecordingMode(RECORD_ALL, vncRecordingDirectory.getRoot()) + .withRecordingFileFactory(new DefaultRecordingFileFactory()) + .withNetwork(NETWORK) + ) { + File[] recordedFiles = runSimpleExploreInContainer(chrome, "PASSED-.*\\.flv"); + mountableFile = MountableFile.forHostPath(recordedFiles[0].getCanonicalPath()); + } + + try (GenericContainer container = new GenericContainer<>(DockerImageName.parse("testcontainers/vnc-recorder:1.2.0"))) { + String recordFileContainerPath = "/tmp/chromeTestRecord.flv"; + container.withCopyFileToContainer(mountableFile, recordFileContainerPath) + .withCreateContainerCmdModifier(createContainerCmd -> createContainerCmd.withEntrypoint("ffmpeg")) + .withCommand("-i", recordFileContainerPath, "-f", "null", "-") + .waitingFor(new LogMessageWaitStrategy() + .withRegEx(".*Duration.*") + .withStartupTimeout(Duration.of(60, SECONDS))) + .start(); + String ffmpegOutput = container.getLogs(); + + assertTrue("Duration is incorrect in:\n " + ffmpegOutput, + ffmpegOutput.contains("Duration: 00:") && !(ffmpegOutput.contains("Duration: 00:00:00.00"))); + } + } } public static class ChromeThatRecordsFailingTests { @@ -85,7 +173,7 @@ public void recordingTestThatShouldBeRecordedButNotPersisted() { } @Test - public void recordingTestThatShouldBeRecordedAndRetained() { + public void recordingTestThatShouldBeRecordedAndRetained() throws InterruptedException { File target = vncRecordingDirectory.getRoot(); try ( // recordFailing { @@ -99,6 +187,7 @@ public void recordingTestThatShouldBeRecordedAndRetained() { ) { chrome.start(); + TimeUnit.MILLISECONDS.sleep(MINIMUM_VIDEO_DURATION_MILLISECONDS); doSimpleExplore(chrome); chrome.afterTest(new TestDescription() { @Override From b62b0ef2b7a98815f0a1937c9c1991a232e05aad Mon Sep 17 00:00:00 2001 From: Chris Roemmich Date: Wed, 10 Feb 2021 04:11:42 -0600 Subject: [PATCH 1170/4969] Implement getDatabaseName() in CockroachContainer (#3778) Co-authored-by: Sergei Egorov --- .../org/testcontainers/containers/CockroachContainer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index 333a6ca0158..f32e6bce385 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -68,6 +68,11 @@ public String getJdbcUrl() { "/" + databaseName + additionalUrlParams; } + @Override + public final String getDatabaseName() { + return databaseName; + } + @Override public String getUsername() { return username; From b0f1bbcd2eb83f939681390ca56fd929996781ab Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Wed, 10 Feb 2021 13:41:58 +0100 Subject: [PATCH 1171/4969] Switch to Presto image hosted on GHCR (#3667) The `prestosql` Docker Hub org has been deprecated and the current Presto image has been moved to GitHub Container Registry. --- .../java/org/testcontainers/containers/PrestoContainer.java | 4 ++-- .../src/test/java/org/testcontainers/PrestoTestImages.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index 54cc6758562..1d9e02114ac 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -16,8 +16,8 @@ public class PrestoContainer> extends JdbcDatabaseContainer { public static final String NAME = "presto"; - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("prestosql/presto"); - public static final String IMAGE = "prestosql/presto"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("ghcr.io/trinodb/presto"); + public static final String IMAGE = "ghcr.io/trinodb/presto"; public static final String DEFAULT_TAG = "344"; public static final Integer PRESTO_PORT = 8080; diff --git a/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java b/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java index a257500576c..174cb7b4d4a 100644 --- a/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java +++ b/modules/presto/src/test/java/org/testcontainers/PrestoTestImages.java @@ -3,6 +3,6 @@ import org.testcontainers.utility.DockerImageName; public interface PrestoTestImages { - DockerImageName PRESTO_TEST_IMAGE = DockerImageName.parse("prestosql/presto:344"); - DockerImageName PRESTO_PREVIOUS_VERSION_TEST_IMAGE = DockerImageName.parse("prestosql/presto:343"); + DockerImageName PRESTO_TEST_IMAGE = DockerImageName.parse("ghcr.io/trinodb/presto:344"); + DockerImageName PRESTO_PREVIOUS_VERSION_TEST_IMAGE = DockerImageName.parse("ghcr.io/trinodb/presto:343"); } From 106463b2e77d45552dfbfdb23aa559de47bea8cd Mon Sep 17 00:00:00 2001 From: Per Lundberg Date: Wed, 10 Feb 2021 17:38:38 +0200 Subject: [PATCH 1172/4969] Fix extra newlines in container log / exec output (#3752) Fixes #1763 Fixes #1854 Co-authored-by: Sergei Egorov --- .../containers/output/ToStringConsumer.java | 7 -- .../output/ToStringConsumerTest.java | 89 +++++++++++++++++++ 2 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java diff --git a/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java b/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java index a12325865aa..40ec60fb744 100644 --- a/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java @@ -10,21 +10,14 @@ * Created by rnorth on 26/03/2016. */ public class ToStringConsumer extends BaseConsumer { - private static final byte[] NEW_LINE = "\n".getBytes(); - - private boolean firstLine = true; private ByteArrayOutputStream stringBuffer = new ByteArrayOutputStream(); @Override public void accept(OutputFrame outputFrame) { try { if (outputFrame.getBytes() != null) { - if (!firstLine) { - stringBuffer.write(NEW_LINE); - } stringBuffer.write(outputFrame.getBytes()); stringBuffer.flush(); - firstLine = false; } } catch (IOException e) { throw new RuntimeException(e); diff --git a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java new file mode 100644 index 00000000000..1610c688931 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java @@ -0,0 +1,89 @@ +package org.testcontainers.containers.output; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.commons.lang.RandomStringUtils; +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.testcontainers.containers.Container.ExecResult; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; + +public class ToStringConsumerTest { + + private static final String LARGE_PAYLOAD; + + static { + StringBuilder builder = new StringBuilder(10_003 * 10);; + for (int i = 0; i < 10; i++) { + builder.append(' ').append(i).append(RandomStringUtils.randomAlphabetic(10000)); + } + LARGE_PAYLOAD = builder.toString(); + Assertions.assertThat(LARGE_PAYLOAD).doesNotContain("\n"); + } + + @Test + public void newlines_are_not_added_to_exec_output() throws Exception { + try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + container.withCommand("sleep", "2m"); + container.start(); + + ExecResult build = container.execInContainer("echo", "-n", LARGE_PAYLOAD); + Assertions.assertThat(build.getStdout()) + .doesNotContain("\n") + .isEqualTo(LARGE_PAYLOAD); + } + } + + @Test(timeout = 60_000L) + public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { + try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + container.withCreateContainerCmdModifier(cmd -> { + cmd + .withAttachStdin(true) + .withStdinOpen(true) + .withTty(true); + }); + container.withCommand("sleep", "2m"); + container.start(); + + ExecResult build = container.execInContainer("echo", "-n", LARGE_PAYLOAD); + assertThat(build.getStdout()) + .isEqualTo(LARGE_PAYLOAD) + .doesNotContain("\n"); + } + } + + @Test + public void newlines_are_not_added_to_container_output() { + try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + container.withCommand("echo", "-n", LARGE_PAYLOAD); + container.setStartupCheckStrategy(new OneShotStartupCheckStrategy()); + container.start(); + + container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode(); + + assertThat(container.getLogs()) + .isEqualTo(LARGE_PAYLOAD) + .doesNotContain("\n"); + } + } + + @Test + public void newlines_are_not_added_to_container_output_with_tty() { + try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + container.withCreateContainerCmdModifier(cmd -> { + cmd.withTty(true); + }); + container.withCommand("echo", "-n", LARGE_PAYLOAD); + container.setStartupCheckStrategy(new OneShotStartupCheckStrategy()); + container.start(); + + container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode(); + + assertThat(container.getLogs()) + .isEqualTo(LARGE_PAYLOAD) + .doesNotContain("\n"); + } + } +} From c0eaf3412d5a6520ab973e9a693234877ae476e8 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 11 Feb 2021 16:57:46 +0100 Subject: [PATCH 1173/4969] Update mkdocs.yml --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 2457d06bcf0..82f2d291164 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -94,4 +94,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.15.1 + latest_version: 1.15.2 From eaf9b9fe2aab4e60a4b0079e7c15afb38bb44beb Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Mon, 15 Feb 2021 21:11:59 +0100 Subject: [PATCH 1174/4969] Delegate copyFile{To,From}Container's state verification to Docker (#3805) This commit closes #3264 by letting the Docker daemon decide in which state the copy operation could be performed (we were too strict about it before). Now, only a quick check (`containerId != null`) is performed. Co-authored-by: Andrew Jefferson Co-authored-by: Sergei Egorov --- .../containers/ContainerState.java | 4 +- .../junit/FileOperationsTest.java | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 1b1a99d3b89..ad96aeb808c 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -260,7 +260,7 @@ default void copyFileToContainer(MountableFile mountableFile, String containerPa */ @SneakyThrows(IOException.class) default void copyFileToContainer(Transferable transferable, String containerPath) { - if (!isCreated()) { + if (getContainerId() == null) { throw new IllegalStateException("copyFileToContainer can only be used with created / running container"); } @@ -306,7 +306,7 @@ default void copyFileFromContainer(String containerPath, String destinationPath) */ @SneakyThrows default T copyFileFromContainer(String containerPath, ThrowingFunction function) { - if (!isCreated()) { + if (getContainerId() == null) { throw new IllegalStateException("copyFileFromContainer can only be used when the Container is created."); } diff --git a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java index 5e12fafc064..beca4a8a49f 100644 --- a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java +++ b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java @@ -2,15 +2,19 @@ import com.github.dockerjava.api.exception.NotFoundException; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.utility.MountableFile; import java.io.File; import java.io.IOException; +import static org.assertj.core.api.Assertions.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; import static org.testcontainers.TestImages.ALPINE_IMAGE; @@ -103,4 +107,50 @@ public void shouldCopyFileFromContainerTest() throws IOException { assertTrue("Files aren't same ", FileUtils.contentEquals(expectedFile, actualFile)); } } + + @Test + public void copyFileOperationsShouldFailWhenNotStartedTest() { + try (GenericContainer container = new GenericContainer<>(ALPINE_IMAGE).withCommand("top")) { + Assertions + .assertThatThrownBy(() -> { + MountableFile mountableFile = MountableFile.forClasspathResource("test_copy_to_container.txt"); + container.copyFileToContainer(mountableFile, "/home/test.txt"); + }) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("can only be used with created / running container"); + + Assertions + .assertThatThrownBy(() -> { + container.copyFileFromContainer( + "/home/test_copy_to_container.txt", + IOUtils::toByteArray + ); + }) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("can only be used when the Container is created"); + } + } + + @Test + public void shouldCopyFileFromExitedContainerTest() throws IOException { + try ( + GenericContainer container = new GenericContainer<>(ALPINE_IMAGE) + .withCommand("sh", "-c", "echo -n 'Hello!' > /home/file_in_container.txt") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + assertThat(container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode()) + .isEqualTo(0); + + container.copyFileFromContainer( + "/home/file_in_container.txt", + IOUtils::toByteArray + ); + + container.copyFileToContainer( + MountableFile.forClasspathResource("test_copy_to_container.txt"), + "/test.txt" + ); + } + } } From f588082636dc2749f4129e943b02ede62527b41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20Br=C3=BCnings?= Date: Fri, 19 Feb 2021 16:57:23 +0100 Subject: [PATCH 1175/4969] Fix mp4 recording to be compatible with Firefox (#3812) Firefox still doesn't support yuv444 so use yuv420p https://shallowsky.com/blog/linux/videos-from-images.html --- .../org/testcontainers/containers/VncRecordingContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index a171e6ba2f6..be8a4ed735f 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -132,7 +132,7 @@ String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull Stri @Override String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull String source) throws IOException, InterruptedException { String newFileOutput = "/newScreen.mp4"; - container.execInContainer("ffmpeg", "-i", source, "-vcodec", "libx264", "-movflags", "faststart", newFileOutput); + container.execInContainer("ffmpeg", "-i", source, "-vcodec", "libx264", "-movflags", "faststart", "-pix_fmt", "yuv420p", newFileOutput); return newFileOutput; } }; From 80a172e6fd0e82b476bf76e9ad3d9440fbd4b07b Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 8 Mar 2021 12:48:22 -0700 Subject: [PATCH 1176/4969] Add Google (#3868) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index bc6d1e64afe..b53ebbf4db5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -163,6 +163,7 @@ A huge thank you to our sponsors: * [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) * [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS * [Trino (formerly Presto SQL)](https://trino.io) - Integration testing all Trino core & connectors, including tests of multi-node deployments and security configurations. +* Google - Various open source projects: [OpenTelemetry](https://github.com/GoogleCloudPlatform/opentelemetry-operations-java), [Universal Application Tool](https://github.com/seattle-uat/universal-application-tool), [CloudBowl](https://github.com/GoogleCloudPlatform/cloudbowl-microservice-game) ## License From 5c1ac7ca518d985495afd76b89ee5325145adbfc Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 12 Mar 2021 09:58:56 +0000 Subject: [PATCH 1177/4969] Fix GitHub Actions error due to short SHA form (#3874) --- .github/workflows/release-drafter.yml | 2 +- .github/workflows/update-docs-version.yml | 2 +- .github/workflows/update-gradle-wrapper.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 8f88ac2231e..28f14cb0ad3 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -9,6 +9,6 @@ jobs: update_release_draft: runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@4d1215c #v5.13.0 + - uses: release-drafter/release-drafter@e5ccf147077e46b0225a80bbe314d795d77bb7a2 # v5.14.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index d2eb803fda2..64658c1be4a 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -22,6 +22,6 @@ jobs: git add mkdocs.yml git commit -m "Update documentation version to ${GITHUB_REF##*/}" -m "skip-checks: true" || echo "not changed" - name: Push changes - uses: ad-m/github-push-action@40bf560936a8022e68a3c00e7d2abefaf01305a6 + uses: ad-m/github-push-action@40bf560936a8022e68a3c00e7d2abefaf01305a6 # v0.6.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index e8f4f130b12..d34110f5a6d 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -12,9 +12,9 @@ jobs: - uses: actions/checkout@v2 - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@74a035ce333f39c84811ce1167669bfa6c65f440 + uses: gradle-update/update-gradle-wrapper-action@af940e8bff73d435137caae9d08cf7a1badf5497 # v1.0.13 with: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies - - uses: gradle/wrapper-validation-action@e2c57acffb2c9aa5a8dc6eda2bbae0b6e495bd4c + - uses: gradle/wrapper-validation-action@e2c57acffb2c9aa5a8dc6eda2bbae0b6e495bd4c # v1.0.3 From ca1dfc499d801d2a4882d9b1e4dfe1150498cfaa Mon Sep 17 00:00:00 2001 From: Erhun Baycelik Date: Fri, 12 Mar 2021 15:59:38 +0200 Subject: [PATCH 1178/4969] Documentation TransferWise has changed its name as Wise. (#3873) Co-authored-by: Richard North --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index b53ebbf4db5..6efa8f82eb3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -158,7 +158,7 @@ A huge thank you to our sponsors: * [JHipster](https://www.jhipster.tech/) - Couchbase and Cassandra integration testing * [wescale](https://www.wescale.com) - Integration testing against HTTP service mocks and various data stores * [Marquez](https://marquezproject.github.io/marquez) - PostgreSQL integration testing -* [Transferwise](https://transferwise.com/) - Integration testing for different RDBMS, kafka and micro services +* [Wise (formerly TransferWise)](https://wise.com) - Integration testing for different RDBMS, kafka and micro services * [XWiki](https://xwiki.org) - [Testing XWiki](https://dev.xwiki.org/xwiki/bin/view/Community/Testing/DockerTesting/) under all [supported configurations](https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/) * [Apache SkyWalking](http://github.com/apache/skywalking) - End-to-end testing of the Apache SkyWalking, and plugin tests of its subproject, [Apache SkyWalking Python](http://github.com/apache/skywalking-python), and of its eco-system built by the community, like [SkyAPM NodeJS Agent](http://github.com/SkyAPM/nodejs) * [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS From 61dcd7ce371f84d28fcc28192223d41c20eb95bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Torres?= Date: Fri, 12 Mar 2021 16:33:44 +0000 Subject: [PATCH 1179/4969] Add Backbase to "who is using" section (#3870) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 6efa8f82eb3..18fd3f034b1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -164,6 +164,7 @@ A huge thank you to our sponsors: * [jOOQ](https://www.jooq.org) - Integration testing all of jOOQ with a variety of RDBMS * [Trino (formerly Presto SQL)](https://trino.io) - Integration testing all Trino core & connectors, including tests of multi-node deployments and security configurations. * Google - Various open source projects: [OpenTelemetry](https://github.com/GoogleCloudPlatform/opentelemetry-operations-java), [Universal Application Tool](https://github.com/seattle-uat/universal-application-tool), [CloudBowl](https://github.com/GoogleCloudPlatform/cloudbowl-microservice-game) +* [Backbase](https://www.backbase.com/) - Unit, Integration and Acceptance testing for different the databases supported (Oracle, SQL Server, MySQL), the different messaging systems supported (Kafka, Rabbit, AMQ) and other microservices and HTTP mocks. ## License From 60865fa43113eaa1bce6c6761fcd9027c58c05cc Mon Sep 17 00:00:00 2001 From: Viktar Patotski Date: Sat, 13 Mar 2021 11:55:34 +0100 Subject: [PATCH 1180/4969] Bump docs environment to python 3.7 (#3871) --- docker-compose.yml | 2 +- docs/contributing_docs.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 822956457f7..1ce5532d0bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.7" services: docs: - image: python:3.6 + image: python:3.7 command: sh -c "pip install -r requirements.txt && mkdocs serve -a 0.0.0.0:8000" working_dir: /docs volumes: diff --git a/docs/contributing_docs.md b/docs/contributing_docs.md index 9ed4b08169c..f6f9304a339 100644 --- a/docs/contributing_docs.md +++ b/docs/contributing_docs.md @@ -15,7 +15,7 @@ The root of the project contains a `docker-compose.yml` file. Simply run `docker ### Using Python locally -* Ensure that you have Python 3.6.0 or higher. +* Ensure that you have Python 3.7.0 or higher. * Set up a virtualenv and run `pip install -r requirements.txt` in the `testcontainers-java` root directory. * Once Python dependencies have been installed, run `mkdocs serve` to start a local auto-updating MkDocs server. From b635eb5ac38d8c2235dd4a2af145dca21d43dcfc Mon Sep 17 00:00:00 2001 From: GooseMagnet Date: Sat, 13 Mar 2021 05:59:40 -0500 Subject: [PATCH 1181/4969] Fix NPE bug with docker-compose files in working directory (#3866) --- .../containers/ParsedDockerComposeFile.java | 2 ++ .../junit/DockerComposeContainerTest.java | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java index 8f88724647f..a0972273b5b 100644 --- a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java +++ b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java @@ -120,6 +120,7 @@ private void findImageNamesInDockerfile(Map serviceDefinitionMap) { final Object contextRelativePath = buildElement.get("context"); if (dockerfileRelativePath instanceof String && contextRelativePath instanceof String) { dockerfilePath = composeFile + .getAbsoluteFile() .getParentFile() .toPath() .resolve((String) contextRelativePath) @@ -128,6 +129,7 @@ private void findImageNamesInDockerfile(Map serviceDefinitionMap) { } } else if (buildNode instanceof String) { dockerfilePath = composeFile + .getAbsoluteFile() .getParentFile() .toPath() .resolve((String) buildNode) diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java index 53d90872332..17a9b665513 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java @@ -6,6 +6,9 @@ import org.testcontainers.containers.DockerComposeContainer; import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.Optional; import static java.lang.String.format; @@ -53,4 +56,24 @@ public void shouldReturnEmptyResultOnNoneExistingService() { Optional result = environment.getContainerByServiceName(notExistingServiceName); assertFalse(format("No container should be found under service name %s", notExistingServiceName), result.isPresent()); } + + @Test + public void shouldCreateContainerWhenFileNotPrefixedWithPath() throws IOException { + String validYaml = + "version: '2.2'\n" + + "services:\n" + + " http:\n" + + " build: .\n" + + " image: python:latest\n" + + " ports:\n" + + " - 8080:8080"; + + File filePathNotStartWithDotSlash = new File("docker-compose-test.yml"); + filePathNotStartWithDotSlash.createNewFile(); + filePathNotStartWithDotSlash.deleteOnExit(); + Files.write(filePathNotStartWithDotSlash.toPath(), validYaml.getBytes(StandardCharsets.UTF_8)); + + final DockerComposeContainer dockerComposeContainer = new DockerComposeContainer<>(filePathNotStartWithDotSlash); + assertNotNull("Container could not be created using docker compose file", dockerComposeContainer); + } } From 26be859459a8596a58791f4b7101fe7026a3d5ba Mon Sep 17 00:00:00 2001 From: askfor Date: Sat, 13 Mar 2021 19:07:11 +0800 Subject: [PATCH 1182/4969] Make DockerComposeContainer only pull necessary images when multiple compose files were given (#3787) Co-authored-by: tianjie --- .../containers/DockerComposeContainer.java | 7 ++- .../containers/DockerComposeFiles.java | 43 +++++++++++++++++++ .../containers/ParsedDockerComposeFile.java | 17 ++++---- .../containers/DockerComposeFilesTest.java | 25 +++++++++++ ...ParsedDockerComposeFileValidationTest.java | 30 ++++++++++--- .../docker-compose-imagename-overriding-a.yml | 12 ++++++ .../docker-compose-imagename-overriding-b.yml | 10 +++++ 7 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java create mode 100644 core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java create mode 100644 core/src/test/resources/docker-compose-imagename-overriding-a.yml create mode 100644 core/src/test/resources/docker-compose-imagename-overriding-b.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 3d58ad53b3b..89d6d692db7 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -77,7 +77,7 @@ public class DockerComposeContainer> e */ private final String identifier; private final List composeFiles; - private Set parsedComposeFiles; + private DockerComposeFiles dockerComposeFiles; private final Map scalingPreferences = new HashMap<>(); private DockerClient dockerClient; private boolean localCompose; @@ -126,7 +126,7 @@ public DockerComposeContainer(String identifier, File... composeFiles) { public DockerComposeContainer(String identifier, List composeFiles) { this.composeFiles = composeFiles; - this.parsedComposeFiles = composeFiles.stream().map(ParsedDockerComposeFile::new).collect(Collectors.toSet()); + this.dockerComposeFiles = new DockerComposeFiles(composeFiles); // Use a unique identifier so that containers created for this compose environment can be identified this.identifier = identifier; @@ -184,8 +184,7 @@ private void pullImages() { // Pull images using our docker client rather than compose itself, // (a) as a workaround for https://github.com/docker/compose/issues/5854, which prevents authenticated image pulls being possible when credential helpers are in use // (b) so that credential helper-based auth still works when compose is running from within a container - parsedComposeFiles.stream() - .flatMap(it -> it.getDependencyImageNames().stream()) + dockerComposeFiles.getDependencyImages() .forEach(imageName -> { try { log.info("Preemptively checking local images for '{}', referenced via a compose file or transitive Dockerfile. If not available, it will be pulled.", imageName); diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java b/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java new file mode 100644 index 00000000000..15d035e3673 --- /dev/null +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java @@ -0,0 +1,43 @@ +package org.testcontainers.containers; + +import java.io.File; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +public class DockerComposeFiles { + + private List parsedComposeFiles; + + public DockerComposeFiles(List composeFiles) { + this.parsedComposeFiles = composeFiles.stream().map(ParsedDockerComposeFile::new).collect(Collectors.toList()); + } + + public Set getDependencyImages() { + + Map> mergedServiceNameToImageNames = mergeServiceDependencyImageNames(); + + return getImageNames(mergedServiceNameToImageNames); + } + + private Map> mergeServiceDependencyImageNames() { + Map> mergedServiceNameToImageNames = new HashMap(); + for (ParsedDockerComposeFile parsedComposeFile : parsedComposeFiles) { + for (Entry> entry : parsedComposeFile.getServiceNameToImageNames().entrySet()) { + mergedServiceNameToImageNames.put(entry.getKey(), entry.getValue()); + } + } + return mergedServiceNameToImageNames; + } + + private Set getImageNames(Map> serviceToImageNames) { + Set imageNames = new HashSet<>(); + serviceToImageNames.values().stream().forEach(imageNames::addAll); + return imageNames; + } + +} diff --git a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java index a0972273b5b..e9457ba92bd 100644 --- a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java +++ b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Sets; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -12,7 +13,7 @@ import java.io.FileInputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashSet; +import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -29,7 +30,7 @@ class ParsedDockerComposeFile { private final File composeFile; @Getter - private Set dependencyImageNames = new HashSet<>(); + private Map> serviceNameToImageNames = new HashMap<>(); ParsedDockerComposeFile(File composeFile) { Yaml yaml = new Yaml(); @@ -87,8 +88,8 @@ private void parseAndValidate() { final Map serviceDefinitionMap = (Map) serviceDefinition; validateNoContainerNameSpecified(serviceName, serviceDefinitionMap); - findServiceImageName(serviceDefinitionMap); - findImageNamesInDockerfile(serviceDefinitionMap); + findServiceImageName(serviceName, serviceDefinitionMap); + findImageNamesInDockerfile(serviceName, serviceDefinitionMap); } } @@ -102,15 +103,15 @@ private void validateNoContainerNameSpecified(String serviceName, Map serviceDef } } - private void findServiceImageName(Map serviceDefinitionMap) { + private void findServiceImageName(String serviceName, Map serviceDefinitionMap) { if (serviceDefinitionMap.containsKey("image") && serviceDefinitionMap.get("image") instanceof String) { final String imageName = (String) serviceDefinitionMap.get("image"); log.debug("Resolved dependency image for Docker Compose in {}: {}", composeFileName, imageName); - dependencyImageNames.add(imageName); + serviceNameToImageNames.put(serviceName, Sets.newHashSet(imageName)); } } - private void findImageNamesInDockerfile(Map serviceDefinitionMap) { + private void findImageNamesInDockerfile(String serviceName, Map serviceDefinitionMap) { final Object buildNode = serviceDefinitionMap.get("build"); Path dockerfilePath = null; @@ -141,7 +142,7 @@ private void findImageNamesInDockerfile(Map serviceDefinitionMap) { Set resolvedImageNames = new ParsedDockerfile(dockerfilePath).getDependencyImageNames(); if (!resolvedImageNames.isEmpty()) { log.debug("Resolved Dockerfile dependency images for Docker Compose in {} -> {}: {}", composeFileName, dockerfilePath, resolvedImageNames); - this.dependencyImageNames.addAll(resolvedImageNames); + this.serviceNameToImageNames.put(serviceName, resolvedImageNames); } } } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java new file mode 100644 index 00000000000..8dbcde2181d --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java @@ -0,0 +1,25 @@ +package org.testcontainers.containers; + + +import com.google.common.collect.Lists; +import java.io.File; +import org.assertj.core.api.Assertions; +import org.junit.Test; + +public class DockerComposeFilesTest { + @Test + public void shouldGetDependencyImages() { + DockerComposeFiles dockerComposeFiles = new DockerComposeFiles(Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"))); + Assertions.assertThat(dockerComposeFiles.getDependencyImages()) + .containsExactlyInAnyOrder("postgres", "redis", "mysql"); + } + + @Test + public void shouldGetDependencyImagesWhenOverriding() { + DockerComposeFiles dockerComposeFiles = new DockerComposeFiles( + Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-overriding-a.yml"), + new File("src/test/resources/docker-compose-imagename-overriding-b.yml"))); + Assertions.assertThat(dockerComposeFiles.getDependencyImages()) + .containsExactlyInAnyOrder("alpine:3.2", "redis:b", "mysql:b", "aservice"); + } +} diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java index 9a8421086f1..bdceba343d9 100644 --- a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -9,7 +9,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.entry; public class ParsedDockerComposeFileValidationTest { @@ -76,27 +76,47 @@ public void shouldIgnoreUnknownStructure() { public void shouldObtainImageNamesV1() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v1.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "postgres"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, postgres from Dockerfile build + Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + .contains( + entry("mysql", Sets.newHashSet("mysql")), + entry("redis", Sets.newHashSet("redis")), + entry("custom", Sets.newHashSet("postgres"))) + .as("all defined images are found"); // redis, mysql from compose file, postgres from Dockerfile build } @Test public void shouldObtainImageNamesV2() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "postgres"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, postgres from Dockerfile build + Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + .contains( + entry("mysql", Sets.newHashSet("mysql")), + entry("redis", Sets.newHashSet("redis")), + entry("custom", Sets.newHashSet("postgres"))) + .as("all defined images are found"); } @Test public void shouldObtainImageFromDockerfileBuild() { File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "alpine:3.2"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, alpine:3.2 from Dockerfile build + Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + .contains( + entry("mysql", Sets.newHashSet("mysql")), + entry("redis", Sets.newHashSet("redis")), + entry("custom", Sets.newHashSet("alpine:3.2"))) + .as("all defined images are found"); // r/ redis, mysql from compose file, alpine:3.2 from Dockerfile build } @Test public void shouldObtainImageFromDockerfileBuildWithContext() { File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - assertEquals("all defined images are found", Sets.newHashSet("redis", "mysql", "alpine:3.2"), parsedFile.getDependencyImageNames()); // redis, mysql from compose file, alpine:3.2 from Dockerfile build + Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + .contains( + entry("mysql", Sets.newHashSet("mysql")), + entry("redis", Sets.newHashSet("redis")), + entry("custom", Sets.newHashSet("alpine:3.2"))) + .as("all defined images are found"); // redis, mysql from compose file, alpine:3.2 from Dockerfile build } } diff --git a/core/src/test/resources/docker-compose-imagename-overriding-a.yml b/core/src/test/resources/docker-compose-imagename-overriding-a.yml new file mode 100644 index 00000000000..50b226d32a4 --- /dev/null +++ b/core/src/test/resources/docker-compose-imagename-overriding-a.yml @@ -0,0 +1,12 @@ +version: "2.1" +services: + aservice: + image: aservice + redis: + image: redis:a + mysql: + image: mysql:a + custom: + build: . +networks: + custom_network: {} diff --git a/core/src/test/resources/docker-compose-imagename-overriding-b.yml b/core/src/test/resources/docker-compose-imagename-overriding-b.yml new file mode 100644 index 00000000000..7e6f83c6b6a --- /dev/null +++ b/core/src/test/resources/docker-compose-imagename-overriding-b.yml @@ -0,0 +1,10 @@ +version: "2.1" +services: + redis: + image: redis:b + mysql: + image: mysql:b + custom: + build: compose-dockerfile +networks: + custom_network: {} From 3c8beb2be6d94567bb7856aefc407eadb9a868f2 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sat, 13 Mar 2021 12:19:32 +0000 Subject: [PATCH 1183/4969] Bump copyright dates and remove Java 8 reference --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ec5ab97ca12..c87138e7d1a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Testcontainers -> Testcontainers is a Java 8 library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. +> Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. [![Build Status](https://travis-ci.org/testcontainers/testcontainers-java.svg?branch=master)](https://travis-ci.org/testcontainers/testcontainers-java)[ ![Download](https://api.bintray.com/packages/testcontainers/releases/testcontainers/images/download.svg) ](https://bintray.com/testcontainers/releases/testcontainers/_latestVersion) @@ -14,10 +14,10 @@ See [LICENSE](LICENSE). ## Copyright -Copyright (c) 2015 - 2020 Richard North and other authors. +Copyright (c) 2015 - 2021 Richard North and other authors. -MS SQL Server module is (c) 2017 - 2020 G DATA Software AG and other authors. +MS SQL Server module is (c) 2017 - 2021 G DATA Software AG and other authors. -Hashicorp Vault module is (c) 2017 - 2020 Capital One Services, LLC and other authors. +Hashicorp Vault module is (c) 2017 - 2021 Capital One Services, LLC and other authors. See [contributors](https://github.com/testcontainers/testcontainers-java/graphs/contributors) for all contributors. From 57ce0c4861d83c804fc1eafb0d2239f35726553f Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 15 Mar 2021 10:45:39 +0000 Subject: [PATCH 1184/4969] Update copyright date --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 18fd3f034b1..013c18d0700 100644 --- a/docs/index.md +++ b/docs/index.md @@ -179,6 +179,6 @@ This project was initially inspired by a [gist](https://gist.github.com/mosheesh ## Copyright -Copyright (c) 2015-2020 Richard North and other authors. +Copyright (c) 2015-2021 Richard North and other authors. See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/AUTHORS) for contributors. From a406f0441d4a08431aff2bd661f9baada2e4fe19 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 19 Mar 2021 20:16:43 +0000 Subject: [PATCH 1185/4969] Add Cloudflare Web Analytics to docs site (#3896) --- docs/theme/main.html | 5 +++++ mkdocs.yml | 1 + 2 files changed, 6 insertions(+) create mode 100644 docs/theme/main.html diff --git a/docs/theme/main.html b/docs/theme/main.html new file mode 100644 index 00000000000..f96a2669e7e --- /dev/null +++ b/docs/theme/main.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} + +{% block analytics %} + +{% endblock %} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 82f2d291164..b0608746825 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,6 +5,7 @@ plugins: - markdownextradata theme: name: 'material' + custom_dir: 'docs/theme' palette: primary: 'blue' accent: 'teal' From a032dc21f4991c43dd30f187136d91eadb623b46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Mar 2021 09:31:48 +0000 Subject: [PATCH 1186/4969] Docs: Bump jinja2 from 2.11.2 to 2.11.3 (#3897) Bumps [jinja2](https://github.com/pallets/jinja) from 2.11.2 to 2.11.3. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/master/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/2.11.2...2.11.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Pipfile.lock | 254 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 179 insertions(+), 75 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 899f8c82170..6ac609b04a9 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c9a90b5f198797e8a6165fa7cb6c2143158bed425d0a8c5f63dc37ea4dcab632" + "sha256": "d3830267ea93391a077a2ba5b93aa8218c0a38002694b404b56df11498da3e56" }, "pipfile-spec": 6, "requires": { @@ -18,76 +18,112 @@ "default": { "click": { "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", + "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" ], - "version": "==7.0" + "version": "==7.1.2" + }, + "importlib-metadata": { + "hashes": [ + "sha256:742add720a20d0467df2f444ae41704000f50e1234f46174b51f9c6031a1bd71", + "sha256:b74159469b464a99cb8cc3e21973e4d96e05d3024d337313fedb618a6e86e6f4" + ], + "markers": "python_version < '3.8'", + "version": "==3.7.3" }, "jinja2": { "hashes": [ - "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", - "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", + "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" ], - "version": "==2.11.2" + "index": "pypi", + "version": "==2.11.3" }, "livereload": { "hashes": [ - "sha256:29cadfabcedd12eed792e0131991235b9d4764d4474bed75cf525f57109ec0a2", - "sha256:e632a6cd1d349155c1d7f13a65be873b38f43ef02961804a1bba8d817fa649a7" + "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869" ], - "version": "==2.6.0" + "version": "==2.6.3" }, "markdown": { "hashes": [ - "sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa", - "sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c" + "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49", + "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c" ], - "version": "==3.0.1" + "version": "==3.3.4" }, "markupsafe": { "hashes": [ - "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", - "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", - "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", - "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", - "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", - "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", - "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", - "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", - "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", - "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", - "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", - "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", - "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", - "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", - "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", - "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", - "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", - "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", - "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", - "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", - "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", - "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", - "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", - "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", - "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", - "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", - "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", - "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" - ], - "version": "==1.1.0" + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", + "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f", + "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014", + "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85", + "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850", + "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1", + "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5", + "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c", + "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", + "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" + ], + "version": "==1.1.1" }, "mkdocs": { "hashes": [ "sha256:17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939", "sha256:8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a" ], + "index": "pypi", "version": "==1.0.4" }, "mkdocs-codeinclude-plugin": { - "editable": true, - "git": "https://github.com/rnorth/mkdocs-codeinclude-plugin", - "ref": "99417fdad0634ccfeea7eaa8ba648a08c7513e7c" + "hashes": [ + "sha256:5d74bd4c1be8e64d71137c1ef1d27a0f9822d3d9ecb2af658d2af7664568a923", + "sha256:a94be142e27ef4a70d8ecc702c21d9596304e06d382d86b39a10ffe8b0375887" + ], + "index": "pypi", + "version": "==0.2.0" }, "mkdocs-markdownextradata-plugin": { "hashes": [ @@ -106,52 +142,120 @@ }, "pygments": { "hashes": [ - "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", - "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d" + "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94", + "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8" ], - "version": "==2.3.1" + "version": "==2.8.1" }, "pymdown-extensions": { "hashes": [ - "sha256:25b0a7967fa697b5035e23340a48594e3e93acb10b06d74574218ace3347d1df", - "sha256:6cf0cf36b5a03b291ace22dc2f320f4789ce56fbdb6635a3be5fadbf5d7694dd" + "sha256:478b2c04513fbb2db61688d5f6e9030a92fb9be14f1f383535c43f7be9dff95b", + "sha256:632371fa3bf1b21a0e3f4063010da59b41db049f261f4c0b0872069a9b6d1735" ], - "version": "==6.0" + "version": "==8.1.1" }, "pyyaml": { "hashes": [ - "sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", - "sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", - "sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", - "sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", - "sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", - "sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", - "sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", - "sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", - "sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", - "sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", - "sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531" + "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", + "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", + "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", + "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", + "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", + "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", + "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", + "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", + "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", + "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", + "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", + "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", + "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347", + "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", + "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541", + "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", + "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", + "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc", + "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", + "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa", + "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", + "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122", + "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", + "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", + "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", + "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc", + "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247", + "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", + "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0" ], - "version": "==3.13" + "version": "==5.4.1" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "version": "==1.12.0" + "version": "==1.15.0" }, "tornado": { "hashes": [ - "sha256:0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d", - "sha256:4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409", - "sha256:732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f", - "sha256:8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f", - "sha256:8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5", - "sha256:d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb", - "sha256:e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444" + "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb", + "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c", + "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288", + "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95", + "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558", + "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe", + "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791", + "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d", + "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326", + "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b", + "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4", + "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c", + "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910", + "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5", + "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c", + "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0", + "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675", + "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd", + "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f", + "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c", + "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea", + "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6", + "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05", + "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd", + "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575", + "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a", + "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37", + "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795", + "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f", + "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32", + "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c", + "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01", + "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4", + "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2", + "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921", + "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085", + "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df", + "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102", + "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5", + "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", + "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" + ], + "version": "==6.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", + "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", + "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" + ], + "markers": "python_version < '3.8'", + "version": "==3.7.4.3" + }, + "zipp": { + "hashes": [ + "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76", + "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098" ], - "version": "==5.1.1" + "version": "==3.4.1" } }, "develop": {} From a2fa424e2f2bf6053a037925b0c1a87cb1b090ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Mar 2021 09:42:17 +0000 Subject: [PATCH 1187/4969] Bump testcontainers from 1.15.1 to 1.15.2 in /core (#3795) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 7613ed58ccc..3b30a64c267 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -165,7 +165,7 @@ configurations.all { } dependencies { - baseline 'org.testcontainers:testcontainers:1.15.1', { + baseline 'org.testcontainers:testcontainers:1.15.2', { exclude group: "*", module: "*" } From 8965712f239ae3c449cec579264af5e79265f314 Mon Sep 17 00:00:00 2001 From: Kevin Robayna Date: Sat, 20 Mar 2021 09:53:18 +0000 Subject: [PATCH 1188/4969] Add example of mapping from file in system (#3808) Co-authored-by: Richard North --- docs/features/files.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/features/files.md b/docs/features/files.md index a74b1add134..7e5f07b3059 100644 --- a/docs/features/files.md +++ b/docs/features/files.md @@ -1,5 +1,14 @@ # Files and volumes +## File mapping + +It is possible to map a file or directory from your FileSystem into the container as a volume using `withFileSystemBind`: +```java +String pathToFile = System.getProperty("user.home") + "/.aws"; +new GenericContainer(...) + .withFileSystemBind(pathToFile, "/home/user/.aws", BindMode.READ_ONLY) +``` + ## Volume mapping It is possible to map a file or directory **on the classpath** into the container as a volume using `withClasspathResourceMapping`: From eeb7eb2c608e6eeb27c602a6061c535add8247e3 Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Wed, 31 Mar 2021 10:47:32 +0200 Subject: [PATCH 1189/4969] Add TrinoContainer (#3668) --- docs/modules/databases/jdbc.md | 4 +- docs/modules/databases/presto.md | 2 +- docs/modules/databases/trino.md | 88 ++++++++++++++++++ mkdocs.yml | 1 + .../containers/PrestoContainer.java | 4 + modules/trino/build.gradle | 9 ++ .../containers/TrinoContainer.java | 89 +++++++++++++++++++ .../containers/TrinoContainerProvider.java | 23 +++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../org/testcontainers/TrinoTestImages.java | 8 ++ .../containers/TrinoContainerTest.java | 64 +++++++++++++ .../jdbc/trino/TrinoJDBCDriverTest.java | 21 +++++ modules/trino/src/test/resources/initial.sql | 2 + 13 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 docs/modules/databases/trino.md create mode 100644 modules/trino/build.gradle create mode 100644 modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java create mode 100644 modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java create mode 100644 modules/trino/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/trino/src/test/java/org/testcontainers/TrinoTestImages.java create mode 100644 modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java create mode 100644 modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java create mode 100644 modules/trino/src/test/resources/initial.sql diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 6853cf44c5c..fec250ffdd9 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -39,9 +39,9 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database `jdbc:tc:postgis:9.6-2.5:///databasename` -#### Using Presto +#### Using Trino -`jdbc:tc:presto:344://localhost/memory/default` +`jdbc:tc:trino:352://localhost/memory/default` ### Using a classpath init script diff --git a/docs/modules/databases/presto.md b/docs/modules/databases/presto.md index 52776d06daf..8e8a2672355 100644 --- a/docs/modules/databases/presto.md +++ b/docs/modules/databases/presto.md @@ -1,7 +1,7 @@ # Presto Module !!! note - This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + This module is deprecated, use Trino module. See [Database containers](./index.md) for documentation and usage that is common to all database container types. diff --git a/docs/modules/databases/trino.md b/docs/modules/databases/trino.md new file mode 100644 index 00000000000..4cd26978af1 --- /dev/null +++ b/docs/modules/databases/trino.md @@ -0,0 +1,88 @@ +# Trino Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +See [Database containers](./index.md) for documentation and usage that is common to all database container types. + +## Usage example + +Running Trino as a stand-in for in a test: + +```java +public class SomeTest { + + @Rule + public TrinoContainer trino = new TrinoContainer(); + + @Test + public void someTestMethod() { + String url = trino.getJdbcUrl(); + + ... create a connection and run test as normal +``` + +Trino comes with several catalogs preconfigured. Most useful ones for testing are + +* `tpch` catalog using the [Trino TPCH Connector](https://trino.io/docs/current/connector/tpch.html). + This is a read-only catalog that defines standard TPCH schema, so is available for querying without a need + to create any tables. +* `memory` catalog using the [Trino Memory Connector](https://trino.io/docs/current/connector/memory.html). + This catalog can be used for creating schemas and tables and does not require any storage, as everything + is stored fully in-memory. + +Example test using the `tpch` and `memory` catalogs: + +```java +public class SomeTest { + @Rule + public TrinoContainer trino = new TrinoContainer(); + + @Test + public void queryMemoryAndTpchConnectors() throws SQLException { + try (Connection connection = trino.createConnection(); + Statement statement = connection.createStatement()) { + // Prepare data + statement.execute("CREATE TABLE memory.default.table_with_array AS SELECT 1 id, ARRAY[1, 42, 2, 42, 4, 42] my_array"); + + // Query Trino using newly created table and a builtin connector + try (ResultSet resultSet = statement.executeQuery("" + + "SELECT nationkey, element " + + "FROM tpch.tiny.nation " + + "JOIN memory.default.table_with_array twa ON nationkey = twa.id " + + "LEFT JOIN UNNEST(my_array) a(element) ON true " + + "ORDER BY element OFFSET 1 FETCH NEXT 3 ROWS WITH TIES ")) { + List actualElements = new ArrayList<>(); + while (resultSet.next()) { + actualElements.add(resultSet.getInt("element")); + } + Assert.assertEquals(Arrays.asList(2, 4, 42, 42, 42), actualElements); + } + } + } +} +``` + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testCompile "org.testcontainers:trino:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + trino + {{latest_version}} + test + +``` + +!!! hint + Adding this Testcontainers library JAR will not automatically add the Trino JDBC driver JAR to your project. + You should ensure that your project has the Trino JDBC driver as a dependency, if you plan on using it. + Refer to [Trino project download page](https://trino.io/download.html) for instructions. + + diff --git a/mkdocs.yml b/mkdocs.yml index b0608746825..15cc915f5b2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -60,6 +60,7 @@ nav: - modules/databases/orientdb.md - modules/databases/postgres.md - modules/databases/presto.md + - modules/databases/trino.md - modules/docker_compose.md - modules/elasticsearch.md - modules/gcloud.md diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index 1d9e02114ac..30d77c1a469 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -14,6 +14,10 @@ import static java.lang.String.format; import static java.time.temporal.ChronoUnit.SECONDS; +/** + * @deprecated Use {@code TrinoContainer} instead. + */ +@Deprecated public class PrestoContainer> extends JdbcDatabaseContainer { public static final String NAME = "presto"; private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("ghcr.io/trinodb/presto"); diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle new file mode 100644 index 00000000000..d726cbc8e76 --- /dev/null +++ b/modules/trino/build.gradle @@ -0,0 +1,9 @@ +description = "Testcontainers :: JDBC :: Trino" + +dependencies { + compile project(':jdbc') + + testCompile project(':jdbc-test') + testCompile 'io.trino:trino-jdbc:352' + compileOnly 'org.jetbrains:annotations:20.0.0' +} diff --git a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java new file mode 100644 index 00000000000..825340459f3 --- /dev/null +++ b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java @@ -0,0 +1,89 @@ +package org.testcontainers.containers; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; +import org.testcontainers.utility.DockerImageName; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Strings.nullToEmpty; +import static java.lang.String.format; + +public class TrinoContainer extends JdbcDatabaseContainer { + static final String NAME = "trino"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("trinodb/trino"); + static final String IMAGE = "trinodb/trino"; + @VisibleForTesting + static final String DEFAULT_TAG = "352"; + + private static final int TRINO_PORT = 8080; + + private String username = "test"; + private String catalog = null; + + public TrinoContainer(final String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public TrinoContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + addExposedPort(TRINO_PORT); + } + + @NotNull + @Override + protected Set getLivenessCheckPorts() { + return new HashSet<>(getMappedPort(TRINO_PORT)); + } + + @Override + public String getDriverClassName() { + return "io.trino.jdbc.TrinoDriver"; + } + + @Override + public String getJdbcUrl() { + return format("jdbc:trino://%s:%s/%s", getHost(), getMappedPort(TRINO_PORT), nullToEmpty(catalog)); + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return ""; + } + + @Override + public String getDatabaseName() { + return catalog; + } + + @Override + public String getTestQueryString() { + return "SELECT count(*) FROM tpch.tiny.nation"; + } + + @Override + public TrinoContainer withUsername(final String username) { + this.username = username; + return this; + } + + @Override + public TrinoContainer withDatabaseName(String dbName) { + this.catalog = dbName; + return this; + } + + public Connection createConnection() throws SQLException, NoDriverFoundException { + return createConnection(""); + } +} diff --git a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java new file mode 100644 index 00000000000..233fc1b9b07 --- /dev/null +++ b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java @@ -0,0 +1,23 @@ +package org.testcontainers.containers; + +import org.testcontainers.utility.DockerImageName; + +/** + * Factory for Trino containers. + */ +public class TrinoContainerProvider extends JdbcDatabaseContainerProvider { + @Override + public boolean supports(String databaseType) { + return databaseType.equals(TrinoContainer.NAME); + } + + @Override + public JdbcDatabaseContainer newInstance() { + return newInstance(TrinoContainer.DEFAULT_TAG); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new TrinoContainer(DockerImageName.parse(TrinoContainer.IMAGE).withTag(tag)); + } +} diff --git a/modules/trino/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/trino/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..637633627e5 --- /dev/null +++ b/modules/trino/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.containers.TrinoContainerProvider diff --git a/modules/trino/src/test/java/org/testcontainers/TrinoTestImages.java b/modules/trino/src/test/java/org/testcontainers/TrinoTestImages.java new file mode 100644 index 00000000000..0ac56e54129 --- /dev/null +++ b/modules/trino/src/test/java/org/testcontainers/TrinoTestImages.java @@ -0,0 +1,8 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface TrinoTestImages { + DockerImageName TRINO_TEST_IMAGE = DockerImageName.parse("trinodb/trino:352"); + DockerImageName TRINO_PREVIOUS_VERSION_TEST_IMAGE = DockerImageName.parse("trinodb/trino:351"); +} diff --git a/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java new file mode 100644 index 00000000000..d7f8014ca9a --- /dev/null +++ b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java @@ -0,0 +1,64 @@ +package org.testcontainers.containers; + +import org.junit.Assert; +import org.junit.Test; +import org.testcontainers.TrinoTestImages; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static java.lang.Integer.parseInt; +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class TrinoContainerTest { + + @Test + public void testSimple() throws Exception { + try (TrinoContainer trino = new TrinoContainer(TrinoTestImages.TRINO_TEST_IMAGE)) { + trino.start(); + try (Connection connection = trino.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + assertTrue("No result", resultSet.next()); + assertEquals("Trino version", TrinoContainer.DEFAULT_TAG, resultSet.getString("node_version")); + } + } + } + + @Test + public void testSpecificVersion() throws Exception { + try (TrinoContainer trino = new TrinoContainer(TrinoTestImages.TRINO_PREVIOUS_VERSION_TEST_IMAGE)) { + trino.start(); + try (Connection connection = trino.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + assertTrue("No result", resultSet.next()); + assertEquals("Trino version", TrinoTestImages.TRINO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), resultSet.getString("node_version")); + } + } + } + + @Test + public void testInitScript() throws Exception { + try (TrinoContainer trino = new TrinoContainer(TrinoTestImages.TRINO_TEST_IMAGE)) { + trino.withInitScript("initial.sql"); + trino.start(); + try (Connection connection = trino.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table")) { + assertTrue("No result", resultSet.next()); + assertEquals("Value", 12345678909324L, resultSet.getObject("a")); + assertFalse("Too many result", resultSet.next()); + } + } + } +} diff --git a/modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java b/modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java new file mode 100644 index 00000000000..8f06aef7278 --- /dev/null +++ b/modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.jdbc.trino; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class TrinoJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:trino:352://hostname/", EnumSet.of(Options.PmdKnownBroken)}, + }); + } +} diff --git a/modules/trino/src/test/resources/initial.sql b/modules/trino/src/test/resources/initial.sql new file mode 100644 index 00000000000..1a3ecdab4f9 --- /dev/null +++ b/modules/trino/src/test/resources/initial.sql @@ -0,0 +1,2 @@ +CREATE TABLE memory.default.test_table(a bigint); +INSERT INTO memory.default.test_table(a) VALUES (12345678909324); From 8929dd72947ac102b78e8c51b19821299c2bc01e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Apr 2021 18:26:18 +0100 Subject: [PATCH 1190/4969] Bump release-drafter/release-drafter from e5ccf147077e46b0225a80bbe314d795d77bb7a2 to 5.15.0 (#3915) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 28f14cb0ad3..e19e08b9f32 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -9,6 +9,6 @@ jobs: update_release_draft: runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@e5ccf147077e46b0225a80bbe314d795d77bb7a2 # v5.14.0 + - uses: release-drafter/release-drafter@fe52e97d262833ae07d05efaf1a239df3f1b5cd4 # v5.15.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 736459168892245bd16727a6a97fd19d6ad846c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Apr 2021 18:27:15 +0100 Subject: [PATCH 1191/4969] Bump org.jetbrains.kotlin.jvm from 1.4.21-2 to 1.4.32 in /examples (#3947) Bumps org.jetbrains.kotlin.jvm from 1.4.21-2 to 1.4.32. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 4675f907235..8ffa1b46d2a 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.4.1" - id("org.jetbrains.kotlin.jvm") version "1.4.21-2" + id("org.jetbrains.kotlin.jvm") version "1.4.32" id("org.jetbrains.kotlin.plugin.spring") version "1.4.21-2" } From 187c0cce8896dbc3ca683f787611d8fd11039a45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Apr 2021 18:27:47 +0100 Subject: [PATCH 1192/4969] Bump elasticsearch-rest-client from 7.10.1 to 7.12.0 in /modules/elasticsearch (#3945) Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.10.1 to 7.12.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.10.1...v7.12.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index b4a64a405b7..cb553c54654 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,6 +2,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.10.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.12.0" testCompile "org.elasticsearch.client:transport:7.10.1" } From 79a1a0650eabfa7535607b81a752aae6739b2a5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Apr 2021 18:28:33 +0100 Subject: [PATCH 1193/4969] Bump aws-java-sdk-sqs from 1.11.930 to 1.11.986 in /modules/localstack (#3942) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.930 to 1.11.986. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.930...1.11.986) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index fdffc649a72..8a4df52b54d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.930' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.930' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.986' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.15.56' } From bc48eebeefb344b0878637c021b8a1998ff4d677 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Apr 2021 18:29:12 +0100 Subject: [PATCH 1194/4969] Bump pulsar-client from 2.7.0 to 2.7.1 in /modules/pulsar (#3913) Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.7.0 to 2.7.1. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.7.0...v2.7.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index b574519a939..e189e7006eb 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.1' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.18.1' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.0' } From b3cf0624c8f251af0e5361d3a92d155d3563b372 Mon Sep 17 00:00:00 2001 From: Patrik Mihalcin <5480557+pmihalcin@users.noreply.github.com> Date: Wed, 7 Apr 2021 16:44:24 +0200 Subject: [PATCH 1195/4969] Add information for TLS disabled mode in Gitlab (#2466) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Docker daemon supports connection over TLS and it’s done by default for Docker 19.03.1 or higher. We need to instruct docker to not start over TLS with DOCKER_TLS_CERTDIR variable Co-authored-by: Richard North --- .../continuous_integration/gitlab_ci.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md index 0cb5017bb87..e6daf84401f 100644 --- a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md +++ b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md @@ -1,7 +1,7 @@ # GitLab CI In order to use Testcontainers in a Gitlab CI pipeline, you need to run the job as a Docker container (see [Patterns for running inside Docker](dind_patterns.md)). -So edit your `.gitlab-ci.yml` to include the [Docker-In-Docker service](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-executor) (`docker:dind`) and set the `DOCKER_HOST` variable to `tcp://docker:2375`. +So edit your `.gitlab-ci.yml` to include the [Docker-In-Docker service](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-workflow-with-docker-executor) (`docker:dind`) and set the `DOCKER_HOST` variable to `tcp://docker:2375` and `DOCKER_TLS_CERTDIR` to empty string. Here is a sample `.gitlab-ci.yml` that executes test with gradle: @@ -13,6 +13,8 @@ services: variables: # Instruct Testcontainers to use the daemon of DinD. DOCKER_HOST: "tcp://docker:2375" + # Instruct Docker not to start over TLS. + DOCKER_TLS_CERTDIR: "" # Improve performance with overlayfs. DOCKER_DRIVER: overlay2 From 8533e9bd190d77c6df2bf7837e9ffb1786e83da8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 11 Apr 2021 15:51:57 +0100 Subject: [PATCH 1196/4969] Bump s3 from 2.15.56 to 2.16.34 in /modules/localstack (#3963) Bumps s3 from 2.15.56 to 2.16.34. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8a4df52b54d..c007b2c649e 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,5 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.986' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.15.56' + testCompile 'software.amazon.awssdk:s3:2.16.34' } From 1e6deb167491c0f62a21dac403ea13ee07d92776 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 11 Apr 2021 19:54:20 +0100 Subject: [PATCH 1197/4969] Filter mapped ports when port numbers are not specified (replaces #3948) (#3979) Co-authored-by: Ilia Rodionov --- .../containers/ContainerState.java | 3 ++ .../containers/ContainerStateTest.java | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 core/src/test/java/org/testcontainers/containers/ContainerStateTest.java diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index ad96aeb808c..da87dbdf724 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -12,6 +12,7 @@ import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; +import org.apache.commons.lang.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; @@ -181,7 +182,9 @@ default List getBoundPortNumbers() { .map(PortBinding::getBinding) .map(Ports.Binding::getHostPortSpec) .filter(Objects::nonNull) + .filter(NumberUtils::isNumber) .map(Integer::valueOf) + .filter(port -> port > 0) .collect(Collectors.toList()); } diff --git a/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java new file mode 100644 index 00000000000..52296678fd4 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java @@ -0,0 +1,49 @@ +package org.testcontainers.containers; + +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(Parameterized.class) +public class ContainerStateTest { + + @Parameterized.Parameters(name = "{0} ({1} -> {2})") + public static Object[][] params() { + return new Object[][]{ + new Object[]{"regular mapping", "80:8080/tcp", singletonList(80),}, + new Object[]{"regular mapping with host", "127.0.0.1:80:8080/tcp", singletonList(80),}, + new Object[]{"zero port without host", ":0:8080/tcp", emptyList(),}, + new Object[]{"missing port with host", "0.0.0.0:0:8080/tcp", emptyList(),}, + new Object[]{"zero port (synthetic case)", "0:8080/tcp", emptyList(),}, + new Object[]{"missing port", ":8080/tcp", emptyList(), + } + }; + } + + @Parameterized.Parameter(0) + public String name; + @Parameterized.Parameter(1) + public String testSet; + @Parameterized.Parameter(2) + public List expectedResult; + + @Test + public void test() { + ContainerState containerState = mock(ContainerState.class); + doCallRealMethod().when(containerState).getBoundPortNumbers(); + + when(containerState.getPortBindings()).thenReturn(singletonList(testSet)); + + List result = containerState.getBoundPortNumbers(); + Assertions.assertThat(result).hasSameElementsAs(expectedResult); + } +} From 9183f8f940e12045e8790c6eb6693cf8c62bd779 Mon Sep 17 00:00:00 2001 From: Mark Rotteveel Date: Sun, 11 Apr 2021 20:57:41 +0200 Subject: [PATCH 1198/4969] Prevent ContainerDatabaseDriver from throwing NPEs when on classpath but not initialized (#3976) When ContainerDatabaseDriver hasn't been used yet to connect, the delegate is null. This causes various JDBC metadata methods of the driver to fail with a NullPointerException. Prevent this by providing reasonable defaults. --- .../jdbc/ContainerDatabaseDriver.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java index c5413fe7efb..c1b4fc29067 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java @@ -230,27 +230,30 @@ private void runInitFunctionIfRequired(final ConnectionUrl connectionUrl, Connec @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { - return delegate.getPropertyInfo(url, info); + return delegate != null ? delegate.getPropertyInfo(url, info) : new DriverPropertyInfo[0]; } @Override public int getMajorVersion() { - return delegate.getMajorVersion(); + return delegate != null ? delegate.getMajorVersion() : 1; } @Override public int getMinorVersion() { - return delegate.getMinorVersion(); + return delegate != null ? delegate.getMinorVersion() : 0; } @Override public boolean jdbcCompliant() { - return delegate.jdbcCompliant(); + return delegate != null && delegate.jdbcCompliant(); } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { - return delegate.getParentLogger(); + if (delegate != null) { + return delegate.getParentLogger(); + } + throw new SQLFeatureNotSupportedException("getParentLogger not supported"); } /** From f3ffed66683034e6cde10d62978eb8c807736e06 Mon Sep 17 00:00:00 2001 From: Ivan Stanislavciuc <2766429+seveneves@users.noreply.github.com> Date: Sun, 11 Apr 2021 21:00:52 +0200 Subject: [PATCH 1199/4969] Fix problem of starting up mysql 5.7.33 version when user is root (#3953) Co-authored-by: Richard North Co-authored-by: Ivan Stanislavciuc --- .../containers/MySQLContainer.java | 10 ++-- .../containers/MySQLRootAccountTest.java | 53 +++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 1dc235e6536..a126a579489 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -62,10 +62,12 @@ protected Set getLivenessCheckPorts() { @Override protected void configure() { optionallyMapResourceParameterAsVolume(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, "/etc/mysql/conf.d", - "mysql-default-conf"); + "mysql-default-conf"); addEnv("MYSQL_DATABASE", databaseName); - addEnv("MYSQL_USER", username); + if (!MYSQL_ROOT_USER.equalsIgnoreCase(username)) { + addEnv("MYSQL_USER", username); + } if (password != null && !password.isEmpty()) { addEnv("MYSQL_PASSWORD", password); addEnv("MYSQL_ROOT_PASSWORD", password); @@ -98,12 +100,12 @@ public String getJdbcUrl() { protected String constructUrlForConnection(String queryString) { String url = super.constructUrlForConnection(queryString); - if (! url.contains("useSSL=")) { + if (!url.contains("useSSL=")) { String separator = url.contains("?") ? "&" : "?"; url = url + separator + "useSSL=false"; } - if (! url.contains("allowPublicKeyRetrieval=")) { + if (!url.contains("allowPublicKeyRetrieval=")) { url = url + "&allowPublicKeyRetrieval=true"; } diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java new file mode 100644 index 00000000000..c437acac013 --- /dev/null +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java @@ -0,0 +1,53 @@ +package org.testcontainers.containers; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.containers.output.Slf4jLogConsumer; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +@Slf4j +@RunWith(Parameterized.class) +public class MySQLRootAccountTest { + + @Parameterized.Parameters(name = "{0}") + public static String[] params() { + return new String[]{ + "mysql:8", + "mysql:5" + }; + } + + @Parameterized.Parameter() + public String image; + + @Test + public void testRootAccountUsageWithDefaultPassword() throws SQLException { + testWithDB(new MySQLContainer<>(image).withUsername("root")); + } + + @Test + public void testRootAccountUsageWithEmptyPassword() throws SQLException { + testWithDB(new MySQLContainer<>(image).withUsername("root").withPassword("")); + } + + @Test + public void testRootAccountUsageWithCustomPassword() throws SQLException { + testWithDB(new MySQLContainer<>(image).withUsername("root").withPassword("not-default")); + } + + private void testWithDB(MySQLContainer db) throws SQLException { + try { + db.withLogConsumer(new Slf4jLogConsumer(log)).start(); + Connection connection = DriverManager.getConnection(db.getJdbcUrl(), db.getUsername(), db.getPassword()); + connection.createStatement().execute("SELECT 1"); + connection.createStatement().execute("set sql_log_bin=0"); // requires root + } finally { + db.close(); + } + } +} From 3c70d0895851193ca5f3b1ec1c4b095871ed4f62 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 11 Apr 2021 21:06:40 +0200 Subject: [PATCH 1200/4969] Update docs to clarify shading approach (#3974) Make the docs section about our shading approach and motivation more up-to-date and less confusing (no JAX-RS/Jersey anymore, mention docker-java-api, etc) --- docs/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 013c18d0700..176ddd16974 100644 --- a/docs/index.md +++ b/docs/index.md @@ -86,8 +86,9 @@ testImplementation('org.testcontainers:mysql') //no version specified [JitPack](jitpack_dependencies.md) builds are available for pre-release versions. !!! warning "Shaded dependencies" - Testcontainers uses the docker-java client library, which in turn depends on JAX-RS, Jersey and Jackson libraries. - These libraries in particular seem to be especially prone to conflicts with test code/application under test code. + Testcontainers depends on other libraries (like docker-java) for it to work. + Some of them (JUnit, docker-java-{api,transport} and its transitive dependencies, JNA, visible-assertions and others) are part of our public API. + But there are also "private", implementation detail dependencies (e.g. docker-java-core, Guava, OkHttp, etc etc) that are not exposed to public API but prone to conflicts with test code/application under test code. As such, **these libraries are 'shaded' into the core testcontainers JAR** and relocated under `org.testcontainers.shaded` to prevent class conflicts. ## Sponsors From 33477107ecd5610eaa25cf8c9cef449f07ac321a Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 12 Apr 2021 07:39:28 +0100 Subject: [PATCH 1201/4969] Pin localstack to 0.12.8 (#3981) --- .../containers/localstack/LegacyModeTest.java | 117 ++++++++---------- .../localstack/LocalstackTestImages.java | 6 +- 2 files changed, 59 insertions(+), 64 deletions(-) diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java index f50846b091f..b8f2ec1aae0 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java @@ -1,30 +1,31 @@ package org.testcontainers.containers.localstack; +import com.github.dockerjava.api.DockerClient; import lombok.AllArgsConstructor; -import lombok.SneakyThrows; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.utility.DockerImageName; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.Arrays; -import java.util.function.Consumer; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; +import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_10_IMAGE; +import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_11_IMAGE; +import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_12_IMAGE; +import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_7_IMAGE; import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_IMAGE; @RunWith(Enclosed.class) public class LegacyModeTest { + private static DockerImageName LOCALSTACK_CUSTOM_TAG = LOCALSTACK_IMAGE.withTag("custom"); @RunWith(Parameterized.class) @AllArgsConstructor @@ -35,10 +36,9 @@ public static class Off { @Parameterized.Parameters(name = "{0}") public static Iterable constructors() { return Arrays.asList(new Object[][]{ - {"default constructor", new LocalStackContainer(LOCALSTACK_IMAGE)}, - {"latest", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("latest"))}, - {"0.11.1", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.11.1"))}, - {"0.7.0 with legacy = off", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.7.0"), false)} + {"0.12", new LocalStackContainer(LOCALSTACK_0_12_IMAGE)}, + {"0.11", new LocalStackContainer(LOCALSTACK_0_11_IMAGE)}, + {"0.7 with legacy = off", new LocalStackContainer(LOCALSTACK_0_7_IMAGE, false)} }); } @@ -47,20 +47,19 @@ public void samePortIsExposedForAllServices() { localstack.withServices(S3, SQS); localstack.start(); - assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); - assertEquals( - "Endpoint overrides are different", - localstack.getEndpointOverride(S3).toString(), - localstack.getEndpointOverride(SQS).toString()); - assertEquals( - "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); - } - - @After - public void cleanup() { - if (localstack != null) localstack.stop(); + try { + assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); + assertEquals( + "Endpoint overrides are different", + localstack.getEndpointOverride(S3).toString(), + localstack.getEndpointOverride(SQS).toString()); + assertEquals( + "Endpoint configuration have different endpoints", + localstack.getEndpointConfiguration(S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + } finally { + localstack.stop(); + } } } @@ -72,16 +71,28 @@ public static class On { @BeforeClass public static void createCustomTag() { - run("docker pull localstack/localstack:latest"); - run("docker tag localstack/localstack:latest localstack/localstack:custom"); + DockerClient dockerClient = DockerClientFactory.instance().client(); + DockerClientFactory + .instance() + .checkAndPullImage( + dockerClient, + LOCALSTACK_0_12_IMAGE.asCanonicalNameString() + ); + dockerClient + .tagImageCmd( + LOCALSTACK_0_12_IMAGE.asCanonicalNameString(), + LOCALSTACK_CUSTOM_TAG.getRepository(), + LOCALSTACK_CUSTOM_TAG.getVersionPart() + ) + .exec(); } @Parameterized.Parameters(name = "{0}") public static Iterable constructors() { return Arrays.asList(new Object[][]{ - {"0.10.7", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.10.7"))}, - {"custom", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("custom"))}, - {"0.11.1 with legacy = on", new LocalStackContainer(LOCALSTACK_IMAGE.withTag("0.11.1"), true)} + {"0.10", new LocalStackContainer(LOCALSTACK_0_10_IMAGE)}, + {"custom", new LocalStackContainer(LOCALSTACK_CUSTOM_TAG)}, + {"0.11 with legacy = on", new LocalStackContainer(LOCALSTACK_0_11_IMAGE, true)} }); } @@ -90,39 +101,19 @@ public void differentPortsAreExposed() { localstack.withServices(S3, SQS); localstack.start(); - assertTrue("Multiple ports are exposed", localstack.getExposedPorts().size() > 1); - assertNotEquals( - "Endpoint overrides are different", - localstack.getEndpointOverride(S3).toString(), - localstack.getEndpointOverride(SQS).toString()); - assertNotEquals( - "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); - } - - @After - public void cleanup() { - if (localstack != null) localstack.stop(); - } - } - - @SneakyThrows - private static void run(String command) { - Process process = Runtime.getRuntime().exec(command); - join(process.getInputStream(), System.out::println); - join(process.getErrorStream(), System.err::println); - process.waitFor(); - if (process.exitValue() != 0) - throw new RuntimeException("Failed to execute " + command); - } - - private static void join(InputStream stream, Consumer logger) throws IOException { - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream)); - String line; - while ((line = bufferedReader.readLine()) != null) { - logger.accept(line); + try { + assertTrue("Multiple ports are exposed", localstack.getExposedPorts().size() > 1); + assertNotEquals( + "Endpoint overrides are different", + localstack.getEndpointOverride(S3).toString(), + localstack.getEndpointOverride(SQS).toString()); + assertNotEquals( + "Endpoint configuration have different endpoints", + localstack.getEndpointConfiguration(S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + } finally { + localstack.stop(); + } } } - } diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java index 0dd0ca9b9ac..491394bea8a 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java @@ -3,6 +3,10 @@ import org.testcontainers.utility.DockerImageName; public interface LocalstackTestImages { - DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.11.3"); + DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.12.8"); + DockerImageName LOCALSTACK_0_7_IMAGE = LOCALSTACK_IMAGE.withTag("0.7.0"); + DockerImageName LOCALSTACK_0_10_IMAGE = LOCALSTACK_IMAGE.withTag("0.10.7"); + DockerImageName LOCALSTACK_0_11_IMAGE = LOCALSTACK_IMAGE.withTag("0.11.3"); + DockerImageName LOCALSTACK_0_12_IMAGE = LOCALSTACK_IMAGE.withTag("0.12.8"); DockerImageName AWS_CLI_IMAGE = DockerImageName.parse("atlassian/pipelines-awscli:1.16.302"); } From 1cd04763de83b4fa523182bae55d8927d99990f8 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 12 Apr 2021 08:44:27 +0200 Subject: [PATCH 1202/4969] Update docker-java to 3.2.8 (#3980) --- core/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 3b30a64c267..463116dc5ee 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -180,9 +180,9 @@ dependencies { compile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compile "com.github.docker-java:docker-java-api:3.2.7" + compile "com.github.docker-java:docker-java-api:3.2.8" - shaded ('com.github.docker-java:docker-java-core:3.2.7') { + shaded ('com.github.docker-java:docker-java-core:3.2.8') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') @@ -191,13 +191,13 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.7') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.8') { exclude(group: 'com.github.docker-java', module: 'docker-java-core') exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } - compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.7' + compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.8' shaded "org.yaml:snakeyaml:1.27" From 55838a9248a55ad628e6159fef5e4c0e6beed981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristopher=20Pinz=C3=B3n?= Date: Mon, 12 Apr 2021 01:45:32 -0500 Subject: [PATCH 1203/4969] ec2 added to localstack services enum (#3955) --- .../containers/localstack/LocalStackContainer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index b8416afb1ed..4863de6e62d 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -306,6 +306,7 @@ public String getRegion() { @FieldDefaults(makeFinal = true) public enum Service { API_GATEWAY("apigateway", 4567), + EC2("ec2", 4597), KINESIS("kinesis", 4568), DYNAMODB("dynamodb", 4569), DYNAMODB_STREAMS("dynamodbstreams", 4570), From dabc99c73eb9832ed2971c42412dd56bbd4d15be Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 12 Apr 2021 13:36:29 +0200 Subject: [PATCH 1204/4969] Make it possible to provide custom LocalStack services (#3995) --- .../localstack/LocalStackContainer.java | 40 +++++++++++++++---- .../localstack/LocalstackContainerTest.java | 2 +- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 4863de6e62d..fe3ea6ab34f 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -37,7 +37,7 @@ public class LocalStackContainer extends GenericContainer { static final int PORT = 4566; private static final String HOSTNAME_EXTERNAL_ENV_VAR = "HOSTNAME_EXTERNAL"; - private final List services = new ArrayList<>(); + private final List services = new ArrayList<>(); private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("localstack/localstack"); private static final String DEFAULT_TAG = "0.11.2"; @@ -119,7 +119,7 @@ protected void configure() { Preconditions.check("services list must not be empty", !services.isEmpty()); - withEnv("SERVICES", services.stream().map(Service::getLocalStackName).collect(Collectors.joining(","))); + withEnv("SERVICES", services.stream().map(EnabledService::getName).collect(Collectors.joining(","))); String hostnameExternalReason; if (getEnvMap().containsKey(HOSTNAME_EXTERNAL_ENV_VAR)) { @@ -144,12 +144,17 @@ private void exposePorts() { .forEach(this::addExposedPort); } + public LocalStackContainer withServices(Service... services) { + this.services.addAll(Arrays.asList(services)); + return self(); + } + /** * Declare a set of simulated AWS services that should be launched by this container. * @param services one or more service names * @return this container object */ - public LocalStackContainer withServices(Service... services) { + public LocalStackContainer withServices(EnabledService... services) { this.services.addAll(Arrays.asList(services)); return self(); } @@ -184,6 +189,10 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service s return new AwsClientBuilder.EndpointConfiguration(getEndpointOverride(service).toString(), getRegion()); } + public URI getEndpointOverride(Service service) { + return getEndpointOverride((EnabledService) service); + } + /** * Provides an endpoint override that is preconfigured to communicate with a given simulated service. * The provided endpoint override should be set in the AWS Java SDK v2 when building a client, e.g.: @@ -203,7 +212,7 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service s * @param service the service that is to be accessed * @return an {@link URI} endpoint override */ - public URI getEndpointOverride(Service service) { + public URI getEndpointOverride(EnabledService service) { try { final String address = getHost(); String ipAddress = address; @@ -218,8 +227,8 @@ public URI getEndpointOverride(Service service) { } } - private int getServicePort(Service service) { - return legacyMode ? service.port : PORT; + private int getServicePort(EnabledService service) { + return legacyMode ? service.getPort() : PORT; } /** @@ -301,10 +310,22 @@ public String getRegion() { return "us-east-1"; } + public interface EnabledService { + static EnabledService named(String name) { + return () -> name; + } + + String getName(); + + default int getPort() { + return PORT; + } + } + @RequiredArgsConstructor @Getter @FieldDefaults(makeFinal = true) - public enum Service { + public enum Service implements EnabledService { API_GATEWAY("apigateway", 4567), EC2("ec2", 4597), KINESIS("kinesis", 4568), @@ -335,6 +356,11 @@ public enum Service { int port; + @Override + public String getName() { + return localStackName; + } + @Deprecated /* Since version 0.11, LocalStack exposes all services on a single (4566) port. diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index af4d0694ab6..6b32ba2c102 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -66,7 +66,7 @@ public static class WithoutNetwork { // without_network { @ClassRule public static LocalStackContainer localstack = new LocalStackContainer(LOCALSTACK_IMAGE) - .withServices(S3, SQS, CLOUDWATCHLOGS, KMS); + .withServices(S3, SQS, CLOUDWATCHLOGS, KMS, LocalStackContainer.EnabledService.named("events")); // } @Test From 3a6e77e920c06ed2157d9baf0313e529f4395650 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 20 Apr 2021 16:51:15 +0200 Subject: [PATCH 1205/4969] Update mkdocs.yml to the latest release (1.15.3) --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 15cc915f5b2..f3cb11f7fe6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -96,4 +96,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.15.2 + latest_version: 1.15.3 From 49a103ce6272a51c29119f19951e1d3c92d2ba1d Mon Sep 17 00:00:00 2001 From: vcvitaly Date: Sat, 24 Apr 2021 21:54:33 +0300 Subject: [PATCH 1206/4969] Improve logging in InternalCommandPortListeningCheck (#3001) --- .../wait/internal/InternalCommandPortListeningCheck.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index cd601e6a131..a3b7a5d4dc7 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -41,7 +41,11 @@ public Boolean call() { try { ExecResult result = ExecInContainerPattern.execInContainer(waitStrategyTarget.getContainerInfo(), "/bin/sh", "-c", command.toString()); log.trace("Check for {} took {}. Result code '{}', stdout message: '{}'", internalPorts, Duration.between(before, Instant.now()), result.getExitCode(), result.getStdout()); - return result.getExitCode() == 0; + int exitCode = result.getExitCode(); + if (exitCode != 0 && exitCode != 1) { + log.warn("An exception while executing the internal check: {}", result); + } + return exitCode == 0; } catch (Exception e) { throw new IllegalStateException(e); } From f94737f0d7509e8a6a5f39b23df7c24585bf5dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Torres?= Date: Thu, 29 Apr 2021 13:28:21 +0100 Subject: [PATCH 1207/4969] Docs: Add Backbase as Bronze sponsor (#4039) --- docs/index.md | 7 +++++++ docs/sponsor_logos/backbase.png | Bin 0 -> 5757 bytes 2 files changed, 7 insertions(+) create mode 100644 docs/sponsor_logos/backbase.png diff --git a/docs/index.md b/docs/index.md index 176ddd16974..45213629ed0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -123,6 +123,13 @@ A huge thank you to our sponsors: +

+ ### Backers * [Philip Riecks (@rieckpil)](https://github.com/rieckpil) diff --git a/docs/sponsor_logos/backbase.png b/docs/sponsor_logos/backbase.png new file mode 100644 index 0000000000000000000000000000000000000000..22acf3aac8e93f4d09f2e4c31502f85a209da4db GIT binary patch literal 5757 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 Wn%C=%XDnxTusSdUjWTtIr~d;?(<52{ literal 0 HcmV?d00001 From 3aa5fbfa17be09f4e42b2300396890f76f508c86 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 7 May 2021 13:09:56 +0100 Subject: [PATCH 1208/4969] Use up-to-date MySQL docker images (#4059) Co-authored-by: Sergei Egorov --- core/src/test/resources/compose-test.yml | 2 +- .../generic/ImageNameSubstitutionTest.java | 6 ++--- .../TestSpecificImageNameSubstitutor.java | 2 +- docs/features/image_name_substitution.md | 2 +- docs/modules/databases/jdbc.md | 12 +++++----- docs/modules/databases/mysql.md | 2 +- docs/modules/databases/r2dbc.md | 4 ++-- .../db/AbstractContainerDatabaseTest.java | 1 - .../jdbc/ConnectionUrlDriversTests.java | 2 +- .../jdbc/ConnectionUrlTest.java | 10 ++++---- .../jdbc/MissingJdbcDriverTest.java | 2 +- modules/mysql/build.gradle | 2 +- .../containers/MySQLContainer.java | 2 +- .../org/testcontainers/MySQLTestImages.java | 6 ++--- .../MySQLR2DBCDatabaseContainerTest.java | 4 ++-- .../containers/MySQLRootAccountTest.java | 12 ++++++---- .../jdbc/mysql/JDBCDriverWithPoolTest.java | 2 +- .../jdbc/mysql/MySQLJDBCDriverTest.java | 16 ++++++------- .../junit/mysql/CustomizableMysqlTest.java | 2 +- .../junit/mysql/MultiVersionMySQLTest.java | 24 +++++++++---------- .../junit/mysql/SimpleMySQLTest.java | 23 +++++++++--------- .../spock/SpockTestImages.groovy | 2 +- 22 files changed, 70 insertions(+), 70 deletions(-) diff --git a/core/src/test/resources/compose-test.yml b/core/src/test/resources/compose-test.yml index a79a4c0b25b..9c5537e7cab 100644 --- a/core/src/test/resources/compose-test.yml +++ b/core/src/test/resources/compose-test.yml @@ -1,6 +1,6 @@ redis: image: redis db: - image: mysql:5.7.22 + image: mysql:5.7.34 environment: MYSQL_RANDOM_ROOT_PASSWORD: "true" diff --git a/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java b/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java index edc622a4104..65da67fd401 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java @@ -12,9 +12,9 @@ public class ImageNameSubstitutionTest { public void simpleExample() { try ( // directDockerHubReference { - // Referring directly to an image on Docker Hub (mysql:8.0.22) + // Referring directly to an image on Docker Hub (mysql:8.0.24) final MySQLContainer mysql = new MySQLContainer<>( - DockerImageName.parse("mysql:8.0.22") + DockerImageName.parse("mysql:8.0.24") ) // start the container and use it for testing @@ -35,7 +35,7 @@ public void substitutedExample() { // hardcodedMirror { // Referring directly to an image on a private registry - image name will vary final MySQLContainer mysql = new MySQLContainer<>( - DockerImageName.parse("registry.mycompany.com/mirror/mysql:8.0.22") + DockerImageName.parse("registry.mycompany.com/mirror/mysql:8.0.24") .asCompatibleSubstituteFor("mysql") ) diff --git a/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java b/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java index 5f9e92c0add..01f6fdcb4f0 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java +++ b/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java @@ -12,7 +12,7 @@ public class TestSpecificImageNameSubstitutor extends ImageNameSubstitutor { @Override public DockerImageName apply(final DockerImageName original) { - if (original.equals(DockerImageName.parse("registry.mycompany.com/mirror/mysql:8.0.22"))) { + if (original.equals(DockerImageName.parse("registry.mycompany.com/mirror/mysql:8.0.24"))) { return DockerImageName.parse("mysql"); } else { return original; diff --git a/docs/features/image_name_substitution.md b/docs/features/image_name_substitution.md index 37088473d72..7ead811a250 100644 --- a/docs/features/image_name_substitution.md +++ b/docs/features/image_name_substitution.md @@ -53,7 +53,7 @@ Consider this if: * Developers and CI machines need to use different image names. For example, developers are able to pull images from Docker Hub, but CI machines need to pull from a private registry * Your private registry has copies of images from Docker Hub where the names are predictable, and just adding a prefix is enough. - For example, `registry.mycompany.com/mirror/mysql:8.0.22` can be derived from the original Docker Hub image name (`mysql:8.0.22`) with a consistent prefix string: `registry.mycompany.com/mirror/` + For example, `registry.mycompany.com/mirror/mysql:8.0.24` can be derived from the original Docker Hub image name (`mysql:8.0.24`) with a consistent prefix string: `registry.mycompany.com/mirror/` In this case, image name references in code are **unchanged**. i.e. you would leave as-is: diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index fec250ffdd9..7adaf2f5e70 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -20,7 +20,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database !!! note We will use `///` (host-less URIs) from now on to emphasis the unimportance of the `host:port` pair. - From Testcontainers' perspective, `jdbc:mysql:5.7.22://localhost:3306/databasename` and `jdbc:mysql:5.7.22:///databasename` is the same URI. + From Testcontainers' perspective, `jdbc:mysql:5.7.34://localhost:3306/databasename` and `jdbc:mysql:5.7.34:///databasename` is the same URI. !!! warning If you're using the JDBC URL support, there is no need to instantiate an instance of the container - Testcontainers will do it automagically. @@ -29,7 +29,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database #### Using Testcontainers with a fixed version -`jdbc:tc:mysql:5.6.23:///databasename` +`jdbc:tc:mysql:5.7.34:///databasename` #### Using PostgreSQL @@ -47,7 +47,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: -`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=somepath/init_mysql.sql` +`jdbc:tc:mysql:5.7.34:///databasename?TC_INITSCRIPT=somepath/init_mysql.sql` This is useful if you have a fixed script for setting up database schema, etc. @@ -55,13 +55,13 @@ This is useful if you have a fixed script for setting up database schema, etc. If the init script path is prefixed `file:`, it will be loaded from a file (relative to the working directory, which will usually be the project root). -`jdbc:tc:mysql:5.7.22:///databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql` +`jdbc:tc:mysql:5.7.34:///databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql` ### Using an init function Instead of running a fixed script for DB setup, it may be useful to call a Java function that you define. This is intended to allow you to trigger database schema migration tools. To do this, add TC_INITFUNCTION to the URL as follows, passing a full path to the class name and method: - `jdbc:tc:mysql:5.7.22:///databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction` + `jdbc:tc:mysql:5.7.34:///databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction` The init function must be a public static method which takes a `java.sql.Connection` as its only parameter, e.g. ```java @@ -76,7 +76,7 @@ public class JDBCDriverTest { By default database container is being stopped as soon as last connection is closed. There are cases when you might need to start container and keep it running till you stop it explicitly or JVM is shutdown. To do this, add `TC_DAEMON` parameter to the URL as follows: - `jdbc:tc:mysql:5.7.22:///databasename?TC_DAEMON=true` + `jdbc:tc:mysql:5.7.34:///databasename?TC_DAEMON=true` With this parameter database container will keep running even when there're no open connections. diff --git a/docs/modules/databases/mysql.md b/docs/modules/databases/mysql.md index b32373f3363..ac3a53fe1fe 100644 --- a/docs/modules/databases/mysql.md +++ b/docs/modules/databases/mysql.md @@ -7,7 +7,7 @@ See [Database containers](./index.md) for documentation and usage that is common For MySQL databases, it is possible to override configuration settings using resources on the classpath. Assuming `somepath/mysql_conf_override` is a directory on the classpath containing .cnf files, the following URL can be used: - `jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override` + `jdbc:tc:mysql:5.7.34://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override` Any .cnf files in this classpath directory will be mapped into the database container's /etc/mysql/conf.d directory, and will be able to override server settings when the container starts. diff --git a/docs/modules/databases/r2dbc.md b/docs/modules/databases/r2dbc.md index 6ba3f401a08..dba59b2d3d9 100644 --- a/docs/modules/databases/r2dbc.md +++ b/docs/modules/databases/r2dbc.md @@ -22,7 +22,7 @@ The started container will be terminated when the `ConnectionFactory` is closed. **Note that, unlike Testcontainers' JDBC URL support, it is not possible to specify an image tag in the 'scheme' part of the URL, and it is always necessary to specify a tag using `TC_IMAGE_TAG`.** So that the URL becomes: -`r2dbc:tc:mysql:///databasename?TC_IMAGE_TAG=5.7.22` +`r2dbc:tc:mysql:///databasename?TC_IMAGE_TAG=5.7.34` !!! note We will use `///` (host-less URIs) from now on to emphasis the unimportance of the `host:port` pair. @@ -35,7 +35,7 @@ So that the URL becomes: #### Using MySQL -`r2dbc:tc:mysql:///databasename?TC_IMAGE_TAG=5.6.23` +`r2dbc:tc:mysql:///databasename?TC_IMAGE_TAG=5.7.34` #### Using MariaDB diff --git a/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java index 8881ed963d8..6a5ca5094d6 100644 --- a/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java @@ -27,7 +27,6 @@ protected DataSource getDataSource(JdbcDatabaseContainer container) { hikariConfig.setUsername(container.getUsername()); hikariConfig.setPassword(container.getPassword()); hikariConfig.setDriverClassName(container.getDriverClassName()); - return new HikariDataSource(hikariConfig); } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java index 3f0673d834f..920fab04016 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java @@ -33,7 +33,7 @@ public class ConnectionUrlDriversTests { public static Iterable data() { return asList( new Object[][]{ - {"jdbc:tc:mysql:5.5.43://hostname/test", "mysql", Optional.of("5.5.43"), "hostname/test", "test"}, + {"jdbc:tc:mysql:5.7.34://hostname/test", "mysql", Optional.of("5.7.34"), "hostname/test", "test"}, {"jdbc:tc:mysql://hostname/test", "mysql", Optional.empty(), "hostname/test", "test"}, {"jdbc:tc:postgresql:1.2.3://hostname/test", "postgresql", Optional.of("1.2.3"), "hostname/test", "test"}, {"jdbc:tc:postgresql://hostname/test", "postgresql", Optional.empty(), "hostname/test", "test"}, diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java index 312d5cf5146..4fefd5d1e13 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java @@ -16,11 +16,11 @@ public class ConnectionUrlTest { @Test public void testConnectionUrl1() { - String urlString = "jdbc:tc:mysql:5.6.23://somehostname:3306/databasename?a=b&c=d"; + String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); assertEquals("Database Type value is as expected", "mysql", url.getDatabaseType()); - assertEquals("Database Image tag value is as expected", "5.6.23", url.getImageTag().get()); + assertEquals("Database Image tag value is as expected", "5.7.34", url.getImageTag().get()); assertEquals("Database Host String is as expected", "somehostname:3306/databasename", url.getDbHostString()); assertEquals("Query String value is as expected", "?a=b&c=d", url.getQueryString().get()); assertEquals("Database Host value is as expected", "somehostname", url.getDatabaseHost().get()); @@ -72,7 +72,7 @@ public void testTmpfsOption() { @Test public void testInitScriptPathCapture() { - String urlString = "jdbc:tc:mysql:5.6.23://somehostname:3306/databasename?a=b&c=d&TC_INITSCRIPT=somepath/init_mysql.sql"; + String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITSCRIPT=somepath/init_mysql.sql"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); assertEquals("Database Type value is as expected", "somepath/init_mysql.sql", url.getInitScriptPath().get()); @@ -88,7 +88,7 @@ public void testInitScriptPathCapture() { @Test public void testInitFunctionCapture() { - String urlString = "jdbc:tc:mysql:5.6.23://somehostname:3306/databasename?a=b&c=d&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction"; + String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); assertTrue("Init Function parameter exists", url.getInitFunction().isPresent()); @@ -100,7 +100,7 @@ public void testInitFunctionCapture() { @Test public void testDaemonCapture() { - String urlString = "jdbc:tc:mysql:5.6.23://somehostname:3306/databasename?a=b&c=d&TC_DAEMON=true"; + String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_DAEMON=true"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); assertTrue("Daemon flag is set to true.", url.isInDaemonMode()); diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java index 88398cebf85..46138d91347 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java @@ -40,7 +40,7 @@ static class MissingDriverContainer extends JdbcDatabaseContainer { private final AtomicInteger connectionAttempts = new AtomicInteger(); MissingDriverContainer() { - super(DockerImageName.parse("mysql:5.7.22")); + super(DockerImageName.parse("mysql:5.7.34")); withEnv("MYSQL_ROOT_PASSWORD", "test"); withExposedPorts(3306); } diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index da3dad9f2b3..172ca29070d 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -13,7 +13,7 @@ dependencies { testCompile 'mysql:mysql-connector-java:8.0.22' testCompile testFixtures(project(':r2dbc')) - testCompile 'dev.miku:r2dbc-mysql:0.8.1.RELEASE' + testCompile 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' compileOnly 'org.jetbrains:annotations:20.1.0' } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index a126a579489..20be08c2aec 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -16,7 +16,7 @@ public class MySQLContainer> extends JdbcDatab private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mysql"); @Deprecated - public static final String DEFAULT_TAG = "5.7.22"; + public static final String DEFAULT_TAG = "5.7.34"; @Deprecated public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); diff --git a/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java b/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java index 6c8c6690d1f..833dc1448cf 100644 --- a/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java +++ b/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java @@ -3,7 +3,7 @@ import org.testcontainers.utility.DockerImageName; public class MySQLTestImages { - public static final DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.22"); - public static final DockerImageName MYSQL_55_IMAGE = DockerImageName.parse("mysql:5.5"); - public static final DockerImageName MYSQL_56_IMAGE = DockerImageName.parse("mysql:5.6"); + public static final DockerImageName MYSQL_56_IMAGE = DockerImageName.parse("mysql:5.6.51"); + public static final DockerImageName MYSQL_57_IMAGE = DockerImageName.parse("mysql:5.7.34"); + public static final DockerImageName MYSQL_80_IMAGE = DockerImageName.parse("mysql:8.0.24"); } diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java index 38abf637c3a..334fabb0a49 100644 --- a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java @@ -13,12 +13,12 @@ protected ConnectionFactoryOptions getOptions(MySQLContainer container) { @Override protected String createR2DBCUrl() { - return "r2dbc:tc:mysql:///db?TC_IMAGE_TAG=5.7.22"; + return "r2dbc:tc:mysql:///db?TC_IMAGE_TAG=" + MySQLTestImages.MYSQL_80_IMAGE.getVersionPart(); } @Override protected MySQLContainer createContainer() { - return new MySQLContainer<>(MySQLTestImages.MYSQL_IMAGE); + return new MySQLContainer<>(MySQLTestImages.MYSQL_80_IMAGE); } } diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java index c437acac013..86b13a0d1bf 100644 --- a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java @@ -4,7 +4,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.testcontainers.MySQLTestImages; import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.utility.DockerImageName; import java.sql.Connection; import java.sql.DriverManager; @@ -15,15 +17,15 @@ public class MySQLRootAccountTest { @Parameterized.Parameters(name = "{0}") - public static String[] params() { - return new String[]{ - "mysql:8", - "mysql:5" + public static DockerImageName[] params() { + return new DockerImageName[]{ + MySQLTestImages.MYSQL_80_IMAGE, + MySQLTestImages.MYSQL_57_IMAGE }; } @Parameterized.Parameter() - public String image; + public DockerImageName image; @Test public void testRootAccountUsageWithDefaultPassword() throws SQLException { diff --git a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java index 1ad77264c62..3b9f9842095 100644 --- a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java @@ -31,7 +31,7 @@ @RunWith(Parameterized.class) public class JDBCDriverWithPoolTest { - public static final String URL = "jdbc:tc:mysql:5://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.mysql.JDBCDriverWithPoolTest::sampleInitFunction"; + public static final String URL = "jdbc:tc:mysql:5.7.34://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.mysql.JDBCDriverWithPoolTest::sampleInitFunction"; private final DataSource dataSource; @Parameterized.Parameters diff --git a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java index d4b37b291d5..302621879eb 100644 --- a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java @@ -17,14 +17,14 @@ public static Iterable data() { new Object[][]{ {"jdbc:tc:mysql://hostname/databasename", EnumSet.noneOf(Options.class)}, {"jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)}, + {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, + {"jdbc:tc:mysql:5.7.34://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, + {"jdbc:tc:mysql:5.7.34://hostname/databasename", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:mysql:5.7.34://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class)}, + {"jdbc:tc:mysql:5.6.51://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)}, }); } } diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java index 708b2b987cd..0b72ce083d2 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java @@ -18,7 +18,7 @@ public class CustomizableMysqlTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - try (MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_IMAGE) + try (MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) .withDatabaseName(DB_NAME) .withUsername(USER) .withPassword(PWD) diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java index b8f1a136d9a..32dee3cd056 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java @@ -3,7 +3,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.testcontainers.MySQLTestImages; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; import org.testcontainers.utility.DockerImageName; @@ -12,32 +11,33 @@ import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.testcontainers.MySQLTestImages.MYSQL_56_IMAGE; +import static org.testcontainers.MySQLTestImages.MYSQL_57_IMAGE; +import static org.testcontainers.MySQLTestImages.MYSQL_80_IMAGE; @RunWith(Parameterized.class) public class MultiVersionMySQLTest extends AbstractContainerDatabaseTest { @Parameterized.Parameters(name = "{0}") - public static String[] params() { - return new String[]{"5.5.62", "5.6.42", "5.7.26", "8.0.16"}; + public static DockerImageName[] params() { + return new DockerImageName[]{ + MYSQL_56_IMAGE, + MYSQL_57_IMAGE, + MYSQL_80_IMAGE + }; } - private final String version; - - public MultiVersionMySQLTest(String version) { - this.version = version; - } + @Parameterized.Parameter() + public DockerImageName dockerImageName; @Test public void versionCheckTest() throws SQLException { - - final DockerImageName dockerImageName = MySQLTestImages.MYSQL_IMAGE.withTag(version); - try (MySQLContainer mysql = new MySQLContainer<>(dockerImageName)) { mysql.start(); final ResultSet resultSet = performQuery(mysql, "SELECT VERSION()"); final String resultSetString = resultSet.getString(1); - assertEquals("The database version can be set using a container rule parameter", version, resultSetString); + assertEquals("The database version can be set using a container rule parameter", dockerImageName.getVersionPart(), resultSetString); } } } diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index f0ceeb92a48..1b6143b3b34 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -24,9 +24,8 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; import static org.rnorth.visibleassertions.VisibleAssertions.fail; -import static org.testcontainers.MySQLTestImages.MYSQL_55_IMAGE; import static org.testcontainers.MySQLTestImages.MYSQL_56_IMAGE; -import static org.testcontainers.MySQLTestImages.MYSQL_IMAGE; +import static org.testcontainers.MySQLTestImages.MYSQL_57_IMAGE; public class SimpleMySQLTest extends AbstractContainerDatabaseTest { @@ -52,7 +51,7 @@ public class SimpleMySQLTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) + try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) .withConfigurationOverride("somepath/mysql_conf_override") .withLogConsumer(new Slf4jLogConsumer(logger))) { @@ -67,7 +66,7 @@ public void testSimple() throws SQLException { @Test public void testSpecificVersion() throws SQLException { - try (MySQLContainer mysqlOldVersion = new MySQLContainer<>(MYSQL_55_IMAGE) + try (MySQLContainer mysqlOldVersion = new MySQLContainer<>(MYSQL_56_IMAGE) .withConfigurationOverride("somepath/mysql_conf_override") .withLogConsumer(new Slf4jLogConsumer(logger))) { @@ -76,7 +75,7 @@ public void testSpecificVersion() throws SQLException { ResultSet resultSet = performQuery(mysqlOldVersion, "SELECT VERSION()"); String resultSetString = resultSet.getString(1); - assertTrue("The database version can be set using a container rule parameter", resultSetString.startsWith("5.5")); + assertTrue("The database version can be set using a container rule parameter", resultSetString.startsWith("5.6")); } } @@ -98,7 +97,7 @@ public void testMySQLWithCustomIniFile() throws SQLException { @Test public void testCommandOverride() throws SQLException { - try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MYSQL_IMAGE) + try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MYSQL_57_IMAGE) .withCommand("mysqld --auto_increment_increment=42")) { mysqlCustomConfig.start(); @@ -112,7 +111,7 @@ public void testCommandOverride() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (MySQLContainer container = new MySQLContainer<>(MYSQL_IMAGE) + try (MySQLContainer container = new MySQLContainer<>(MYSQL_57_IMAGE) .withInitScript("somepath/init_mysql.sql") .withLogConsumer(new Slf4jLogConsumer(logger))) { container.start(); @@ -126,7 +125,7 @@ public void testExplicitInitScript() throws SQLException { @Test(expected = ContainerLaunchException.class) public void testEmptyPasswordWithNonRootUser() { - try (MySQLContainer container = new MySQLContainer<>(MYSQL_55_IMAGE) + try (MySQLContainer container = new MySQLContainer<>(MYSQL_56_IMAGE) .withDatabaseName("TEST") .withUsername("test") .withPassword("") @@ -139,7 +138,7 @@ public void testEmptyPasswordWithNonRootUser() { @Test public void testEmptyPasswordWithRootUser() throws SQLException { // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_55_IMAGE) + try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_56_IMAGE) .withDatabaseName("foo") .withUsername("root") .withPassword("") @@ -156,7 +155,7 @@ public void testEmptyPasswordWithRootUser() throws SQLException { @Test public void testWithAdditionalUrlParamTimeZone() throws SQLException { - MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) + MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) .withUrlParam("serverTimezone", "Europe/Zurich") .withEnv("TZ", "Europe/Zurich") .withLogConsumer(new Slf4jLogConsumer(logger)); @@ -186,7 +185,7 @@ public void testWithAdditionalUrlParamTimeZone() throws SQLException { @Test public void testWithAdditionalUrlParamMultiQueries() throws SQLException { - MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) + MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) .withUrlParam("allowMultiQueries", "true") .withLogConsumer(new Slf4jLogConsumer(logger)); mysql.start(); @@ -210,7 +209,7 @@ public void testWithAdditionalUrlParamMultiQueries() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - MySQLContainer mysql = new MySQLContainer<>(MYSQL_IMAGE) + MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) .withUrlParam("allowMultiQueries", "true") .withUrlParam("rewriteBatchedStatements", "true") .withLogConsumer(new Slf4jLogConsumer(logger)); diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy index 9698e7d433a..f18bc8dc96d 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy @@ -3,7 +3,7 @@ package org.testcontainers.spock import org.testcontainers.utility.DockerImageName interface SpockTestImages { - DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.22") + DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.34") DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.5") From 99f5fac886d857896b19b8c609161fe53608eda1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20L=C3=B6vdahl?= Date: Fri, 7 May 2021 16:58:22 +0300 Subject: [PATCH 1209/4969] Docs: Use `testImplementation` instead of deprecated `testCompile` (#4054) Co-authored-by: Richard North --- docs/examples/junit4/generic/build.gradle | 14 +++++++------- docs/examples/junit4/redis/build.gradle | 4 ++-- docs/examples/junit5/redis/build.gradle | 8 ++++---- docs/index.md | 2 +- docs/modules/databases/cassandra.md | 2 +- docs/modules/databases/clickhouse.md | 2 +- docs/modules/databases/cockroachdb.md | 2 +- docs/modules/databases/couchbase.md | 2 +- docs/modules/databases/db2.md | 2 +- docs/modules/databases/dynalite.md | 2 +- docs/modules/databases/influxdb.md | 2 +- docs/modules/databases/mariadb.md | 2 +- docs/modules/databases/mongodb.md | 2 +- docs/modules/databases/mssqlserver.md | 2 +- docs/modules/databases/mysql.md | 2 +- docs/modules/databases/neo4j.md | 2 +- docs/modules/databases/oraclexe.md | 2 +- docs/modules/databases/orientdb.md | 2 +- docs/modules/databases/postgres.md | 2 +- docs/modules/databases/presto.md | 2 +- docs/modules/databases/trino.md | 2 +- docs/modules/docker_compose.md | 2 +- docs/modules/elasticsearch.md | 2 +- docs/modules/gcloud.md | 2 +- docs/modules/kafka.md | 2 +- docs/modules/localstack.md | 2 +- docs/modules/mockserver.md | 2 +- docs/modules/nginx.md | 2 +- docs/modules/pulsar.md | 2 +- docs/modules/rabbitmq.md | 2 +- docs/modules/solr.md | 2 +- docs/modules/toxiproxy.md | 2 +- docs/modules/vault.md | 2 +- docs/modules/webdriver_containers.md | 2 +- docs/quickstart/junit_4_quickstart.md | 2 +- docs/quickstart/junit_5_quickstart.md | 8 ++++---- docs/quickstart/spock_quickstart.md | 2 +- docs/test_framework_integration/spock.md | 2 +- 38 files changed, 51 insertions(+), 51 deletions(-) diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle index ff1b11f142e..1021bfeffc0 100644 --- a/docs/examples/junit4/generic/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -1,12 +1,12 @@ description = "Examples for docs" dependencies { - testCompile "junit:junit:4.12" - testCompile project(":testcontainers") - testCompile project(":selenium") - testCompile project(":mysql") + testImplementation "junit:junit:4.12" + testImplementation project(":testcontainers") + testImplementation project(":selenium") + testImplementation project(":mysql") - testCompile 'mysql:mysql-connector-java:8.0.21' - testCompile "org.seleniumhq.selenium:selenium-api:3.141.59" - testCompile 'org.assertj:assertj-core:3.15.0' + testImplementation 'mysql:mysql-connector-java:8.0.21' + testImplementation "org.seleniumhq.selenium:selenium-api:3.141.59" + testImplementation 'org.assertj:assertj-core:3.15.0' } diff --git a/docs/examples/junit4/redis/build.gradle b/docs/examples/junit4/redis/build.gradle index 76d32e5b4d0..bf203a8fefa 100644 --- a/docs/examples/junit4/redis/build.gradle +++ b/docs/examples/junit4/redis/build.gradle @@ -3,6 +3,6 @@ description = "Examples for docs" dependencies { compile "io.lettuce:lettuce-core:5.1.1.RELEASE" - testCompile "junit:junit:4.12" - testCompile project(":testcontainers") + testImplementation "junit:junit:4.12" + testImplementation project(":testcontainers") } diff --git a/docs/examples/junit5/redis/build.gradle b/docs/examples/junit5/redis/build.gradle index 56442b66af3..409b766b758 100644 --- a/docs/examples/junit5/redis/build.gradle +++ b/docs/examples/junit5/redis/build.gradle @@ -3,9 +3,9 @@ description = "Examples for docs" dependencies { compile "io.lettuce:lettuce-core:5.1.1.RELEASE" - testCompile "org.junit.jupiter:junit-jupiter-api:5.4.2" - testCompile "org.junit.jupiter:junit-jupiter-params:5.4.2" + testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.2" + testImplementation "org.junit.jupiter:junit-jupiter-params:5.4.2" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.2" - testCompile project(":testcontainers") - testCompile project(":junit-jupiter") + testImplementation project(":testcontainers") + testImplementation project(":junit-jupiter") } diff --git a/docs/index.md b/docs/index.md index 45213629ed0..e58a23bc330 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,7 +32,7 @@ Testcontainers is distributed as separate JARs with a common version number: For the core library, the latest Maven/Gradle dependency is as follows: ```groovy tab='Gradle' -testCompile "org.testcontainers:testcontainers:{{latest_version}}" +testImplementation "org.testcontainers:testcontainers:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/cassandra.md b/docs/modules/databases/cassandra.md index d15304afa81..63213d27343 100644 --- a/docs/modules/databases/cassandra.md +++ b/docs/modules/databases/cassandra.md @@ -38,7 +38,7 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:cassandra:{{latest_version}}" +testImplementation "org.testcontainers:cassandra:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/clickhouse.md b/docs/modules/databases/clickhouse.md index 37f68c41e18..a52a75af51f 100644 --- a/docs/modules/databases/clickhouse.md +++ b/docs/modules/databases/clickhouse.md @@ -5,7 +5,7 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:clickhouse:{{latest_version}}" +testImplementation "org.testcontainers:clickhouse:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/cockroachdb.md b/docs/modules/databases/cockroachdb.md index d9e6def4e48..540f4820a84 100644 --- a/docs/modules/databases/cockroachdb.md +++ b/docs/modules/databases/cockroachdb.md @@ -10,7 +10,7 @@ See [Database containers](./index.md) for documentation and usage that is common Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:cockroachdb:{{latest_version}}" +testImplementation "org.testcontainers:cockroachdb:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/couchbase.md b/docs/modules/databases/couchbase.md index b71ee5de327..f8ed7465dd9 100644 --- a/docs/modules/databases/couchbase.md +++ b/docs/modules/databases/couchbase.md @@ -33,7 +33,7 @@ Running Couchbase as a stand-in in a test: Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:couchbase:{{latest_version}}" +testImplementation "org.testcontainers:couchbase:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/db2.md b/docs/modules/databases/db2.md index bc25b343072..3872e7fa857 100644 --- a/docs/modules/databases/db2.md +++ b/docs/modules/databases/db2.md @@ -34,7 +34,7 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:db2:{{latest_version}}" +testImplementation "org.testcontainers:db2:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/dynalite.md b/docs/modules/databases/dynalite.md index 2d5c7f7492d..dfc32f35d2e 100644 --- a/docs/modules/databases/dynalite.md +++ b/docs/modules/databases/dynalite.md @@ -30,7 +30,7 @@ In part, because it's light and quick to run. Also, please see the [reasons give Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:dynalite:{{latest_version}}" +testImplementation "org.testcontainers:dynalite:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/influxdb.md b/docs/modules/databases/influxdb.md index 740cf69982c..5de7d36182a 100644 --- a/docs/modules/databases/influxdb.md +++ b/docs/modules/databases/influxdb.md @@ -23,7 +23,7 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:influxdb:{{latest_version}}" +testImplementation "org.testcontainers:influxdb:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/mariadb.md b/docs/modules/databases/mariadb.md index 74a4c6e061e..7ef14bed3cc 100644 --- a/docs/modules/databases/mariadb.md +++ b/docs/modules/databases/mariadb.md @@ -24,7 +24,7 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:mariadb:{{latest_version}}" +testImplementation "org.testcontainers:mariadb:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/mongodb.md b/docs/modules/databases/mongodb.md index fc2cb873f59..3d49ecc6809 100644 --- a/docs/modules/databases/mongodb.md +++ b/docs/modules/databases/mongodb.md @@ -41,7 +41,7 @@ That's where the MongoDBContainer might come in handy. Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:mongodb:{{latest_version}}" +testImplementation "org.testcontainers:mongodb:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/mssqlserver.md b/docs/modules/databases/mssqlserver.md index 29c5435be32..6dea62def25 100644 --- a/docs/modules/databases/mssqlserver.md +++ b/docs/modules/databases/mssqlserver.md @@ -30,7 +30,7 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:mssqlserver:{{latest_version}}" +testImplementation "org.testcontainers:mssqlserver:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/mysql.md b/docs/modules/databases/mysql.md index ac3a53fe1fe..f5a428e1cdc 100644 --- a/docs/modules/databases/mysql.md +++ b/docs/modules/databases/mysql.md @@ -18,7 +18,7 @@ and will be able to override server settings when the container starts. Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:mysql:{{latest_version}}" +testImplementation "org.testcontainers:mysql:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/neo4j.md b/docs/modules/databases/neo4j.md index aaa18d225c9..702f9cc40d7 100644 --- a/docs/modules/databases/neo4j.md +++ b/docs/modules/databases/neo4j.md @@ -163,7 +163,7 @@ You'll find more information about licensing Neo4j here: [About Neo4j Licenses]( Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:neo4j:{{latest_version}}" +testImplementation "org.testcontainers:neo4j:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/oraclexe.md b/docs/modules/databases/oraclexe.md index 86a9a5f938c..56eb57bc0e5 100644 --- a/docs/modules/databases/oraclexe.md +++ b/docs/modules/databases/oraclexe.md @@ -31,7 +31,7 @@ containing `oracle.container.image=IMAGE`, where IMAGE is a suitable image name Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:oracle-xe:{{latest_version}}" +testImplementation "org.testcontainers:oracle-xe:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/orientdb.md b/docs/modules/databases/orientdb.md index 80ed96f9548..4f0b3550e44 100644 --- a/docs/modules/databases/orientdb.md +++ b/docs/modules/databases/orientdb.md @@ -46,7 +46,7 @@ You are not limited to Unit tests and can of course use an instance of the Orien Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:orientdb:{{latest_version}}" +testImplementation "org.testcontainers:orientdb:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/postgres.md b/docs/modules/databases/postgres.md index 07831766d1b..0777296b0c0 100644 --- a/docs/modules/databases/postgres.md +++ b/docs/modules/databases/postgres.md @@ -7,7 +7,7 @@ See [Database containers](./index.md) for documentation and usage that is common Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:postgresql:{{latest_version}}" +testImplementation "org.testcontainers:postgresql:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/presto.md b/docs/modules/databases/presto.md index 8e8a2672355..3b987796360 100644 --- a/docs/modules/databases/presto.md +++ b/docs/modules/databases/presto.md @@ -68,7 +68,7 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:presto:{{latest_version}}" +testImplementation "org.testcontainers:presto:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/databases/trino.md b/docs/modules/databases/trino.md index 4cd26978af1..5b65f45934a 100644 --- a/docs/modules/databases/trino.md +++ b/docs/modules/databases/trino.md @@ -68,7 +68,7 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:trino:{{latest_version}}" +testImplementation "org.testcontainers:trino:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index fa584d7f631..b789a0030a7 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -178,7 +178,7 @@ There are 3 ways to specify location of the `config.json` for Docker Compose: Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:testcontainers:{{latest_version}}" +testImplementation "org.testcontainers:testcontainers:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index cd47c9c4ed3..738bf427a56 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -42,7 +42,7 @@ other new and advanced features), you can use this instead: Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:elasticsearch:{{latest_version}}" +testImplementation "org.testcontainers:elasticsearch:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 33d50ee634f..aeab52fc932 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -142,7 +142,7 @@ See more examples: Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:gcloud:{{latest_version}}" +testImplementation "org.testcontainers:gcloud:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index b74d4ef49bd..b0cd1742f6b 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -51,7 +51,7 @@ You will need to explicitly create a network and set it on the Kafka container a Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:kafka:{{latest_version}}" +testImplementation "org.testcontainers:kafka:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index 41fd2a50a52..b6058508ddb 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -67,7 +67,7 @@ Testcontainers will inform Localstack of the best hostname automatically, using Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:localstack:{{latest_version}}" +testImplementation "org.testcontainers:localstack:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/mockserver.md b/docs/modules/mockserver.md index ead9d123915..bf56046deda 100644 --- a/docs/modules/mockserver.md +++ b/docs/modules/mockserver.md @@ -21,7 +21,7 @@ And how to set a simple expectation using the Java MockServerClient. Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:mockserver:{{latest_version}}" +testImplementation "org.testcontainers:mockserver:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/nginx.md b/docs/modules/nginx.md index d195b5451a2..5169d3c5625 100644 --- a/docs/modules/nginx.md +++ b/docs/modules/nginx.md @@ -27,7 +27,7 @@ And how to query the Nginx server for the custom content added. Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:nginx:{{latest_version}}" +testImplementation "org.testcontainers:nginx:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/pulsar.md b/docs/modules/pulsar.md index 8e6441586f8..92eda498f7c 100644 --- a/docs/modules/pulsar.md +++ b/docs/modules/pulsar.md @@ -5,7 +5,7 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:pulsar:{{latest_version}}" +testImplementation "org.testcontainers:pulsar:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/rabbitmq.md b/docs/modules/rabbitmq.md index 92275ad765b..dff8631eeca 100644 --- a/docs/modules/rabbitmq.md +++ b/docs/modules/rabbitmq.md @@ -8,7 +8,7 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:rabbitmq:{{latest_version}}" +testImplementation "org.testcontainers:rabbitmq:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/solr.md b/docs/modules/solr.md index 4776ffa608b..bb2d18d6431 100644 --- a/docs/modules/solr.md +++ b/docs/modules/solr.md @@ -21,7 +21,7 @@ You can start a solr container instance from any Java application by using: Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:solr:{{latest_version}}" +testImplementation "org.testcontainers:solr:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/toxiproxy.md b/docs/modules/toxiproxy.md index 8ffb910d6c1..a3403ccc377 100644 --- a/docs/modules/toxiproxy.md +++ b/docs/modules/toxiproxy.md @@ -73,7 +73,7 @@ Additionally we can disable the proxy to simulate a complete interruption to the Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:toxiproxy:{{latest_version}}" +testImplementation "org.testcontainers:toxiproxy:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/vault.md b/docs/modules/vault.md index 1f58c0ab836..3140a6258bc 100644 --- a/docs/modules/vault.md +++ b/docs/modules/vault.md @@ -42,7 +42,7 @@ test how your application behaves with Vault by writing different test scenarios Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:vault:{{latest_version}}" +testImplementation "org.testcontainers:vault:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/modules/webdriver_containers.md b/docs/modules/webdriver_containers.md index 41b7fb6bb23..34d3430830c 100644 --- a/docs/modules/webdriver_containers.md +++ b/docs/modules/webdriver_containers.md @@ -89,7 +89,7 @@ A few different examples are shown in [ChromeWebDriverContainerTest.java](https: Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:selenium:{{latest_version}}" +testImplementation "org.testcontainers:selenium:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/quickstart/junit_4_quickstart.md b/docs/quickstart/junit_4_quickstart.md index a3fecb1a14d..1a2cd84c77e 100644 --- a/docs/quickstart/junit_4_quickstart.md +++ b/docs/quickstart/junit_4_quickstart.md @@ -22,7 +22,7 @@ Let's start from here, and see how to improve the test with Testcontainers: First, add Testcontainers as a dependency as follows: ```groovy tab='Gradle' -testCompile "org.testcontainers:testcontainers:{{latest_version}}" +testImplementation "org.testcontainers:testcontainers:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/quickstart/junit_5_quickstart.md b/docs/quickstart/junit_5_quickstart.md index efd52b6c523..eb43bf05797 100644 --- a/docs/quickstart/junit_5_quickstart.md +++ b/docs/quickstart/junit_5_quickstart.md @@ -23,11 +23,11 @@ First, add Testcontainers as a dependency as follows: ```groovy tab='Gradle' def junitJupiterVersion = '5.4.2' -testCompile "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion" -testCompile "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion" +testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion" +testImplementation "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion" -testCompile "org.testcontainers:testcontainers:{{latest_version}}" -testCompile "org.testcontainers:junit-jupiter:{{latest_version}}" +testImplementation "org.testcontainers:testcontainers:{{latest_version}}" +testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/quickstart/spock_quickstart.md b/docs/quickstart/spock_quickstart.md index 902f1a78c09..875c1976c93 100644 --- a/docs/quickstart/spock_quickstart.md +++ b/docs/quickstart/spock_quickstart.md @@ -22,7 +22,7 @@ Let's start from here, and see how to improve the test with Testcontainers: First, add Testcontainers as a dependency as follows: ```groovy tab='Gradle' -testCompile "org.testcontainers:spock:{{latest_version}}" +testImplementation "org.testcontainers:spock:{{latest_version}}" ``` ```xml tab='Maven' diff --git a/docs/test_framework_integration/spock.md b/docs/test_framework_integration/spock.md index 8528faf4490..11ccf058767 100644 --- a/docs/test_framework_integration/spock.md +++ b/docs/test_framework_integration/spock.md @@ -18,7 +18,7 @@ can be mixed with Spock's `@Shared` annotation to indicate, that containers shou Add the following dependency to your `pom.xml`/`build.gradle` file: ```groovy tab='Gradle' -testCompile "org.testcontainers:spock:{{latest_version}}" +testImplementation "org.testcontainers:spock:{{latest_version}}" ``` ```xml tab='Maven' From cf6d15c8b8dabb59be8be2e1000d7e4f6d16817c Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 7 May 2021 15:59:21 +0200 Subject: [PATCH 1210/4969] Remove visible assertions dependency (#4010) --- core/build.gradle | 3 +-- .../java/org/testcontainers/containers/GenericContainer.java | 3 +-- examples/disque-job-queue/build.gradle | 1 + examples/redis-backed-cache-testng/build.gradle | 1 + examples/redis-backed-cache/build.gradle | 1 + examples/selenium-container/build.gradle | 1 + examples/singleton-container/build.gradle | 1 + examples/solr-container/build.gradle | 1 + examples/spring-boot/build.gradle | 1 + modules/dynalite/build.gradle | 2 ++ modules/elasticsearch/build.gradle | 1 + modules/jdbc/build.gradle | 1 + modules/localstack/build.gradle | 1 + modules/mockserver/build.gradle | 1 + modules/nginx/build.gradle | 1 + modules/selenium/build.gradle | 1 + 16 files changed, 17 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 463116dc5ee..5c8e9fe875d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -178,8 +178,6 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } - compile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compile "com.github.docker-java:docker-java-api:3.2.8" shaded ('com.github.docker-java:docker-java-core:3.2.8') { @@ -218,6 +216,7 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' testCompile 'org.assertj:assertj-core:3.18.1' testCompile project(':test-support') diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 4536a70789c..e53af6240ab 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -71,7 +71,6 @@ import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.rnorth.ducttape.unreliables.Unreliables; -import org.rnorth.visibleassertions.VisibleAssertions; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.UnstableAPI; @@ -748,7 +747,7 @@ private void applyConfiguration(CreateContainerCmd createCommand) { boolean shouldCheckFileMountingSupport = binds.size() > 0 && !TestcontainersConfiguration.getInstance().isDisableChecks(); if (shouldCheckFileMountingSupport) { if (!DockerClientFactory.instance().isFileMountingSupported()) { - VisibleAssertions.warn( + logger().warn( "Unable to mount a file from test host into a running container. " + "This may be a misconfiguration or limitation of your Docker environment. " + "Some features might not work." diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index c31cb39b7fe..90bbdd6d6f9 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -15,4 +15,5 @@ dependencies { testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.testcontainers:testcontainers' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 76c245d5b51..d297f026323 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -14,6 +14,7 @@ dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testng:testng:7.3.0' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } test { diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index e63d494bcef..702ce023c6b 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -14,4 +14,5 @@ dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.1' testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 1f05d7b5663..a671c1832fe 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -15,4 +15,5 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.testcontainers:selenium' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index bbd35cabc49..54a16b25230 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -15,4 +15,5 @@ dependencies { testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:testcontainers' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index fcdf93a9c53..8c9fc2fcc11 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -14,5 +14,6 @@ dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 288a9226b90..ce2c028f83a 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -17,4 +17,5 @@ dependencies { runtimeOnly 'org.postgresql:postgresql' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.testcontainers:postgresql' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index a09ef417159..3ac35862e1a 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -5,4 +5,6 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.929' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.929' + + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index cb553c54654..f50b38bb568 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -4,4 +4,5 @@ dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.12.0" testCompile "org.elasticsearch.client:transport:7.10.1" + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 910dc29ebad..8b509f54fdb 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -10,4 +10,5 @@ dependencies { testCompile 'org.apache.tomcat:tomcat-jdbc:10.0.0' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c007b2c649e..6fb69b1ad85 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -8,4 +8,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.986' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.16.34' + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/mockserver/build.gradle b/modules/mockserver/build.gradle index b463997fed5..e13343559f5 100644 --- a/modules/mockserver/build.gradle +++ b/modules/mockserver/build.gradle @@ -4,4 +4,5 @@ dependencies { compile project(':testcontainers') testCompile 'org.mock-server:mockserver-client-java:5.5.4' + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index 6c4b97876c4..1e601312ab4 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -3,4 +3,5 @@ description = "Testcontainers :: Nginx" dependencies { compile project(':testcontainers') compileOnly 'org.jetbrains:annotations:20.1.0' + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index 7c6d81ca1bf..7911b1ea991 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -10,6 +10,7 @@ dependencies { testCompile 'org.mortbay.jetty:jetty:6.1.26' testCompile project(':nginx') + testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' compileOnly 'org.jetbrains:annotations:20.1.0' testCompileClasspath 'org.jetbrains:annotations:20.0.0' From 67812b567285be124253442007b1fe0034c23c15 Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 14 May 2021 05:43:40 +0100 Subject: [PATCH 1211/4969] Reduce dependabot bump rate to monthly (#4083) --- .github/dependabot.yml | 56 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 16b59da6dfa..4caa6509af2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,146 +3,146 @@ updates: - package-ecosystem: "gradle" directory: "/core" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 # Explicit entry for each module - package-ecosystem: "gradle" directory: "/modules/cassandra" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/clickhouse" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/couchbase" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/database-commons" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/dynalite" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/elasticsearch" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/influxdb" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/jdbc" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/jdbc-test" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/junit-jupiter" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/kafka" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/localstack" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/mariadb" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/mockserver" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/mssqlserver" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/mysql" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/neo4j" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/nginx" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/oracle-xe" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/postgresql" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/pulsar" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/selenium" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/spock" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/toxiproxy" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/vault" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 # Examples - package-ecosystem: "gradle" directory: "/examples" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 # GitHub Actions - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 From 137b00dfb9c72a3af1e0b27c442e8a5aa1a234c3 Mon Sep 17 00:00:00 2001 From: Mark Rotteveel Date: Wed, 19 May 2021 14:19:16 +0200 Subject: [PATCH 1212/4969] Only run update-* and release-drafter on original repository, not on forks (#4104) --- .github/workflows/release-drafter.yml | 1 + .github/workflows/update-docs-version.yml | 1 + .github/workflows/update-gradle-wrapper.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index e19e08b9f32..bb2afd986f1 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -7,6 +7,7 @@ on: jobs: update_release_draft: + if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - uses: release-drafter/release-drafter@fe52e97d262833ae07d05efaf1a239df3f1b5cd4 # v5.15.0 diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 64658c1be4a..ee11b83026a 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -6,6 +6,7 @@ on: jobs: build: + if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index d34110f5a6d..329230640e7 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -6,6 +6,7 @@ on: jobs: update-gradle-wrapper: + if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: From 3858aff8d63ae0b28b92bd08c21255163ae75160 Mon Sep 17 00:00:00 2001 From: vcvitaly Date: Wed, 19 May 2021 15:23:26 +0300 Subject: [PATCH 1213/4969] Improve log messages when database container test query fails (#3015) Co-authored-by: Sergei Egorov --- modules/jdbc/build.gradle | 1 + .../containers/JdbcDatabaseContainer.java | 32 ++++----- .../containers/JdbcDatabaseContainerTest.java | 71 +++++++++++++++++++ 3 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 8b509f54fdb..8f2d8954985 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -11,4 +11,5 @@ dependencies { testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testCompile 'org.assertj:assertj-core:3.16.1' } diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 26d699a1813..cf5ae150575 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -1,7 +1,9 @@ package org.testcontainers.containers; import com.github.dockerjava.api.command.InspectContainerResponse; +import java.sql.Statement; import lombok.NonNull; +import lombok.SneakyThrows; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.traits.LinkableContainer; @@ -130,25 +132,23 @@ public SELF withInitScript(String initScriptPath) { return self(); } + @SneakyThrows(InterruptedException.class) @Override protected void waitUntilContainerStarted() { logger().info("Waiting for database connection to become available at {} using query '{}'", getJdbcUrl(), getTestQueryString()); // Repeatedly try and open a connection to the DB and execute a test query long start = System.currentTimeMillis(); - try { - while (System.currentTimeMillis() < start + (1000 * startupTimeoutSeconds)) { - try { - if (!isRunning()) { - Thread.sleep(100L); - continue; // Don't attempt to connect yet - } - try (Connection connection = createConnection("")) { - boolean testQuerySucceeded = connection.createStatement().execute(this.getTestQueryString()); - if (testQuerySucceeded) { - break; - } + while (System.currentTimeMillis() < start + (1000 * startupTimeoutSeconds)) { + if (!isRunning()) { + Thread.sleep(100L); + } else { + try (Statement statement = createConnection("").createStatement()) { + boolean testQuerySucceeded = statement.execute(this.getTestQueryString()); + if (testQuerySucceeded) { + logger().info("Container is started (JDBC URL: {})", this.getJdbcUrl()); + return; } } catch (NoDriverFoundException e) { // we explicitly want this exception to fail fast without retries @@ -159,12 +159,12 @@ protected void waitUntilContainerStarted() { Thread.sleep(100L); } } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new ContainerLaunchException("Container startup wait was interrupted", e); } - logger().info("Container is started (JDBC URL: {})", JdbcDatabaseContainer.this.getJdbcUrl()); + throw new IllegalStateException( + String.format("Container is started, but cannot be accessed by (JDBC URL: %s), please check container logs", + this.getJdbcUrl()) + ); } @Override diff --git a/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java b/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java new file mode 100644 index 00000000000..9f0cf514558 --- /dev/null +++ b/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java @@ -0,0 +1,71 @@ +package org.testcontainers.containers; + +import java.sql.Connection; +import java.sql.SQLException; +import lombok.NonNull; +import org.junit.Test; +import org.slf4j.Logger; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.mock; + +public class JdbcDatabaseContainerTest { + + @Test + public void anExceptionIsThrownIfJdbcIsNotAvailable() { + JdbcDatabaseContainer jdbcContainer = new JdbcDatabaseContainerStub("mysql:latest") + .withStartupTimeoutSeconds(1); + + assertThatExceptionOfType(IllegalStateException.class).isThrownBy(jdbcContainer::waitUntilContainerStarted); + } + + static class JdbcDatabaseContainerStub extends JdbcDatabaseContainer { + + public JdbcDatabaseContainerStub(@NonNull String dockerImageName) { + super(dockerImageName); + } + + @Override + public String getDriverClassName() { + return null; + } + + @Override + public String getJdbcUrl() { + return null; + } + + @Override + public String getUsername() { + return null; + } + + @Override + public String getPassword() { + return null; + } + + @Override + protected String getTestQueryString() { + return null; + } + + @Override + public boolean isRunning() { + return true; + } + + @Override + public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException { + throw new SQLException("Could not create new connection"); + } + + @Override + protected Logger logger() { + return mock(Logger.class); + } + + @Override + public void setDockerImageName(@NonNull String dockerImageName) {} + } +} From 9c759abbb60d0d9b72aa711f35fee008ec4aa679 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:44:24 +0100 Subject: [PATCH 1214/4969] Bump s3 from 2.16.34 to 2.16.62 in /modules/localstack (#4102) Bumps s3 from 2.16.34 to 2.16.62. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 6fb69b1ad85..61d9271bad4 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.986' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.16.34' + testCompile 'software.amazon.awssdk:s3:2.16.62' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From dda77d61aa2a7d6f3d74d28e660088f98c5a2dd4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:44:51 +0100 Subject: [PATCH 1215/4969] Bump aws-java-sdk-sqs from 1.11.986 to 1.11.1018 in /modules/localstack (#4101) Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.986 to 1.11.1018. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.986...1.11.1018) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 61d9271bad4..15f34e28d76 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.930' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.986' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.1018' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.16.62' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 8c9feb706db98f12f48f2714927b9ac916cb093e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:45:05 +0100 Subject: [PATCH 1216/4969] Bump mysql-connector-java from 8.0.22 to 8.0.25 in /modules/jdbc-test (#4095) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.22 to 8.0.25. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.22...8.0.25) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 05a96aaf333..b7a81682e37 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -16,5 +16,5 @@ dependencies { compile 'org.apache.tomcat:tomcat-jdbc:9.0.40' compile 'org.vibur:vibur-dbcp:25.0' - compile 'mysql:mysql-connector-java:8.0.22' + compile 'mysql:mysql-connector-java:8.0.25' } From 264796da9d7bc567f8baacdbc4de2a620eba31a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:45:15 +0100 Subject: [PATCH 1217/4969] Bump pulsar-client-admin from 2.7.0 to 2.7.2 in /modules/pulsar (#4098) Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.7.0 to 2.7.2. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.7.0...v2.7.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index e189e7006eb..7604a6712a6 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.1' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.18.1' - testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.0' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' } From eb62a375c4f7e221b83a34959d68ac6908613539 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:45:23 +0100 Subject: [PATCH 1218/4969] Bump mockito-core from 3.6.28 to 3.10.0 in /core (#4100) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.6.28 to 3.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.6.28...v3.10.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 5c8e9fe875d..e7a2710b796 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -210,7 +210,7 @@ dependencies { testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' - testCompile ('org.mockito:mockito-core:3.6.28') { + testCompile ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 0bfcc10c2dff95fd47478d84c3a8ecfbc5adf716 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:45:45 +0100 Subject: [PATCH 1219/4969] Bump mockito-core from 3.6.28 to 3.10.0 in /modules/junit-jupiter (#4094) Bumps [mockito-core](https://github.com/mockito/mockito) from 3.6.28 to 3.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.6.28...v3.10.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 12d4321d10f..15a5d665ee0 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'com.zaxxer:HikariCP:3.4.5' testCompile 'redis.clients:jedis:3.3.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.13' - testCompile ('org.mockito:mockito-core:3.6.28') { + testCompile ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.18.1' From 83c4b823b93f16d03b99de3536c0c2da6415e136 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:45:53 +0100 Subject: [PATCH 1220/4969] Bump mysql-connector-java from 8.0.22 to 8.0.25 in /modules/spock (#4093) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.22 to 8.0.25. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.22...8.0.25) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index a095bcb8a80..d0665614b17 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.apache.httpcomponents:httpclient:4.5.13' testRuntime 'org.postgresql:postgresql:42.2.18' - testRuntime 'mysql:mysql-connector-java:8.0.22' + testRuntime 'mysql:mysql-connector-java:8.0.25' testCompileClasspath 'org.jetbrains:annotations:20.1.0' } From 3aa1b8a3b8bed2f92b21ebaa342c8114873887f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:46:01 +0100 Subject: [PATCH 1221/4969] Bump aws-java-sdk-dynamodb from 1.11.929 to 1.11.1018 in /modules/dynalite (#4091) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 3ac35862e1a..ea982a2d9ea 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.929' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1018' testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.929' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 992322b3437c8fc51fbf59992da92f9b58009c7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:46:22 +0100 Subject: [PATCH 1222/4969] Bump r2dbc-postgresql from 0.8.5.RELEASE to 0.8.8.RELEASE in /modules/postgresql (#4092) Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.5.RELEASE to 0.8.8.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.8.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.5.RELEASE...v0.8.8.RELEASE) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index b16ceaea2a8..f666394d733 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.8.RELEASE' testCompile project(':jdbc-test') testCompile project(':test-support') From 4ac8dedaae07c7051ea26a59dc3645298fb1d4a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:46:34 +0100 Subject: [PATCH 1223/4969] Bump mariadb-java-client from 2.7.0 to 2.7.3 in /modules/mariadb (#4090) Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.7.0 to 2.7.3. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/2.7.3/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.7.0...2.7.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 915e14eb7ee..1424d032020 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:1.0.0' testCompile project(':jdbc-test') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.7.0' + testCompile 'org.mariadb.jdbc:mariadb-java-client:2.7.3' testCompile testFixtures(project(':r2dbc')) testCompile 'org.mariadb:r2dbc-mariadb:1.0.0' From 24a2ec9db9090b406c642f82410c2ae257989452 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 12:46:58 +0000 Subject: [PATCH 1224/4969] Bump r2dbc-mariadb from 1.0.0 to 1.0.1 in /modules/mariadb Bumps [r2dbc-mariadb](https://github.com/mariadb-corporation/mariadb-connector-r2dbc) from 1.0.0 to 1.0.1. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/compare/1.0.0...1.0.1) Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 1424d032020..ae55575d421 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'org.mariadb:r2dbc-mariadb:1.0.0' + compileOnly 'org.mariadb:r2dbc-mariadb:1.0.1' testCompile project(':jdbc-test') testCompile 'org.mariadb.jdbc:mariadb-java-client:2.7.3' From 10056934e384c9fd2b40287f3e6e8109b460bda0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:52:16 +0100 Subject: [PATCH 1225/4969] Bump pulsar-client from 2.7.1 to 2.7.2 in /modules/pulsar (#4097) Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.7.1 to 2.7.2. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.7.1...v2.7.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 7604a6712a6..10fe90dadf9 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { compile project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.1' + testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.18.1' testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' } From ad348c4f7b2ff0bdf00043f09ff9f608005e1d59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:52:24 +0100 Subject: [PATCH 1226/4969] Bump r2dbc-mssql from 0.8.5.RELEASE to 0.8.6.RELEASE in /modules/mssqlserver (#4089) Bumps [r2dbc-mssql](https://github.com/r2dbc/r2dbc-mssql) from 0.8.5.RELEASE to 0.8.6.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-mssql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-mssql/blob/v0.8.6.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-mssql/compare/v0.8.5.RELEASE...v0.8.6.RELEASE) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index c36f1e6ba84..5471a3e3f68 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -7,7 +7,7 @@ dependencies { compile project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' + compileOnly 'io.r2dbc:r2dbc-mssql:0.8.6.RELEASE' testCompile project(':jdbc-test') testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.1.jre8-preview' From 4bcfbd7a7136394c5dd0682ddd30785562cc3ca4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:52:31 +0100 Subject: [PATCH 1227/4969] Bump testcontainers from 1.15.2 to 1.15.3 in /core (#4067) Bumps [testcontainers](https://github.com/testcontainers/testcontainers-java) from 1.15.2 to 1.15.3. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.15.2...1.15.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index e7a2710b796..cc62e5581c8 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -165,7 +165,7 @@ configurations.all { } dependencies { - baseline 'org.testcontainers:testcontainers:1.15.2', { + baseline 'org.testcontainers:testcontainers:1.15.3', { exclude group: "*", module: "*" } From 52af32194393374c623dff14811547e595bb9360 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:52:38 +0100 Subject: [PATCH 1228/4969] Bump transport from 7.10.1 to 7.12.1 in /modules/elasticsearch (#4050) Bumps [transport](https://github.com/elastic/elasticsearch) from 7.10.1 to 7.12.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.10.1...v7.12.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index f50b38bb568..fd3b99b491a 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.12.0" - testCompile "org.elasticsearch.client:transport:7.10.1" + testCompile "org.elasticsearch.client:transport:7.12.1" testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 16d330c28b0d68ee6f3bd8a1cf0ce43403f367f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:52:52 +0100 Subject: [PATCH 1229/4969] Bump junit-jupiter-api from 5.7.0 to 5.7.1 in /modules/junit-jupiter (#3770) Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.7.0 to 5.7.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.0...r5.7.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 15a5d665ee0..dc4650ada94 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.7.0' + compile 'org.junit.jupiter:junit-jupiter-api:5.7.1' testCompile project(':mysql') testCompile project(':postgresql') From e93cefd83cc775b116efc44f6963e8cf6819a82d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 13:52:59 +0100 Subject: [PATCH 1230/4969] Bump junit from 4.13.1 to 4.13.2 in /examples (#3794) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/mongodb-container/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 57b578a1607..8a4c727f069 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -8,6 +8,6 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' - testImplementation 'junit:junit:4.13.1' + testImplementation 'junit:junit:4.13.2' testCompileClasspath 'org.jetbrains:annotations:20.1.0' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 702ce023c6b..de1e2d8a0a8 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'junit:junit:4.13.1' + testImplementation 'junit:junit:4.13.2' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 4b6b23906d95c88cb76dff4cbfccfd8eedb4006d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:28:59 +0100 Subject: [PATCH 1231/4969] Bump junit-jupiter-params from 5.7.0 to 5.7.1 in /modules/junit-jupiter (#3769) Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.7.0 to 5.7.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.0...r5.7.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index dc4650ada94..7e1b17356ca 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } testCompile 'org.assertj:assertj-core:3.18.1' - testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' + testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.1' testRuntime 'org.postgresql:postgresql:42.2.18' testRuntime 'mysql:mysql-connector-java:8.0.22' From 6dd2475e88fbccb9976744425ad7749337b510c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:29:11 +0100 Subject: [PATCH 1232/4969] Bump org.jetbrains.kotlin.plugin.spring from 1.4.21-2 to 1.4.32 in /examples (#3946) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard North --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 8ffa1b46d2a..6810020f17d 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.4.1" id("org.jetbrains.kotlin.jvm") version "1.4.32" - id("org.jetbrains.kotlin.plugin.spring") version "1.4.21-2" + id("org.jetbrains.kotlin.plugin.spring") version "1.4.32" } apply plugin: 'io.spring.dependency-management' From c7bea124d433ebf6a10ee20363babb0103c0e99a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:29:25 +0100 Subject: [PATCH 1233/4969] Bump auto-service from 1.0-rc7 to 1.0 in /modules/mariadb (#3989) Bumps [auto-service](https://github.com/google/auto) from 1.0-rc7 to 1.0. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/commits/auto-value-1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mariadb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 1424d032020..c70dfb93bfd 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' - compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0' + compileOnly 'com.google.auto.service:auto-service:1.0' compile project(':jdbc') From e48b3550e65ccd7e8216d7484532dbbf5ed341d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:29:31 +0100 Subject: [PATCH 1234/4969] Bump auto-service from 1.0-rc7 to 1.0 in /modules/mysql (#3988) Bumps [auto-service](https://github.com/google/auto) from 1.0-rc7 to 1.0. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/commits/auto-value-1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 172ca29070d..5ac1ba945da 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' - compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0' + compileOnly 'com.google.auto.service:auto-service:1.0' compile project(':jdbc') From 36e2035a0d8a84be8e3256918282f7ca6bb49ac8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:29:37 +0100 Subject: [PATCH 1235/4969] Bump auto-service from 1.0-rc7 to 1.0 in /modules/postgresql (#3984) Bumps [auto-service](https://github.com/google/auto) from 1.0-rc7 to 1.0. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/commits/auto-value-1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/postgresql/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index f666394d733..e853387291f 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' - compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0' + compileOnly 'com.google.auto.service:auto-service:1.0' compile project(':jdbc') From 2a0de4457314ea157e2e76346f743193343dfab5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:29:50 +0100 Subject: [PATCH 1236/4969] Bump lombok from 1.18.16 to 1.18.20 in /examples (#3956) Bumps [lombok](https://github.com/rzwitserloot/lombok) from 1.18.16 to 1.18.20. - [Release notes](https://github.com/rzwitserloot/lombok/releases) - [Changelog](https://github.com/rzwitserloot/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/rzwitserloot/lombok/compare/v1.18.16...v1.18.20) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/disque-job-queue/build.gradle | 4 ++-- examples/kafka-cluster/build.gradle | 2 +- examples/solr-container/build.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 90bbdd6d6f9..82d1bb548ee 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,8 +7,8 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.16" - annotationProcessor "org.projectlombok:lombok:1.18.14" + compileOnly "org.projectlombok:lombok:1.18.20" + annotationProcessor "org.projectlombok:lombok:1.18.20" implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index db07c6859f3..491b5c2f214 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - testCompileOnly "org.projectlombok:lombok:1.18.10" + testCompileOnly "org.projectlombok:lombok:1.18.20" testAnnotationProcessor "org.projectlombok:lombok:1.18.10" testCompile 'org.testcontainers:kafka' testCompile 'org.apache.kafka:kafka-clients:2.3.1' diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 8c9fc2fcc11..b01d66ea9a9 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.16" + compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.16" implementation 'org.apache.solr:solr-solrj:8.7.0' From c69f6f8adb79b29cb4b4460a423f38f3757e0f8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:29:57 +0100 Subject: [PATCH 1237/4969] Bump json from 20201115 to 20210307 in /examples (#3884) Bumps [json](https://github.com/douglascrockford/JSON-java) from 20201115 to 20210307. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Commits](https://github.com/douglascrockford/JSON-java/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 5c7279dd09a..d3055dd3aa8 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.9.0' - implementation 'org.json:json:20201115' + implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.2.18' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' From 5a942431836957d92a6d7ab1686e83e18b5f7e7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:30:04 +0100 Subject: [PATCH 1238/4969] Bump commons-lang3 from 3.11 to 3.12.0 in /modules/jdbc-test (#3856) Bumps commons-lang3 from 3.11 to 3.12.0. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index b7a81682e37..3dd0d52f2e8 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -3,7 +3,7 @@ dependencies { compile project(':test-support') compile 'com.google.guava:guava:30.1-jre' - compile 'org.apache.commons:commons-lang3:3.11' + compile 'org.apache.commons:commons-lang3:3.12.0' compile 'com.zaxxer:HikariCP-java6:2.3.13' compile 'commons-dbutils:commons-dbutils:1.7' From c06520dbdb45bf51bc1ff7f3ac5c5adc360d4b07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 14:30:13 +0000 Subject: [PATCH 1239/4969] Bump kafka-clients from 2.6.0 to 2.8.0 in /modules/kafka Bumps kafka-clients from 2.6.0 to 2.8.0. Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 4454823bda4..db400c0b557 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { compile project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.6.0' + testCompile 'org.apache.kafka:kafka-clients:2.8.0' testCompile 'org.assertj:assertj-core:3.18.1' testCompile 'com.google.guava:guava:23.0' } From 858b1aa06e865d10451f47dd0042cbd5e0025265 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 14:30:23 +0000 Subject: [PATCH 1240/4969] Bump testng from 7.3.0 to 7.4.0 in /examples Bumps [testng](https://github.com/cbeust/testng) from 7.3.0 to 7.4.0. - [Release notes](https://github.com/cbeust/testng/releases) - [Changelog](https://github.com/cbeust/testng/blob/master/CHANGES.txt) - [Commits](https://github.com/cbeust/testng/compare/7.3.0...7.4.0) Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index d297f026323..42553843710 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' - testImplementation 'org.testng:testng:7.3.0' + testImplementation 'org.testng:testng:7.4.0' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From f5e88058f6bc775e73f63ee833734790aff706fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 15:30:33 +0100 Subject: [PATCH 1241/4969] Bump junit-jupiter-engine from 5.7.0 to 5.7.1 in /modules/junit-jupiter (#3768) Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.7.0 to 5.7.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.0...r5.7.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7e1b17356ca..70ba308092b 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.18' testRuntime 'mysql:mysql-connector-java:8.0.22' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.0' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.1' } test { From 0b8b301893532c10ec75d9e408260f9d7bfbdd0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 14:30:35 +0000 Subject: [PATCH 1242/4969] Bump okhttp from 4.9.0 to 4.9.1 in /examples Bumps [okhttp](https://github.com/square/okhttp) from 4.9.0 to 4.9.1. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.9.0...parent-4.9.1) Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index d3055dd3aa8..b3d339d4db8 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'com.squareup.okhttp3:okhttp:4.9.0' + implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.2.18' testImplementation 'ch.qos.logback:logback-classic:1.2.3' From 0a2dfc4c95fa73757d1741fb1e4ea79ac36da46d Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 20 May 2021 13:00:34 +0100 Subject: [PATCH 1243/4969] Allow DOCKER_HOST and related settings to be set in `~/.testcontainers.properties` (#4118) --- ...dSystemPropertyClientProviderStrategy.java | 29 +++++- .../utility/TestcontainersConfiguration.java | 23 ++++- ...temPropertyClientProviderStrategyTest.java | 91 +++++++++++++++++++ .../TestcontainersConfigurationTest.java | 23 ++++- docs/features/configuration.md | 15 ++- 5 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java diff --git a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java index e0afba9af93..e9bdbd90bea 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java @@ -2,10 +2,19 @@ import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientConfig; +import org.testcontainers.utility.TestcontainersConfiguration; + +import java.util.Optional; /** * Use environment variables and system properties (as supported by the underlying DockerClient DefaultConfigBuilder) * to try and locate a docker environment. + *

+ * Resolution order is: + *

    + *
  1. DOCKER_HOST env var
  2. + *
  3. docker.host in ~/.testcontainers.properties
  4. + *
* * @deprecated this class is used by the SPI and should not be used directly */ @@ -14,12 +23,26 @@ public final class EnvironmentAndSystemPropertyClientProviderStrategy extends Do public static final int PRIORITY = 100; - // Try using environment variables - private final DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); + private final DockerClientConfig dockerClientConfig; + + public EnvironmentAndSystemPropertyClientProviderStrategy() { + // use docker-java defaults if present, overridden if our own configuration is set + DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder(); + + getSetting("docker.host").ifPresent(configBuilder::withDockerHost); + getSetting("docker.tls.verify").ifPresent(configBuilder::withDockerTlsVerify); + getSetting("docker.cert.path").ifPresent(configBuilder::withDockerCertPath); + + dockerClientConfig = configBuilder.build(); + } + + private Optional getSetting(final String name) { + return Optional.ofNullable(TestcontainersConfiguration.getInstance().getEnvVarOrUserProperty(name, null)); + } @Override protected boolean isApplicable() { - return System.getenv("DOCKER_HOST") != null; + return getSetting("docker.host").isPresent(); } @Override diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 3b4d9f8f70c..9b2ab707a2e 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -168,7 +168,11 @@ public boolean environmentSupportsReuse() { } public String getDockerClientStrategyClassName() { - return getEnvVarOrUserProperty("docker.client.strategy", null); + // getConfigurable won't apply the TESTCONTAINERS_ prefix when looking for env vars if DOCKER_ appears at the beginning. + // Because of this overlap, and the desire to not change this specific TESTCONTAINERS_DOCKER_CLIENT_STRATEGY setting, + // we special-case the logic here so that docker.client.strategy is used when reading properties files and + // TESTCONTAINERS_DOCKER_CLIENT_STRATEGY is used when searching environment variables. + return getEnvVarOrUserProperty("docker.client.strategy", environment.get("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY")); } public String getTransportType() { @@ -187,7 +191,7 @@ public String getImageSubstitutorClassName() { @Contract("_, !null, _ -> !null") private String getConfigurable(@NotNull final String propertyName, @Nullable final String defaultValue, Properties... propertiesSources) { String envVarName = propertyName.replaceAll("\\.", "_").toUpperCase(); - if (!envVarName.startsWith("TESTCONTAINERS_")) { + if (!envVarName.startsWith("TESTCONTAINERS_") && !envVarName.startsWith("DOCKER_")) { envVarName = "TESTCONTAINERS_" + envVarName; } @@ -208,6 +212,10 @@ private String getConfigurable(@NotNull final String propertyName, @Nullable fin * Gets a configured setting from an environment variable (if present) or a configuration file property otherwise. * The configuration file will be the .testcontainers.properties file in the user's home directory or * a testcontainers.properties found on the classpath. + *

+ * Note that when searching environment variables, the prefix `TESTCONTAINERS_` will usually be applied to the + * property name, which will be converted to upper-case with underscore separators. This prefix will not be added + * if the property name begins `docker.`. * * @param propertyName name of configuration file property (dot-separated lower case) * @return the found value, or null if not set @@ -220,6 +228,10 @@ public String getEnvVarOrProperty(@NotNull final String propertyName, @Nullable /** * Gets a configured setting from an environment variable (if present) or a configuration file property otherwise. * The configuration file will be the .testcontainers.properties file in the user's home directory. + *

+ * Note that when searching environment variables, the prefix `TESTCONTAINERS_` will usually be applied to the + * property name, which will be converted to upper-case with underscore separators. This prefix will not be added + * if the property name begins `docker.`. * * @param propertyName name of configuration file property (dot-separated lower case) * @return the found value, or null if not set @@ -230,8 +242,11 @@ public String getEnvVarOrUserProperty(@NotNull final String propertyName, @Nulla } /** - * Gets a configured setting from a the user's configuration file. - * The configuration file will be the .testcontainers.properties file in the user's home directory. + * Gets a configured setting from an environment variable. + *

+ * Note that when searching environment variables, the prefix `TESTCONTAINERS_` will usually be applied to the + * property name, which will be converted to upper-case with underscore separators. This prefix will not be added + * if the property name begins `docker.`. * * @param propertyName name of configuration file property (dot-separated lower case) * @return the found value, or null if not set diff --git a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java new file mode 100644 index 00000000000..91f61848d69 --- /dev/null +++ b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java @@ -0,0 +1,91 @@ +package org.testcontainers.dockerclient; + +import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.LocalDirectorySSLConfig; +import com.github.dockerjava.transport.SSLConfig; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.testcontainers.utility.MockTestcontainersConfigurationRule; +import org.testcontainers.utility.TestcontainersConfiguration; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; + +/** + * Test that we can use Testcontainers configuration file to override settings. We assume that docker-java has test + * coverage for detection of environment variables (e.g. DOCKER_HOST) and its own properties config file. + */ +@RunWith(MockitoJUnitRunner.class) +public class EnvironmentAndSystemPropertyClientProviderStrategyTest { + + @Rule + public MockTestcontainersConfigurationRule mockConfig = new MockTestcontainersConfigurationRule(); + private URI defaultDockerHost; + private com.github.dockerjava.core.SSLConfig defaultSSLConfig; + + @Before + public void checkEnvironmentClear() { + // If docker-java picks up non-default settings from the environment, our test needs to know to expect those + DefaultDockerClientConfig defaultConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); + defaultDockerHost = defaultConfig.getDockerHost(); + defaultSSLConfig = defaultConfig.getSSLConfig(); + } + + @Test + public void testWhenConfigAbsent() { + Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); + Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); + Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); + + EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); + + TransportConfig transportConfig = strategy.getTransportConfig(); + assertEquals(defaultDockerHost, transportConfig.getDockerHost()); + assertEquals(defaultSSLConfig, transportConfig.getSslConfig()); + } + + @Test + public void testWhenDockerHostPresent() { + Mockito.doReturn("tcp://1.2.3.4:2375").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); + Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); + Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); + + EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); + + TransportConfig transportConfig = strategy.getTransportConfig(); + assertEquals("tcp://1.2.3.4:2375", transportConfig.getDockerHost().toString()); + assertEquals(defaultSSLConfig, transportConfig.getSslConfig()); + } + + @Test + public void testWhenDockerHostAndSSLConfigPresent() throws IOException { + Path tempDir = Files.createTempDirectory("testcontainers-test"); + String tempDirPath = tempDir.toAbsolutePath().toString(); + + Mockito.doReturn("tcp://1.2.3.4:2375").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); + Mockito.doReturn("1").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); + Mockito.doReturn(tempDirPath).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); + + EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); + + TransportConfig transportConfig = strategy.getTransportConfig(); + assertEquals("tcp://1.2.3.4:2375", transportConfig.getDockerHost().toString()); + + SSLConfig sslConfig = transportConfig.getSslConfig(); + assertNotNull(sslConfig); + assertTrue(sslConfig instanceof LocalDirectorySSLConfig); + assertEquals(tempDirPath, ((LocalDirectorySSLConfig) sslConfig).getDockerCertPath()); + } +} diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index e5300bce58d..0fca36f0f2f 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -113,6 +113,27 @@ public void shouldReadChecksFromEnvironment() { assertTrue("checks disabled via env var", newConfig().isDisableChecks()); } + @Test + public void shouldReadDockerSettingsFromEnvironmentWithoutTestcontainersPrefix() { + userProperties.remove("docker.foo"); + environment.put("DOCKER_FOO", "some value"); + assertEquals("reads unprefixed env vars for docker. settings", "some value", newConfig().getEnvVarOrUserProperty("docker.foo", "default")); + } + + @Test + public void shouldNotReadDockerSettingsFromEnvironmentWithTestcontainersPrefix() { + userProperties.remove("docker.foo"); + environment.put("TESTCONTAINERS_DOCKER_FOO", "some value"); + assertEquals("reads unprefixed env vars for docker. settings", "default", newConfig().getEnvVarOrUserProperty("docker.foo", "default")); + } + + @Test + public void shouldReadDockerSettingsFromUserProperties() { + environment.remove("DOCKER_FOO"); + userProperties.put("docker.foo", "some value"); + assertEquals("reads unprefixed user properties for docker. settings", "some value", newConfig().getEnvVarOrUserProperty("docker.foo", "default")); + } + @Test public void shouldNotReadDockerClientStrategyFromClasspathProperties() { String currentValue = newConfig().getDockerClientStrategyClassName(); @@ -129,7 +150,7 @@ public void shouldReadDockerClientStrategyFromUserProperties() { @Test public void shouldReadDockerClientStrategyFromEnvironment() { - userProperties.remove("docker.client.strategy"); + userProperties.remove("docker.client.strategy"); environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "foo"); assertEquals("Docker client strategy is changed by env var", "foo", newConfig().getDockerClientStrategyClassName()); } diff --git a/docs/features/configuration.md b/docs/features/configuration.md index da7bbd82d60..2336ec840c5 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -96,9 +96,9 @@ but does not allow starting privileged containers, you can turn off the Ryuk con ## Customizing Docker host detection -Testcontainers will attempt to detect the Docker environment and configure everything. +Testcontainers will attempt to detect the Docker environment and configure everything to work automatically. -However, sometimes a customization is required. For that, you can provide the following environment variables: +However, sometimes customization is required. Testcontainers will respect the following **environment variables**: > **DOCKER_HOST** = unix:///var/run/docker.sock > See [Docker environment variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables) @@ -110,3 +110,14 @@ However, sometimes a customization is required. For that, you can provide the fo > **TESTCONTAINERS_HOST_OVERRIDE** > Docker's host on which ports are exposed. > Example: `docker.svc.local` + +For advanced users, the Docker host connection can be configured **via configuration** in `~/.testcontainers.properties`. +Note that these settings require use of the `EnvironmentAndSystemPropertyClientProviderStrategy`. The example below +illustrates usage: + +```properties +docker.client.strategy=org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy +docker.host=tcp\://my.docker.host\:1234 # Equivalent to the DOCKER_HOST environment variable. Colons should be escaped. +docker.tls.verify=1 # Equivalent to the DOCKER_TLS_VERIFY environment variable +docker.cert.path=/some/path # Equivalent to the DOCKER_CERT_PATH environment variable +``` From 426c6239187c596651b6e40842dd08665fff02a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 May 2021 10:54:02 +0100 Subject: [PATCH 1244/4969] Bump postgresql from 42.2.18 to 42.2.20 in /modules/junit-jupiter (#4032) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 70ba308092b..69e13138e2a 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testCompile 'org.assertj:assertj-core:3.18.1' testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.1' - testRuntime 'org.postgresql:postgresql:42.2.18' + testRuntime 'org.postgresql:postgresql:42.2.20' testRuntime 'mysql:mysql-connector-java:8.0.22' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.1' } From e2b0e3c0327e7c8d787925337fed5a0defc42d58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:57:43 +0100 Subject: [PATCH 1245/4969] Bump org.jetbrains.kotlin.plugin.spring from 1.4.32 to 1.5.0 in /examples (#4115) Bumps org.jetbrains.kotlin.plugin.spring from 1.4.32 to 1.5.0. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 6810020f17d..6fb7b4c1d24 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.4.1" id("org.jetbrains.kotlin.jvm") version "1.4.32" - id("org.jetbrains.kotlin.plugin.spring") version "1.4.32" + id("org.jetbrains.kotlin.plugin.spring") version "1.5.0" } apply plugin: 'io.spring.dependency-management' From bdbe1a457248a1d1b7fab8f22ef24279e63dca9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:57:58 +0100 Subject: [PATCH 1246/4969] Bump elasticsearch-rest-client from 7.12.0 to 7.12.1 in /modules/elasticsearch (#4049) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index fd3b99b491a..b7fbda347a1 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.12.0" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.12.1" testCompile "org.elasticsearch.client:transport:7.12.1" testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From f01d0e5f91da28cffaae4189eef00912a8bc0ade Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:58:05 +0100 Subject: [PATCH 1247/4969] Bump mssql-jdbc from 9.1.1.jre8-preview to 9.3.1.jre8-preview in /modules/mssqlserver (#4048) Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 9.1.1.jre8-preview to 9.3.1.jre8-preview. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/dev/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 5471a3e3f68..10699e508e5 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,12 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.6.RELEASE' testCompile project(':jdbc-test') - testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.1.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' testCompile project(':r2dbc') testCompile 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' // MSSQL's wait strategy requires the JDBC driver testCompile testFixtures(project(':r2dbc')) - testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.1.1.jre8-preview' + testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' } From 4735b7441ecd975e4fcafb8e02ca54fd9946dad0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:58:16 +0100 Subject: [PATCH 1248/4969] Bump jedis from 3.4.0 to 3.6.0 in /core (#4019) Bumps [jedis](https://github.com/redis/jedis) from 3.4.0 to 3.6.0. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.4.0...jedis-3.6.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index cc62e5581c8..059202e1b41 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -206,7 +206,7 @@ dependencies { } testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testCompile 'redis.clients:jedis:3.4.0' + testCompile 'redis.clients:jedis:3.6.0' testCompile 'com.rabbitmq:amqp-client:5.9.0' testCompile 'org.mongodb:mongo-java-driver:3.12.7' From 5b4609a406ef1c353f0ba651c019c5f16ef283c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:58:29 +0100 Subject: [PATCH 1249/4969] Bump jedis from 3.3.0 to 3.6.0 in /modules/junit-jupiter (#4028) Bumps [jedis](https://github.com/redis/jedis) from 3.3.0 to 3.6.0. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.3.0...jedis-3.6.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 69e13138e2a..99789bf2721 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') testCompile 'com.zaxxer:HikariCP:3.4.5' - testCompile 'redis.clients:jedis:3.3.0' + testCompile 'redis.clients:jedis:3.6.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.13' testCompile ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') From e86454a7b71b2c4c6431fc3d604e913040e43361 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:58:39 +0100 Subject: [PATCH 1250/4969] Bump auto-service from 1.0-rc7 to 1.0 in /modules/mssqlserver (#3983) Bumps [auto-service](https://github.com/google/auto) from 1.0-rc7 to 1.0. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/commits/auto-value-1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 10699e508e5..143a6582ae1 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: MS SQL Server" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' - compileOnly 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0' + compileOnly 'com.google.auto.service:auto-service:1.0' compile project(':jdbc') From 1719cf5a5840bf3ee8f1575c4004d2b991e78fad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:58:49 +0100 Subject: [PATCH 1251/4969] Bump solr-solrj from 8.7.0 to 8.8.2 in /examples (#4005) Bumps solr-solrj from 8.7.0 to 8.8.2. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index b01d66ea9a9..e0a6f356a77 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.16" - implementation 'org.apache.solr:solr-solrj:8.7.0' + implementation 'org.apache.solr:solr-solrj:8.8.2' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From cd91b0e4f824e9bb215b5caffabbdf13125de078 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:58:59 +0100 Subject: [PATCH 1252/4969] Bump HikariCP from 3.4.5 to 4.0.3 in /modules/spock (#3857) Bumps [HikariCP](https://github.com/brettwooldridge/HikariCP) from 3.4.5 to 4.0.3. - [Release notes](https://github.com/brettwooldridge/HikariCP/releases) - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-3.4.5...HikariCP-4.0.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index d0665614b17..07ac5c7ce3b 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -12,7 +12,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.5' + testCompile 'com.zaxxer:HikariCP:4.0.3' testCompile 'org.apache.httpcomponents:httpclient:4.5.13' testRuntime 'org.postgresql:postgresql:42.2.18' From e83895fde8dfd851d8c487e0595d7e4d17a95277 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 19:59:18 +0100 Subject: [PATCH 1253/4969] Bump mysql-connector-java from 8.0.22 to 8.0.25 in /modules/mysql (#4086) Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.22 to 8.0.25. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.22...8.0.25) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 5ac1ba945da..c6823e247d4 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testCompile project(':jdbc-test') - testCompile 'mysql:mysql-connector-java:8.0.22' + testCompile 'mysql:mysql-connector-java:8.0.25' testCompile testFixtures(project(':r2dbc')) testCompile 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' From 73d7fd0f28b03c434c24d57c4e0af16e98259c26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 20:00:48 +0100 Subject: [PATCH 1254/4969] Bump assertj-core from 3.18.1 to 3.19.0 in /modules/neo4j (#3716) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.1 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.1...assertj-core-3.19.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 9aab6b18298..722e5474388 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { compile project(":testcontainers") testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.18.1' + testCompile 'org.assertj:assertj-core:3.19.0' } From 3167adc033ac3e1d2cf050e1ef83c2b9bc43afb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 20:00:55 +0100 Subject: [PATCH 1255/4969] Bump assertj-core from 3.18.1 to 3.19.0 in /modules/vault (#3722) Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.1 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.1...assertj-core-3.19.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index e75d1121131..72dc2811292 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testCompile 'com.bettercloud:vault-java-driver:5.1.0' testCompile 'io.rest-assured:rest-assured:4.3.3' - testCompile 'org.assertj:assertj-core:3.18.1' + testCompile 'org.assertj:assertj-core:3.19.0' } From 96b2065f27b259530766d968f12339e64b980bc9 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 26 May 2021 06:55:18 +0100 Subject: [PATCH 1256/4969] Only publish exposed ports (#4122) --- .../containers/GenericContainer.java | 107 ++++++++++-------- .../containers/GenericContainerTest.java | 61 +++++++++- .../containers/ClickHouseContainer.java | 6 +- .../couchbase/CouchbaseContainer.java | 13 +++ .../containers/MariaDBContainer.java | 7 +- .../containers/MSSQLServerContainer.java | 6 +- .../containers/OracleContainer.java | 6 +- 7 files changed, 147 insertions(+), 59 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index e53af6240ab..10f8e1e7195 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1,8 +1,5 @@ package org.testcontainers.containers; -import static com.google.common.collect.Lists.newArrayList; -import static org.testcontainers.utility.CommandLine.runShellCommand; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializationFeature; @@ -16,6 +13,7 @@ import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Link; import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.api.model.VolumesFrom; import com.github.dockerjava.core.DefaultDockerClientConfig; @@ -23,39 +21,6 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.hash.Hashing; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.UndeclaredThrowableException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.zip.Adler32; -import java.util.zip.Checksum; import lombok.AccessLevel; import lombok.Data; import lombok.NonNull; @@ -97,6 +62,43 @@ import org.testcontainers.utility.ResourceReaper; import org.testcontainers.utility.TestcontainersConfiguration; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.Adler32; +import java.util.zip.Checksum; + +import static com.google.common.collect.Lists.newArrayList; +import static org.testcontainers.utility.CommandLine.runShellCommand; + /** * Base class for that allows a container to be launched and controlled. */ @@ -718,21 +720,28 @@ public Set getLivenessCheckPortNumbers() { private void applyConfiguration(CreateContainerCmd createCommand) { HostConfig hostConfig = buildHostConfig(); - createCommand.withHostConfig(hostConfig); - - // Set up exposed ports (where there are no host port bindings defined) - ExposedPort[] portArray = exposedPorts.stream() - .map(ExposedPort::new) - .toArray(ExposedPort[]::new); - createCommand.withExposedPorts(portArray); + // PortBindings must contain: + // * all exposed ports with a randomized host port (equivalent to -p CONTAINER_PORT) + // * all exposed ports with a fixed host port (equivalent to -p HOST_PORT:CONTAINER_PORT) + Map allPortBindings = new HashMap<>(); + // First collect all the randomized host ports from our 'exposedPorts' field + for (final Integer tcpPort : exposedPorts) { + ExposedPort exposedPort = ExposedPort.tcp(tcpPort); + allPortBindings.put(exposedPort, new PortBinding(Ports.Binding.empty(), exposedPort)); + } + // Next collect all the fixed host ports from our 'portBindings' field, overwriting any randomized ports so that + // we don't create two bindings for the same container port. + for (final String portBinding : portBindings) { + PortBinding parsedBinding = PortBinding.parse(portBinding); + allPortBindings.put(parsedBinding.getExposedPort(), parsedBinding); + } + hostConfig.withPortBindings(new ArrayList<>(allPortBindings.values())); - // Set up exposed ports that need host port bindings - PortBinding[] portBindingArray = portBindings.stream() - .map(PortBinding::parse) - .toArray(PortBinding[]::new); + // Next, ExposedPorts must be set up to publish all of the above ports, both randomized and fixed. + createCommand.withExposedPorts(new ArrayList<>(allPortBindings.keySet())); - createCommand.withPortBindings(portBindingArray); + createCommand.withHostConfig(hostConfig); if (commandParts != null) { createCommand.withCmd(commandParts); @@ -798,8 +807,6 @@ private void applyConfiguration(CreateContainerCmd createCommand) { createCommand.withNetworkMode(networkForLinks.get()); } - createCommand.withPublishAllPorts(true); - PortForwardingContainer.INSTANCE.getNetwork().ifPresent(it -> { withExtraHost(INTERNAL_HOST_HOSTNAME, it.getIpAddress()); }); diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index e059a48709f..1e2cb041cf1 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -1,8 +1,12 @@ package org.testcontainers.containers; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.command.InspectContainerResponse.ContainerState; +import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.api.model.Ports; +import com.google.common.primitives.Ints; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -11,15 +15,23 @@ import org.assertj.core.api.Assumptions; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; -import org.testcontainers.TestImages; import org.testcontainers.DockerClientFactory; +import org.testcontainers.TestImages; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; +import org.testcontainers.images.builder.ImageFromDockerfile; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; +import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class GenericContainerTest { @@ -60,6 +72,53 @@ public void shouldReportErrorAfterWait() { } } + @Test + public void shouldOnlyPublishExposedPorts() { + ImageFromDockerfile image = new ImageFromDockerfile("publish-multiple") + .withDockerfileFromBuilder(builder -> + builder + .from("testcontainers/helloworld:1.1.0") + .expose(8080, 8081) + .build() + ); + try (GenericContainer container = new GenericContainer<>(image).withExposedPorts(8080)) { + container.start(); + + InspectContainerResponse inspectedContainer = container.getContainerInfo(); + + List exposedPorts = Arrays.stream(inspectedContainer.getConfig().getExposedPorts()) + .map(ExposedPort::getPort) + .collect(Collectors.toList()); + + assertEquals( + "the exposed ports are all of those EXPOSEd by the image", + Ints.asList(8080, 8081), + exposedPorts + ); + + Map hostBindings = inspectedContainer.getHostConfig().getPortBindings().getBindings(); + assertEquals( + "only 1 port is bound on the host (published)", + 1, + hostBindings.size() + ); + + Integer mappedPort = container.getMappedPort(8080); + assertTrue( + "port 8080 is bound to a different port on the host", + mappedPort != 8080 + ); + + assertThrows( + "trying to get a non-bound port mapping fails", + IllegalArgumentException.class, + () -> { + container.getMappedPort(8081); + } + ); + } + } + static class NoopStartupCheckStrategy extends StartupCheckStrategy { @Override diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index e26ca8c8416..9b5f130a323 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -1,9 +1,11 @@ package org.testcontainers.containers; +import com.google.common.collect.Sets; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.DockerImageName; import java.time.Duration; +import java.util.Set; public class ClickHouseContainer extends JdbcDatabaseContainer { public static final String NAME = "clickhouse"; @@ -54,8 +56,8 @@ public ClickHouseContainer(final DockerImageName dockerImageName) { } @Override - protected Integer getLivenessCheckPort() { - return getMappedPort(HTTP_PORT); + public Set getLivenessCheckPortNumbers() { + return Sets.newHashSet(HTTP_PORT); } @Override diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 3671608d324..8df5844f538 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -166,6 +166,19 @@ public String getConnectionString() { protected void configure() { super.configure(); + addExposedPorts( + MGMT_PORT, + MGMT_SSL_PORT, + VIEW_PORT, + VIEW_SSL_PORT, + QUERY_PORT, + QUERY_SSL_PORT, + SEARCH_PORT, + SEARCH_SSL_PORT, + KV_PORT, + KV_SSL_PORT + ); + WaitAllStrategy waitStrategy = new WaitAllStrategy(); // Makes sure that all nodes in the cluster are healthy. diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index b43a5f237e5..2e28e5d0480 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -1,7 +1,10 @@ package org.testcontainers.containers; +import com.google.common.collect.Sets; import org.testcontainers.utility.DockerImageName; +import java.util.Set; + /** * Container implementation for the MariaDB project. * @@ -51,8 +54,8 @@ public MariaDBContainer(final DockerImageName dockerImageName) { } @Override - protected Integer getLivenessCheckPort() { - return getMappedPort(MARIADB_PORT); + public Set getLivenessCheckPortNumbers() { + return Sets.newHashSet(MARIADB_PORT); } @Override diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index a20c60fd2dc..ecccc320b28 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -1,8 +1,10 @@ package org.testcontainers.containers; +import com.google.common.collect.Sets; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.LicenseAcceptance; +import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -60,8 +62,8 @@ public MSSQLServerContainer(final DockerImageName dockerImageName) { } @Override - protected Integer getLivenessCheckPort() { - return getMappedPort(MS_SQL_SERVER_PORT); + public Set getLivenessCheckPortNumbers() { + return Sets.newHashSet(MS_SQL_SERVER_PORT); } @Override diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index 0a66ad6fd27..2573ef722e3 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -1,8 +1,10 @@ package org.testcontainers.containers; +import com.google.common.collect.Sets; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.TestcontainersConfiguration; +import java.util.Set; import java.util.concurrent.Future; /** @@ -61,8 +63,8 @@ private void preconfigure() { } @Override - protected Integer getLivenessCheckPort() { - return getMappedPort(ORACLE_PORT); + public Set getLivenessCheckPortNumbers() { + return Sets.newHashSet(ORACLE_PORT); } @Override From 841ce8e6bec55b1d9717c2c6e60a0df5290f4859 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 05:08:45 +0000 Subject: [PATCH 1257/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.5.0 to 1.5.10. Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 6fb7b4c1d24..6617e830e8b 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.4.1" id("org.jetbrains.kotlin.jvm") version "1.4.32" - id("org.jetbrains.kotlin.plugin.spring") version "1.5.0" + id("org.jetbrains.kotlin.plugin.spring") version "1.5.10" } apply plugin: 'io.spring.dependency-management' From 8289f3a21d1f2262952faf302ed0950442c5b78f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 05:09:35 +0000 Subject: [PATCH 1258/4969] Bump rest-assured from 4.3.3 to 4.4.0 in /modules/vault Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 4.3.3 to 4.4.0. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-4.3.3...rest-assured-4.4.0) Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 72dc2811292..17edbd3f3fd 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { compile project(':testcontainers') testCompile 'com.bettercloud:vault-java-driver:5.1.0' - testCompile 'io.rest-assured:rest-assured:4.3.3' + testCompile 'io.rest-assured:rest-assured:4.4.0' testCompile 'org.assertj:assertj-core:3.19.0' } From d992d127fd8bcc1b5fda02a004ca132963ab4f03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 05:11:22 +0000 Subject: [PATCH 1259/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.1018 to 1.11.1030. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.1018...1.11.1030) Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index ea982a2d9ea..58a16a0b62b 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Dynalite" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1018' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.929' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' + testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From ae2d57934e635df1ed8e20a5d89a02a521dd1fd9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 05:11:42 +0000 Subject: [PATCH 1260/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.12.1 to 7.13.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.12.1...v7.13.0) Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index b7fbda347a1..21db8e69545 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.12.1" + testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.13.0" testCompile "org.elasticsearch.client:transport:7.12.1" testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From b82fa09c00c8cfe40748e93b1a4ddc433da48206 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 05:11:49 +0000 Subject: [PATCH 1261/4969] Bump aws-java-sdk-s3 from 1.11.930 to 1.11.1030 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.930 to 1.11.1030. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.930...1.11.1030) Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 15f34e28d76..e6a6340f686 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { compile project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.930' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.929' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.1030' + testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.1018' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.16.62' From 371125469210d1de9d3e602dced904350ce8df35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 05:30:06 +0000 Subject: [PATCH 1262/4969] Bump actions/setup-java from 1 to 2.1.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 1 to 2.1.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v1...v2.1.0) Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index cea7180566d..e3f540065e3 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -15,7 +15,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' - name: Cache Gradle Home files @@ -42,7 +42,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' - name: Cache Gradle Home files diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f49b6426a2e..727c89f22f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' - name: Cache Gradle Home files @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' - name: Cache Gradle Home files From 69ead41b3d4fff61b4a1fe891b5f80335affae49 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 7 Jun 2021 00:27:24 +0200 Subject: [PATCH 1263/4969] Add @oleg-nenashev as backer, reference @jenkinsci and @cloudbees as adopters (#4170) --- docs/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/index.md b/docs/index.md index e58a23bc330..139cbcd3f4e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -139,6 +139,7 @@ A huge thank you to our sponsors: * [Pascal Zwick (@pas2al)](https://github.com/pas2al) * [Nikita Zhevnitskiy (@zhenik)](https://github.com/zhenik) * [Bas Stoker (@bastoker)](https://github.com/bastoker) +* [Oleg Nenashev (@oleg-nenashev)](https://github.com/oleg-nenashev) ## Who is using Testcontainers? @@ -173,6 +174,9 @@ A huge thank you to our sponsors: * [Trino (formerly Presto SQL)](https://trino.io) - Integration testing all Trino core & connectors, including tests of multi-node deployments and security configurations. * Google - Various open source projects: [OpenTelemetry](https://github.com/GoogleCloudPlatform/opentelemetry-operations-java), [Universal Application Tool](https://github.com/seattle-uat/universal-application-tool), [CloudBowl](https://github.com/GoogleCloudPlatform/cloudbowl-microservice-game) * [Backbase](https://www.backbase.com/) - Unit, Integration and Acceptance testing for different the databases supported (Oracle, SQL Server, MySQL), the different messaging systems supported (Kafka, Rabbit, AMQ) and other microservices and HTTP mocks. +* [CloudBees](https://www.cloudbees.com/) - Integration testing of products, including but not limited to database and AWS/Localstack integration testing. +* [Jenkins](https://www.jenkins.io/) - Integration testing of multiple plugins and the Trilead SSH2 fork maintained by the Jenkins community + ([query](https://github.com/search?l=Maven+POM&q=org%3Ajenkinsci+testcontainers&type=Code)). ## License From b4bafc9a039aa0adf865c33293b89d7fdbe01846 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 7 Jun 2021 09:16:15 +0100 Subject: [PATCH 1264/4969] Combined dependencies PR (#4135) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/database-commons/build.gradle | 2 +- modules/jdbc/build.gradle | 2 +- modules/junit-jupiter/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index dacd8a500ac..0eecc1844d0 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { compile project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.18.1' + testCompile 'org.assertj:assertj-core:3.19.0' } diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 8f2d8954985..992f7611de4 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:20.1.0' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:10.0.0' + testCompile 'org.apache.tomcat:tomcat-jdbc:10.0.6' testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 99789bf2721..393c4cac653 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.20' testRuntime 'mysql:mysql-connector-java:8.0.22' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.1' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } test { From 57f4802095e73a25266b827dc357fbd71521f0aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 08:39:30 +0000 Subject: [PATCH 1265/4969] Bump annotations from 20.1.0 to 21.0.1 in /modules/spock Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 07ac5c7ce3b..8c065e389cd 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -18,7 +18,7 @@ dependencies { testRuntime 'org.postgresql:postgresql:42.2.18' testRuntime 'mysql:mysql-connector-java:8.0.25' - testCompileClasspath 'org.jetbrains:annotations:20.1.0' + testCompileClasspath 'org.jetbrains:annotations:21.0.1' } sourceJar { From 1c1bc81de3810a1a5c1417c3cd00842a452b314b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 08:39:41 +0000 Subject: [PATCH 1266/4969] Bump annotations from 20.1.0 to 21.0.1 in /modules/mysql Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index c6823e247d4..91a7d2c9918 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -15,5 +15,5 @@ dependencies { testCompile testFixtures(project(':r2dbc')) testCompile 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' - compileOnly 'org.jetbrains:annotations:20.1.0' + compileOnly 'org.jetbrains:annotations:21.0.1' } From 80491db9816e6afa8406b4aef1626ae23849c2fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 08:44:39 +0000 Subject: [PATCH 1267/4969] Bump assertj-core from 3.16.1 to 3.19.0 in /modules/jdbc Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.16.1 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.16.1...assertj-core-3.19.0) Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 992f7611de4..2741a348f34 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -11,5 +11,5 @@ dependencies { testCompile 'com.zaxxer:HikariCP-java6:2.3.13' testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testCompile 'org.assertj:assertj-core:3.16.1' + testCompile 'org.assertj:assertj-core:3.19.0' } From 9a3bff0b3ecb55ca45eca292515c1410b2c606fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 14:29:12 +0100 Subject: [PATCH 1268/4969] Bump actions/cache from 2.1.3 to 2.1.6 (#4162) Bumps [actions/cache](https://github.com/actions/cache) from 2.1.3 to 2.1.6. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.3...v2.1.6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index cea7180566d..d3b9f7811a2 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -19,7 +19,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v2.1.3 + uses: actions/cache@v2.1.6 continue-on-error: true with: path: ~/.gradle/caches @@ -46,7 +46,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v2.1.3 + uses: actions/cache@v2.1.6 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f49b6426a2e..409aff3da98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v2.1.3 + uses: actions/cache@v2.1.6 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -44,7 +44,7 @@ jobs: with: java-version: '1.8' - name: Cache Gradle Home files - uses: actions/cache@v2.1.3 + uses: actions/cache@v2.1.6 continue-on-error: true with: path: ~/.gradle/caches From 3844712431165501f9238cc30a6c6d7c34fb64fa Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 8 Jun 2021 14:31:27 +0100 Subject: [PATCH 1269/4969] Add `distribution` config to fix build --- .github/workflows/ci-examples.yml | 2 ++ .github/workflows/ci.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index e3f540065e3..cd696de7edd 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -18,6 +18,7 @@ jobs: - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' + distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 continue-on-error: true @@ -45,6 +46,7 @@ jobs: - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' + distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 continue-on-error: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 727c89f22f4..0bc9d517322 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,7 @@ jobs: - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' + distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 with: @@ -43,6 +44,7 @@ jobs: - uses: actions/setup-java@v2.1.0 with: java-version: '1.8' + distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 continue-on-error: true From 669cc53419c30b7d211f44fb93802a34729b8c20 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 8 Jun 2021 16:55:01 +0100 Subject: [PATCH 1270/4969] Change java-version format --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index cd696de7edd..83c74833563 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.1.0 with: - java-version: '1.8' + java-version: '8.0.292+10' distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 @@ -45,7 +45,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.1.0 with: - java-version: '1.8' + java-version: '8.0.292+10' distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bc9d517322..a84b9fa6723 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.1.0 with: - java-version: '1.8' + java-version: '8.0.292+10' distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 @@ -43,7 +43,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.1.0 with: - java-version: '1.8' + java-version: '8.0.292+10' distribution: adopt-hotspot - name: Cache Gradle Home files uses: actions/cache@v2.1.3 From 24610cbae71b3d27f9df1ae64678ee0c6012331e Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 8 Jun 2021 17:11:21 +0100 Subject: [PATCH 1271/4969] Add combine-prs workflow (#4176) --- .github/workflows/combine-prs.yml | 139 ++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 .github/workflows/combine-prs.yml diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml new file mode 100644 index 00000000000..b4a89055446 --- /dev/null +++ b/.github/workflows/combine-prs.yml @@ -0,0 +1,139 @@ +name: 'Combine PRs' + +# Controls when the action will run - in this case triggered manually +on: + workflow_dispatch: + inputs: + branchPrefix: + description: 'Branch prefix to find combinable PRs based on' + required: true + default: 'dependabot' + mustBeGreen: + description: 'Only combine PRs that are green (status is success)' + required: true + default: 'true' + combineBranchName: + description: 'Name of the branch to combine PRs into' + required: true + default: 'combine-prs-branch' + ignoreLabel: + description: 'Exclude PRs with this label' + required: true + default: 'nocombine' + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "combine-prs" + combine-prs: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - uses: actions/github-script@v3 + id: fetch-branch-names + name: Fetch branch names + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', { + owner: context.repo.owner, + repo: context.repo.repo + }); + branches = []; + prs = []; + base_branch = null; + for (const pull of pulls) { + const branch = pull['head']['ref']; + console.log('Pull for branch: ' + branch); + if (branch.startsWith('${{ github.event.inputs.branchPrefix }}')) { + console.log('Branch matched: ' + branch); + statusOK = true; + if(${{ github.event.inputs.mustBeGreen }}) { + console.log('Checking green status: ' + branch); + const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{ref}/status', { + owner: context.repo.owner, + repo: context.repo.repo, + ref: branch + }); + if(statuses.length > 0) { + const latest_status = statuses[0]['state']; + console.log('Validating status: ' + latest_status); + if(latest_status != 'success') { + console.log('Discarding ' + branch + ' with status ' + latest_status); + statusOK = false; + } + } + } + console.log('Checking labels: ' + branch); + const labels = pull['labels']; + for(const label of labels) { + const labelName = label['name']; + console.log('Checking label: ' + labelName); + if(labelName == '${{ github.event.inputs.ignoreLabel }}') { + console.log('Discarding ' + branch + ' with label ' + labelName); + statusOK = false; + } + } + if (statusOK) { + console.log('Adding branch to array: ' + branch); + branches.push(branch); + prs.push('#' + pull['number'] + ' ' + pull['title']); + base_branch = pull['base']['ref']; + } + } + } + + if (branches.length == 0) { + core.setFailed('No PRs/branches matched criteria'); + return; + } + + core.setOutput('base-branch', base_branch); + core.setOutput('prs-string', prs.join('\n')); + + combined = branches.join(' ') + console.log('Combined: ' + combined); + return combined + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2.3.3 + with: + fetch-depth: 0 + # Creates a branch with other PR branches merged together + - name: Created combined branch + env: + BASE_BRANCH: ${{ steps.fetch-branch-names.outputs.base-branch }} + BRANCHES_TO_COMBINE: ${{ steps.fetch-branch-names.outputs.result }} + COMBINE_BRANCH_NAME: ${{ github.event.inputs.combineBranchName }} + run: | + echo "${{steps.fetch-branch-names.outputs.result}}" + sourcebranches="${BRANCHES_TO_COMBINE%\"}" + sourcebranches="${sourcebranches#\"}" + + basebranch="${BASE_BRANCH%\"}" + basebranch="${basebranch#\"}" + + git config pull.rebase false + git config user.name github-actions + git config user.email github-actions@github.com + + git branch $COMBINE_BRANCH_NAME $basebranch + git checkout $COMBINE_BRANCH_NAME + git pull origin $sourcebranches --no-edit + git push origin $COMBINE_BRANCH_NAME + # Creates a PR with the new combined branch + - uses: actions/github-script@v3 + name: Create Combined Pull Request + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const prString = `${{ steps.fetch-branch-names.outputs.prs-string }}`; + const body = 'This PR was created by the Combine PRs action by combining the following PRs:\n' + prString; + await github.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: 'Combined PR', + head: '${{ github.event.inputs.combineBranchName }}', + base: '${{ steps.fetch-branch-names.outputs.base-branch }}', + body: body + }); From ec37236bc28e18724f6e4cf6aca5c63224935fa2 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 8 Jun 2021 17:31:47 +0100 Subject: [PATCH 1272/4969] Tweak combine-prs.yml to use check-runs Copied from https://github.com/hrvey/combine-prs-workflow/pull/6 --- .github/workflows/combine-prs.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index b4a89055446..749cc648fb5 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -51,16 +51,15 @@ jobs: statusOK = true; if(${{ github.event.inputs.mustBeGreen }}) { console.log('Checking green status: ' + branch); - const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{ref}/status', { + const checkRuns = await github.request('GET /repos/{owner}/{repo}/commits/{ref}/check-runs', { owner: context.repo.owner, repo: context.repo.repo, ref: branch }); - if(statuses.length > 0) { - const latest_status = statuses[0]['state']; - console.log('Validating status: ' + latest_status); - if(latest_status != 'success') { - console.log('Discarding ' + branch + ' with status ' + latest_status); + for await (const cr of checkRuns.data.check_runs) { + console.log('Validating check conclusion: ' + cr.conclusion); + if(cr.conclusion != 'success') { + console.log('Discarding ' + branch + ' with check conclusion ' + cr.conclusion); statusOK = false; } } From 3684a0b6b322d13c0a1e71934af5ca30c8d1e679 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:17 +0000 Subject: [PATCH 1273/4969] Bump HikariCP from 3.4.5 to 4.0.3 in /modules/junit-jupiter Bumps [HikariCP](https://github.com/brettwooldridge/HikariCP) from 3.4.5 to 4.0.3. - [Release notes](https://github.com/brettwooldridge/HikariCP/releases) - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-3.4.5...HikariCP-4.0.3) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 393c4cac653..2bc2a88e7b3 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile project(':mysql') testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:3.4.5' + testCompile 'com.zaxxer:HikariCP:4.0.3' testCompile 'redis.clients:jedis:3.6.0' testCompile 'org.apache.httpcomponents:httpclient:4.5.13' testCompile ('org.mockito:mockito-core:3.10.0') { From 8cf5661c18cf3eb0fcc500476865f656c2190323 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:26 +0000 Subject: [PATCH 1274/4969] Bump mysql-connector-java in /modules/junit-jupiter Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.22 to 8.0.25. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.22...8.0.25) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 393c4cac653..aed6deb0c10 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.1' testRuntime 'org.postgresql:postgresql:42.2.20' - testRuntime 'mysql:mysql-connector-java:8.0.22' + testRuntime 'mysql:mysql-connector-java:8.0.25' testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } From 160bb814e91b54050afd9a904059566c6f7d9df3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:34 +0000 Subject: [PATCH 1275/4969] Bump org.jetbrains.kotlin.jvm from 1.4.32 to 1.5.10 in /examples Bumps org.jetbrains.kotlin.jvm from 1.4.32 to 1.5.10. Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 6617e830e8b..61a74a3950e 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.4.1" - id("org.jetbrains.kotlin.jvm") version "1.4.32" + id("org.jetbrains.kotlin.jvm") version "1.5.10" id("org.jetbrains.kotlin.plugin.spring") version "1.5.10" } From 4f573f2802b4a31c44cbb516d3bed2bc7a2ccd20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:42 +0000 Subject: [PATCH 1276/4969] Bump annotations from 20.1.0 to 21.0.1 in /modules/postgresql Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index e853387291f..c01cd67df48 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -16,5 +16,5 @@ dependencies { testCompile testFixtures(project(':r2dbc')) testCompile 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' - compileOnly 'org.jetbrains:annotations:20.1.0' + compileOnly 'org.jetbrains:annotations:21.0.1' } From ff462ae0ab0a9b3b671bc7391afc2af96ea52af9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:44 +0000 Subject: [PATCH 1277/4969] Bump annotations from 20.1.0 to 21.0.1 in /modules/selenium Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- modules/selenium/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index 7911b1ea991..e9e4bf2d4a5 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -12,6 +12,6 @@ dependencies { testCompile project(':nginx') testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compileOnly 'org.jetbrains:annotations:20.1.0' - testCompileClasspath 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:21.0.1' + testCompileClasspath 'org.jetbrains:annotations:21.0.1' } From b820c4a07a8ccc415838851ada8e6e1bfa52466c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:47 +0000 Subject: [PATCH 1278/4969] Bump aws-java-sdk-sqs from 1.11.1018 to 1.12.1 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.11.1018 to 1.12.1. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.1018...1.12.1) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index e6a6340f686..3948f1443b2 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.1030' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.1018' + testCompile 'com.amazonaws:aws-java-sdk-sqs:1.12.1' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' testCompile 'software.amazon.awssdk:s3:2.16.62' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 5091c179d5636c2ccb8e80833a92535a564a418c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:48 +0000 Subject: [PATCH 1279/4969] Bump annotations from 20.1.0 to 21.0.1 in /modules/nginx Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- modules/nginx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index 1e601312ab4..c0fe33a8258 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -2,6 +2,6 @@ description = "Testcontainers :: Nginx" dependencies { compile project(':testcontainers') - compileOnly 'org.jetbrains:annotations:20.1.0' + compileOnly 'org.jetbrains:annotations:21.0.1' testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From ef197a4d1b686e8c88e1883ac9c32e4153bb93af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 18:57:50 +0000 Subject: [PATCH 1280/4969] Bump annotations from 20.1.0 to 21.0.1 in /modules/jdbc Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 2741a348f34..1152b2a5e93 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -4,7 +4,7 @@ dependencies { compile project(':database-commons') testCompile project(':test-support') - compileOnly 'org.jetbrains:annotations:20.1.0' + compileOnly 'org.jetbrains:annotations:21.0.1' testCompile 'commons-dbutils:commons-dbutils:1.7' testCompile 'org.vibur:vibur-dbcp:25.0' testCompile 'org.apache.tomcat:tomcat-jdbc:10.0.6' From 5fcbd6db51b92b6eeaf78efb6fb7487c46c47584 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 8 Jun 2021 20:16:43 +0100 Subject: [PATCH 1281/4969] Make release drafter observe PR events --- .github/workflows/release-drafter.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index bb2afd986f1..629280b1241 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -4,6 +4,8 @@ on: push: branches: - master + pull_request: + types: [opened, reopened, synchronize] jobs: update_release_draft: From 9a8df79f847dbcca833680e69f8b4ea1ace310bf Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 9 Jun 2021 17:48:37 +0200 Subject: [PATCH 1282/4969] Update to Gradle 7 (#4171) * Update to Gradle 7 * Add `checkPOMdependencies` task to test that no new dependencies were added * Update examples to Gradle 7 * Disable the filesystem watching * Try Gradle 7.0.2 * fix `provided` configuration * Extract `ComparePOMWithLatestReleasedTask` * Add missing file --- .gitignore | 1 + build.gradle | 19 +++--- buildSrc/build.gradle | 7 +++ .../ComparePOMWithLatestReleasedTask.groovy | 35 +++++++++++ core/build.gradle | 62 ++++++++----------- docs/examples/junit4/redis/build.gradle | 2 +- docs/examples/junit5/redis/build.gradle | 2 +- docs/examples/spock/redis/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- examples/kafka-cluster/build.gradle | 10 +-- gradle.properties | 1 + gradle/publishing.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- modules/cassandra/build.gradle | 4 +- modules/clickhouse/build.gradle | 8 +-- modules/cockroachdb/build.gradle | 6 +- modules/couchbase/build.gradle | 4 +- modules/database-commons/build.gradle | 4 +- modules/db2/build.gradle | 6 +- modules/dynalite/build.gradle | 6 +- modules/elasticsearch/build.gradle | 8 +-- modules/gcloud/build.gradle | 14 ++--- modules/influxdb/build.gradle | 4 +- modules/jdbc-test/build.gradle | 22 +++---- modules/jdbc/build.gradle | 18 +++--- modules/junit-jupiter/build.gradle | 26 ++++---- modules/kafka/build.gradle | 8 +-- modules/localstack/build.gradle | 12 ++-- modules/mariadb/build.gradle | 10 +-- modules/mockserver/build.gradle | 6 +- modules/mongodb/build.gradle | 4 +- modules/mssqlserver/build.gradle | 14 ++--- modules/mysql/build.gradle | 10 +-- modules/neo4j/build.gradle | 6 +- modules/nginx/build.gradle | 4 +- modules/oracle-xe/build.gradle | 6 +- modules/orientdb/build.gradle | 10 +-- modules/postgresql/build.gradle | 12 ++-- modules/presto/build.gradle | 6 +- modules/pulsar/build.gradle | 8 +-- modules/r2dbc/build.gradle | 14 ++--- modules/rabbitmq/build.gradle | 6 +- modules/selenium/build.gradle | 12 ++-- modules/solr/build.gradle | 4 +- modules/spock/build.gradle | 18 +++--- modules/toxiproxy/build.gradle | 10 +-- modules/trino/build.gradle | 6 +- modules/vault/build.gradle | 8 +-- 48 files changed, 254 insertions(+), 217 deletions(-) create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/src/main/groovy/org/testcontainers/build/ComparePOMWithLatestReleasedTask.groovy diff --git a/.gitignore b/.gitignore index 1b6070306a2..aa9fdf33f1f 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ node_modules/ .gradle/ build/ +!buildSrc/src/main/groovy/org/testcontainers/build out/ *.class diff --git a/build.gradle b/build.gradle index c51b24909cb..40f5bfed399 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,13 @@ plugins { - id 'io.franzbecker.gradle-lombok' version '3.1.0' - id 'nebula.provided-base' version '3.0.3' - id 'com.github.johnrengelman.shadow' version '5.2.0' + id 'io.franzbecker.gradle-lombok' version '4.0.0' + id 'com.github.johnrengelman.shadow' version '7.0.0' id "com.jfrog.bintray" version "1.8.4" apply false } apply from: "$rootDir/gradle/ci-support.gradle" subprojects { - apply plugin: 'nebula.provided-base' - apply plugin: 'java' + apply plugin: 'java-library' apply plugin: 'idea' apply plugin: 'io.franzbecker.gradle-lombok' apply plugin: 'com.github.johnrengelman.shadow' @@ -26,8 +24,13 @@ subprojects { mavenCentral() } + configurations { + provided + api.extendsFrom(provided) + } + lombok { - version = '1.18.12' + version = '1.18.20' } task delombok(type: io.franzbecker.gradle.lombok.task.DelombokTask) { @@ -98,7 +101,7 @@ subprojects { shadowJar { configurations = [] - classifier = null + archiveClassifier.set(null) doFirst { // See https://github.com/johnrengelman/shadow/blob/5.0.0/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ConfigureShadowRelocation.groovy @@ -128,6 +131,6 @@ subprojects { } dependencies { - testCompile 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.2.3' } } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 00000000000..13414d46a22 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,7 @@ +plugins { + id 'java-gradle-plugin' +} + +repositories { + mavenCentral() +} diff --git a/buildSrc/src/main/groovy/org/testcontainers/build/ComparePOMWithLatestReleasedTask.groovy b/buildSrc/src/main/groovy/org/testcontainers/build/ComparePOMWithLatestReleasedTask.groovy new file mode 100644 index 00000000000..1bb71ca8f52 --- /dev/null +++ b/buildSrc/src/main/groovy/org/testcontainers/build/ComparePOMWithLatestReleasedTask.groovy @@ -0,0 +1,35 @@ +package org.testcontainers.build + +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +class ComparePOMWithLatestReleasedTask extends DefaultTask { + + @Input + Set ignore = [] + + @TaskAction + def doCompare() { + def rootNode = new XmlSlurper().parse(project.tasks.generatePomFileForMavenJavaPublication.destination) + + def artifactId = rootNode.artifactId.text() + + def latestRelease = new XmlSlurper() + .parse("https://repo1.maven.org/maven2/org/testcontainers/${artifactId}/maven-metadata.xml") + .versioning.release.text() + + def releasedRootNode = new XmlSlurper() + .parse("https://repo1.maven.org/maven2/org/testcontainers/${artifactId}/${latestRelease}/${artifactId}-${latestRelease}.pom") + + Set dependencies = releasedRootNode.dependencies.children() + .collect { "${it.groupId.text()}:${it.artifactId.text()}".toString() } + + for (dependency in rootNode.dependencies.children()) { + def coordinates = "${dependency.groupId.text()}:${dependency.artifactId.text()}".toString() + if (!dependencies.contains(coordinates) && !ignore.contains(coordinates)) { + throw new IllegalStateException("A new dependency '${coordinates}' has been added to 'org.testcontainers:${artifactId}' - if this was intentional please add it to the ignore list in ${project.buildFile}") + } + } + } +} diff --git a/core/build.gradle b/core/build.gradle index 059202e1b41..d260ae5317a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -26,7 +26,7 @@ idea.module.testSourceDirs += sourceSets.jarFileTest.allSource.srcDirs configurations { baseline shaded - [runtime, compileOnly, testCompile]*.extendsFrom shaded + [api, compileOnly, testCompile]*.extendsFrom shaded } shadowJar { @@ -34,33 +34,16 @@ shadowJar { mergeServiceFiles() - exclude 'org/newsclub/**' - [ 'META-INF/NOTICE', 'META-INF/NOTICE.txt', 'META-INF/LICENSE', 'META-INF/LICENSE.txt', - 'META-INF/DEPENDENCIES', 'META-INF/maven/', 'META-INF/proguard/', 'META-INF/versions/*/module-info.class', - 'META-INF/services/README.md', - 'META-INF/services/com.fasterxml.jackson.core.*', - 'META-INF/services/com.github.dockerjava.api.command.*', - 'META-INF/services/javax.ws.rs.ext.*', 'META-INF/services/java.security.Provider', - 'mozilla/public-suffix-list.txt', - 'module-info.class', ].each { exclude(it) } - - project.afterEvaluate { - dependencies { - for (id in project.configurations.compile.resolvedConfiguration.resolvedArtifacts*.moduleVersion*.id) { - exclude(dependency("${id.group}:${id.name}")) - } - } - } } task jarFileTest(type: Test) { @@ -169,16 +152,16 @@ dependencies { exclude group: "*", module: "*" } - compile 'junit:junit:4.12' - compile 'org.slf4j:slf4j-api:1.7.30' + api 'junit:junit:4.12' + api 'org.slf4j:slf4j-api:1.7.30' compileOnly 'org.jetbrains:annotations:20.1.0' testCompileClasspath 'org.jetbrains:annotations:20.0.0' - compile 'org.apache.commons:commons-compress:1.20' - compile ('org.rnorth.duct-tape:duct-tape:1.0.8') { + api 'org.apache.commons:commons-compress:1.20' + api ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') } - compile "com.github.docker-java:docker-java-api:3.2.8" + api "com.github.docker-java:docker-java-api:3.2.8" shaded ('com.github.docker-java:docker-java-core:3.2.8') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') @@ -195,7 +178,7 @@ dependencies { exclude(group: 'org.slf4j') } - compile 'com.github.docker-java:docker-java-transport-zerodep:3.2.8' + api 'com.github.docker-java:docker-java-transport-zerodep:3.2.8' shaded "org.yaml:snakeyaml:1.27" @@ -205,24 +188,31 @@ dependencies { exclude(group: 'org.slf4j') } - testCompile 'org.apache.httpcomponents:httpclient:4.5.9' - testCompile 'redis.clients:jedis:3.6.0' - testCompile 'com.rabbitmq:amqp-client:5.9.0' - testCompile 'org.mongodb:mongo-java-driver:3.12.7' + testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' + testImplementation 'redis.clients:jedis:3.6.0' + testImplementation 'com.rabbitmq:amqp-client:5.9.0' + testImplementation 'org.mongodb:mongo-java-driver:3.12.7' - testCompile ('org.mockito:mockito-core:3.10.0') { + testImplementation ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest - testCompile files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') + testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testCompile 'org.assertj:assertj-core:3.18.1' - testCompile project(':test-support') + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.18.1' + testImplementation project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" - jarFileTestCompile 'junit:junit:4.12' - jarFileTestCompile 'org.assertj:assertj-core:3.18.1' - jarFileTestCompile 'org.ow2.asm:asm-debug-all:5.2' + jarFileTestImplementation 'junit:junit:4.12' + jarFileTestImplementation 'org.assertj:assertj-core:3.18.1' + jarFileTestImplementation 'org.ow2.asm:asm-debug-all:5.2' } + +tasks.generatePomFileForMavenJavaPublication.finalizedBy( + tasks.register('checkPOMdependencies', org.testcontainers.build.ComparePOMWithLatestReleasedTask) { + ignore = [ + ] + } +) diff --git a/docs/examples/junit4/redis/build.gradle b/docs/examples/junit4/redis/build.gradle index bf203a8fefa..7551c6e578e 100644 --- a/docs/examples/junit4/redis/build.gradle +++ b/docs/examples/junit4/redis/build.gradle @@ -1,7 +1,7 @@ description = "Examples for docs" dependencies { - compile "io.lettuce:lettuce-core:5.1.1.RELEASE" + api "io.lettuce:lettuce-core:5.1.1.RELEASE" testImplementation "junit:junit:4.12" testImplementation project(":testcontainers") diff --git a/docs/examples/junit5/redis/build.gradle b/docs/examples/junit5/redis/build.gradle index 409b766b758..348f4788555 100644 --- a/docs/examples/junit5/redis/build.gradle +++ b/docs/examples/junit5/redis/build.gradle @@ -1,7 +1,7 @@ description = "Examples for docs" dependencies { - compile "io.lettuce:lettuce-core:5.1.1.RELEASE" + api "io.lettuce:lettuce-core:5.1.1.RELEASE" testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.2" testImplementation "org.junit.jupiter:junit-jupiter-params:5.4.2" diff --git a/docs/examples/spock/redis/build.gradle b/docs/examples/spock/redis/build.gradle index 398a6d3fa1c..1bff637a7fb 100644 --- a/docs/examples/spock/redis/build.gradle +++ b/docs/examples/spock/redis/build.gradle @@ -4,7 +4,7 @@ plugins { } dependencies { - compile "io.lettuce:lettuce-core:5.2.0.RELEASE" + api "io.lettuce:lettuce-core:5.2.0.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' testImplementation project(":spock") testImplementation 'ch.qos.logback:logback-classic:1.2.3' diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 622ab64a3cb..0f80bbf516c 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 491b5c2f214..6ba1a966dae 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -9,9 +9,9 @@ repositories { dependencies { testCompileOnly "org.projectlombok:lombok:1.18.20" testAnnotationProcessor "org.projectlombok:lombok:1.18.10" - testCompile 'org.testcontainers:kafka' - testCompile 'org.apache.kafka:kafka-clients:2.3.1' - testCompile 'org.assertj:assertj-core:3.14.0' - testCompile 'com.google.guava:guava:23.0' - testCompile 'org.slf4j:slf4j-simple:1.7.30' + testImplementation 'org.testcontainers:kafka' + testImplementation 'org.apache.kafka:kafka-clients:2.3.1' + testImplementation 'org.assertj:assertj-core:3.14.0' + testImplementation 'com.google.guava:guava:23.0' + testImplementation 'org.slf4j:slf4j-simple:1.7.30' } diff --git a/gradle.properties b/gradle.properties index dad41a4425a..397b832391e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,3 @@ org.gradle.parallel=false org.gradle.caching=true + diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 3acdeb10c88..84fad9994e5 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -72,7 +72,7 @@ publishing { } } - project.configurations.compile.dependencies.each { addDependency(it, 'compile') } + project.configurations.api.dependencies.each { addDependency(it, 'compile') } project.configurations.provided.dependencies.each { addDependency(it, 'provided') } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6fd47cc3de5..4a66b0f1980 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ #Sun Apr 05 19:28:23 BST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists diff --git a/modules/cassandra/build.gradle b/modules/cassandra/build.gradle index 9704a05b69d..a5427aaea07 100644 --- a/modules/cassandra/build.gradle +++ b/modules/cassandra/build.gradle @@ -1,6 +1,6 @@ description = "TestContainers :: Cassandra" dependencies { - compile project(":database-commons") - compile "com.datastax.cassandra:cassandra-driver-core:3.7.1" + api project(":database-commons") + api "com.datastax.cassandra:cassandra-driver-core:3.7.1" } diff --git a/modules/clickhouse/build.gradle b/modules/clickhouse/build.gradle index 323475b1d1c..7eb68eb2e51 100644 --- a/modules/clickhouse/build.gradle +++ b/modules/clickhouse/build.gradle @@ -1,9 +1,9 @@ description = "Testcontainers :: JDBC :: ClickHouse" dependencies { - compile project(':testcontainers') - compile project(':jdbc') + api project(':testcontainers') + api project(':jdbc') - testCompile project(':jdbc-test') - testCompile 'ru.yandex.clickhouse:clickhouse-jdbc:0.2.4' + testImplementation project(':jdbc-test') + testImplementation 'ru.yandex.clickhouse:clickhouse-jdbc:0.2.4' } diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index a3927258679..5222208fae0 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: JDBC :: CockroachDB" dependencies { - compile project(':jdbc') + api project(':jdbc') - testCompile project(':jdbc-test') - testCompile 'org.postgresql:postgresql:42.2.12' + testImplementation project(':jdbc-test') + testImplementation 'org.postgresql:postgresql:42.2.12' } diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 9cb778fd479..88eb537269d 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: Couchbase" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile 'com.couchbase.client:java-client:2.7.15' + testImplementation 'com.couchbase.client:java-client:2.7.15' } diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 0eecc1844d0..7bba8548c95 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: Database-Commons" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.19.0' } diff --git a/modules/db2/build.gradle b/modules/db2/build.gradle index feaf5f790c5..9d5d8a61ab0 100644 --- a/modules/db2/build.gradle +++ b/modules/db2/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: JDBC :: DB2" dependencies { - compile project(':jdbc') + api project(':jdbc') - testCompile project(':jdbc-test') - testCompile 'com.ibm.db2:jcc:11.5.0.0' + testImplementation project(':jdbc-test') + testImplementation 'com.ibm.db2:jcc:11.5.0.0' } diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 58a16a0b62b..e3a49df5be2 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -1,10 +1,10 @@ description = "Testcontainers :: Dynalite" dependencies { - compile project(':testcontainers') + api project(':testcontainers') compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' - testCompile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 21db8e69545..e66e045ead4 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -1,8 +1,8 @@ description = "TestContainers :: elasticsearch" dependencies { - compile project(':testcontainers') - testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.13.0" - testCompile "org.elasticsearch.client:transport:7.12.1" - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + api project(':testcontainers') + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.13.0" + testImplementation "org.elasticsearch.client:transport:7.12.1" + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index aa42d7dc560..11e68824c34 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -1,12 +1,12 @@ description = "Testcontainers :: GCloud" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile 'com.google.cloud:google-cloud-datastore:1.102.4' - testCompile 'com.google.cloud:google-cloud-firestore:1.33.0' - testCompile 'com.google.cloud:google-cloud-pubsub:1.105.0' - testCompile 'com.google.cloud:google-cloud-spanner:1.50.0' - testCompile 'com.google.cloud:google-cloud-bigtable:1.17.3' - testCompile 'org.assertj:assertj-core:3.15.0' + testImplementation 'com.google.cloud:google-cloud-datastore:1.102.4' + testImplementation 'com.google.cloud:google-cloud-firestore:1.33.0' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.105.0' + testImplementation 'com.google.cloud:google-cloud-spanner:1.50.0' + testImplementation 'com.google.cloud:google-cloud-bigtable:1.17.3' + testImplementation 'org.assertj:assertj-core:3.15.0' } diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index 2e735e1137a..704bf960724 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: InfluxDB" dependencies { - compile project(':testcontainers') + api project(':testcontainers') compileOnly 'org.influxdb:influxdb-java:2.21' - testCompile 'org.influxdb:influxdb-java:2.21' + testImplementation 'org.influxdb:influxdb-java:2.21' } diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 3dd0d52f2e8..3da4eb0f691 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -1,20 +1,20 @@ dependencies { - compile project(':jdbc') - compile project(':test-support') + api project(':jdbc') + api project(':test-support') - compile 'com.google.guava:guava:30.1-jre' - compile 'org.apache.commons:commons-lang3:3.12.0' - compile 'com.zaxxer:HikariCP-java6:2.3.13' - compile 'commons-dbutils:commons-dbutils:1.7' + api 'com.google.guava:guava:30.1-jre' + api 'org.apache.commons:commons-lang3:3.12.0' + api 'com.zaxxer:HikariCP-java6:2.3.13' + api 'commons-dbutils:commons-dbutils:1.7' - compile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' + api 'com.googlecode.junit-toolbox:junit-toolbox:2.4' - compile('org.rnorth.visible-assertions:visible-assertions:2.1.2') { + api('org.rnorth.visible-assertions:visible-assertions:2.1.2') { // Excluded in favor of jna-platform exclude(group: "net.java.dev.jna", module: "jna") } - compile 'org.apache.tomcat:tomcat-jdbc:9.0.40' - compile 'org.vibur:vibur-dbcp:25.0' - compile 'mysql:mysql-connector-java:8.0.25' + api 'org.apache.tomcat:tomcat-jdbc:9.0.40' + api 'org.vibur:vibur-dbcp:25.0' + api 'mysql:mysql-connector-java:8.0.25' } diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 1152b2a5e93..16b95af77bf 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -1,15 +1,15 @@ description = "Testcontainers :: JDBC" dependencies { - compile project(':database-commons') - testCompile project(':test-support') + api project(':database-commons') + testImplementation project(':test-support') compileOnly 'org.jetbrains:annotations:21.0.1' - testCompile 'commons-dbutils:commons-dbutils:1.7' - testCompile 'org.vibur:vibur-dbcp:25.0' - testCompile 'org.apache.tomcat:tomcat-jdbc:10.0.6' - testCompile 'com.zaxxer:HikariCP-java6:2.3.13' - testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4' - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testCompile 'org.assertj:assertj-core:3.19.0' + testImplementation 'commons-dbutils:commons-dbutils:1.7' + testImplementation 'org.vibur:vibur-dbcp:25.0' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.6' + testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' + testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.19.0' } diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index b06972371ff..ad74eb3ec26 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -1,23 +1,23 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { - compile project(':testcontainers') - compile 'org.junit.jupiter:junit-jupiter-api:5.7.1' + api project(':testcontainers') + api 'org.junit.jupiter:junit-jupiter-api:5.7.1' - testCompile project(':mysql') - testCompile project(':postgresql') - testCompile 'com.zaxxer:HikariCP:4.0.3' - testCompile 'redis.clients:jedis:3.6.0' - testCompile 'org.apache.httpcomponents:httpclient:4.5.13' - testCompile ('org.mockito:mockito-core:3.10.0') { + testImplementation project(':mysql') + testImplementation project(':postgresql') + testImplementation 'com.zaxxer:HikariCP:4.0.3' + testImplementation 'redis.clients:jedis:3.6.0' + testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' + testImplementation ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') } - testCompile 'org.assertj:assertj-core:3.18.1' - testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.1' + testImplementation 'org.assertj:assertj-core:3.18.1' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.1' - testRuntime 'org.postgresql:postgresql:42.2.20' - testRuntime 'mysql:mysql-connector-java:8.0.25' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.7.2' + testRuntimeOnly 'org.postgresql:postgresql:42.2.20' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } test { diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index db400c0b557..56abadbce47 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -1,9 +1,9 @@ description = "Testcontainers :: Kafka" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile 'org.apache.kafka:kafka-clients:2.8.0' - testCompile 'org.assertj:assertj-core:3.18.1' - testCompile 'com.google.guava:guava:23.0' + testImplementation 'org.apache.kafka:kafka-clients:2.8.0' + testImplementation 'org.assertj:assertj-core:3.18.1' + testImplementation 'com.google.guava:guava:23.0' } diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3948f1443b2..503a3a7bf49 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -1,12 +1,12 @@ description = "Testcontainers :: Localstack" dependencies { - compile project(':testcontainers') + api project(':testcontainers') compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.1030' - testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.1030' - testCompile 'com.amazonaws:aws-java-sdk-sqs:1.12.1' - testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testCompile 'software.amazon.awssdk:s3:2.16.62' - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.1' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.11.807' + testImplementation 'software.amazon.awssdk:s3:2.16.62' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 17d912b826c..ca267a1fe7c 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -4,14 +4,14 @@ dependencies { annotationProcessor 'com.google.auto.service:auto-service:1.0' compileOnly 'com.google.auto.service:auto-service:1.0' - compile project(':jdbc') + api project(':jdbc') compileOnly project(':r2dbc') compileOnly 'org.mariadb:r2dbc-mariadb:1.0.1' - testCompile project(':jdbc-test') - testCompile 'org.mariadb.jdbc:mariadb-java-client:2.7.3' + testImplementation project(':jdbc-test') + testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3' - testCompile testFixtures(project(':r2dbc')) - testCompile 'org.mariadb:r2dbc-mariadb:1.0.0' + testImplementation testFixtures(project(':r2dbc')) + testImplementation 'org.mariadb:r2dbc-mariadb:1.0.0' } diff --git a/modules/mockserver/build.gradle b/modules/mockserver/build.gradle index e13343559f5..9ea504ca74a 100644 --- a/modules/mockserver/build.gradle +++ b/modules/mockserver/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: MockServer" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile 'org.mock-server:mockserver-client-java:5.5.4' - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.mock-server:mockserver-client-java:5.5.4' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index 57db1be21de..e332badb68b 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: MongoDB" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile("org.mongodb:mongodb-driver-sync:4.0.2") + testImplementation("org.mongodb:mongodb-driver-sync:4.0.2") } diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 143a6582ae1..74e77d474e9 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -4,18 +4,18 @@ dependencies { annotationProcessor 'com.google.auto.service:auto-service:1.0' compileOnly 'com.google.auto.service:auto-service:1.0' - compile project(':jdbc') + api project(':jdbc') compileOnly project(':r2dbc') compileOnly 'io.r2dbc:r2dbc-mssql:0.8.6.RELEASE' - testCompile project(':jdbc-test') - testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' + testImplementation project(':jdbc-test') + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' - testCompile project(':r2dbc') - testCompile 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' + testImplementation project(':r2dbc') + testImplementation 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' // MSSQL's wait strategy requires the JDBC driver - testCompile testFixtures(project(':r2dbc')) - testCompile 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' + testImplementation testFixtures(project(':r2dbc')) + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' } diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 91a7d2c9918..a14fa678280 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -4,16 +4,16 @@ dependencies { annotationProcessor 'com.google.auto.service:auto-service:1.0' compileOnly 'com.google.auto.service:auto-service:1.0' - compile project(':jdbc') + api project(':jdbc') compileOnly project(':r2dbc') compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' - testCompile project(':jdbc-test') - testCompile 'mysql:mysql-connector-java:8.0.25' + testImplementation project(':jdbc-test') + testImplementation 'mysql:mysql-connector-java:8.0.25' - testCompile testFixtures(project(':r2dbc')) - testCompile 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' + testImplementation testFixtures(project(':r2dbc')) + testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' compileOnly 'org.jetbrains:annotations:21.0.1' } diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 722e5474388..f556c96095a 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -31,8 +31,8 @@ test.dependsOn customNeo4jPluginJar dependencies { customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.9" - compile project(":testcontainers") + api project(":testcontainers") - testCompile "org.neo4j.driver:neo4j-java-driver:1.7.5" - testCompile 'org.assertj:assertj-core:3.19.0' + testImplementation "org.neo4j.driver:neo4j-java-driver:1.7.5" + testImplementation 'org.assertj:assertj-core:3.19.0' } diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index c0fe33a8258..5bfcfae910b 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: Nginx" dependencies { - compile project(':testcontainers') + api project(':testcontainers') compileOnly 'org.jetbrains:annotations:21.0.1' - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index 026521e9a0c..5a6040ac81f 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -1,8 +1,8 @@ description = "Testcontainers :: JDBC :: Oracle XE" dependencies { - compile project(':jdbc') + api project(':jdbc') - testCompile project(':jdbc-test') - testCompile 'com.oracle.ojdbc:ojdbc8:19.3.0.0' + testImplementation project(':jdbc-test') + testImplementation 'com.oracle.ojdbc:ojdbc8:19.3.0.0' } diff --git a/modules/orientdb/build.gradle b/modules/orientdb/build.gradle index ffa1350172a..5be59938603 100644 --- a/modules/orientdb/build.gradle +++ b/modules/orientdb/build.gradle @@ -1,11 +1,11 @@ description = "TestContainers :: Orientdb" dependencies { - compile project(":testcontainers") + api project(":testcontainers") - compile "com.orientechnologies:orientdb-client:3.0.24" + api "com.orientechnologies:orientdb-client:3.0.24" - testCompile 'org.assertj:assertj-core:3.12.0' - testCompile 'org.apache.tinkerpop:gremlin-driver:3.3.4' - testCompile "com.orientechnologies:orientdb-gremlin:3.0.18" + testImplementation 'org.assertj:assertj-core:3.12.0' + testImplementation 'org.apache.tinkerpop:gremlin-driver:3.3.4' + testImplementation "com.orientechnologies:orientdb-gremlin:3.0.18" } diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index c01cd67df48..fe9e58820d8 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -4,17 +4,17 @@ dependencies { annotationProcessor 'com.google.auto.service:auto-service:1.0' compileOnly 'com.google.auto.service:auto-service:1.0' - compile project(':jdbc') + api project(':jdbc') compileOnly project(':r2dbc') compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.8.RELEASE' - testCompile project(':jdbc-test') - testCompile project(':test-support') - testCompile 'org.postgresql:postgresql:42.2.18' + testImplementation project(':jdbc-test') + testImplementation project(':test-support') + testImplementation 'org.postgresql:postgresql:42.2.18' - testCompile testFixtures(project(':r2dbc')) - testCompile 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' + testImplementation testFixtures(project(':r2dbc')) + testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' compileOnly 'org.jetbrains:annotations:21.0.1' } diff --git a/modules/presto/build.gradle b/modules/presto/build.gradle index 4130fb74891..1db76199969 100644 --- a/modules/presto/build.gradle +++ b/modules/presto/build.gradle @@ -1,9 +1,9 @@ description = "Testcontainers :: JDBC :: Presto" dependencies { - compile project(':jdbc') + api project(':jdbc') - testCompile project(':jdbc-test') - testCompile 'io.prestosql:presto-jdbc:331' + testImplementation project(':jdbc-test') + testImplementation 'io.prestosql:presto-jdbc:331' compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 10fe90dadf9..92cf910f259 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -1,9 +1,9 @@ description = "Testcontainers :: Pulsar" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.18.1' - testCompile group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' + testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.18.1' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' } diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index a7388ebc6d2..21d3c1894e4 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -8,13 +8,13 @@ dependencies { annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' compileOnly 'com.google.auto.service:auto-service:1.0-rc6' - compile project(':testcontainers') - compile 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE' + api project(':testcontainers') + api 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE' - testCompile 'org.assertj:assertj-core:3.14.0' - testCompile 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' - testCompile project(':postgresql') + testImplementation 'org.assertj:assertj-core:3.14.0' + testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' + testImplementation project(':postgresql') - testFixturesCompile 'io.projectreactor:reactor-core:3.3.4.RELEASE' - testFixturesCompile 'org.assertj:assertj-core:3.14.0' + testFixturesImplementation 'io.projectreactor:reactor-core:3.3.4.RELEASE' + testFixturesImplementation 'org.assertj:assertj-core:3.14.0' } diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 73524c2da18..13638b51b97 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -1,8 +1,8 @@ description = "TestContainers :: RabbitMQ" dependencies { - compile project(":testcontainers") - testCompile 'com.rabbitmq:amqp-client:5.7.0' - testCompile 'org.assertj:assertj-core:3.12.2' + api project(":testcontainers") + testImplementation 'com.rabbitmq:amqp-client:5.7.0' + testImplementation 'org.assertj:assertj-core:3.12.2' compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index e9e4bf2d4a5..f91bb361775 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -1,16 +1,16 @@ description = "Testcontainers :: Selenium" dependencies { - compile project(':testcontainers') + api project(':testcontainers') provided 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' provided 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testCompile 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' - testCompile 'org.seleniumhq.selenium:selenium-support:3.141.59' + testImplementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' + testImplementation 'org.seleniumhq.selenium:selenium-support:3.141.59' - testCompile 'org.mortbay.jetty:jetty:6.1.26' - testCompile project(':nginx') - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.mortbay.jetty:jetty:6.1.26' + testImplementation project(':nginx') + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' compileOnly 'org.jetbrains:annotations:21.0.1' testCompileClasspath 'org.jetbrains:annotations:21.0.1' diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index af3193be52a..76535a2b7c8 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: Solr" dependencies { - compile project(':testcontainers') - testCompile 'org.apache.solr:solr-solrj:8.3.0' + api project(':testcontainers') + testImplementation 'org.apache.solr:solr-solrj:8.3.0' } diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 8c065e389cd..013a79dbc59 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -5,18 +5,18 @@ plugins { description = "Testcontainers :: Spock-Extension" dependencies { - compile project(':testcontainers') - compile 'org.spockframework:spock-core:1.3-groovy-2.5' + api project(':testcontainers') + api 'org.spockframework:spock-core:1.3-groovy-2.5' - testCompile project(':selenium') - testCompile project(':mysql') - testCompile project(':postgresql') + testImplementation project(':selenium') + testImplementation project(':mysql') + testImplementation project(':postgresql') - testCompile 'com.zaxxer:HikariCP:4.0.3' - testCompile 'org.apache.httpcomponents:httpclient:4.5.13' + testImplementation 'com.zaxxer:HikariCP:4.0.3' + testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntime 'org.postgresql:postgresql:42.2.18' - testRuntime 'mysql:mysql-connector-java:8.0.25' + testRuntimeOnly 'org.postgresql:postgresql:42.2.18' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' testCompileClasspath 'org.jetbrains:annotations:21.0.1' } diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index 47221d68e40..3d7d110609b 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -1,11 +1,11 @@ description = "Testcontainers :: Toxiproxy" dependencies { - compile project(':testcontainers') - compile 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.4' + api project(':testcontainers') + api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.4' - testCompile 'redis.clients:jedis:3.0.1' - testCompile 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'redis.clients:jedis:3.0.1' + testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testCompile project(':test-support') + testImplementation project(':test-support') } diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index d726cbc8e76..5a3b733934f 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -1,9 +1,9 @@ description = "Testcontainers :: JDBC :: Trino" dependencies { - compile project(':jdbc') + api project(':jdbc') - testCompile project(':jdbc-test') - testCompile 'io.trino:trino-jdbc:352' + testImplementation project(':jdbc-test') + testImplementation 'io.trino:trino-jdbc:352' compileOnly 'org.jetbrains:annotations:20.0.0' } diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 17edbd3f3fd..50797658fbb 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -1,10 +1,10 @@ description = "Testcontainers :: Vault" dependencies { - compile project(':testcontainers') + api project(':testcontainers') - testCompile 'com.bettercloud:vault-java-driver:5.1.0' - testCompile 'io.rest-assured:rest-assured:4.4.0' - testCompile 'org.assertj:assertj-core:3.19.0' + testImplementation 'com.bettercloud:vault-java-driver:5.1.0' + testImplementation 'io.rest-assured:rest-assured:4.4.0' + testImplementation 'org.assertj:assertj-core:3.19.0' } From 636b7f9c9eea5e98c3d8be9c902e9890cb0ae710 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:21 +0000 Subject: [PATCH 1283/4969] Bump guava from 30.1-jre to 30.1.1-jre in /core Bumps [guava](https://github.com/google/guava) from 30.1-jre to 30.1.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d260ae5317a..7f10e4847de 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ buildscript { dependencies { // https://github.com/melix/japicmp-gradle-plugin/issues/36 - classpath 'com.google.guava:guava:30.1-jre' + classpath 'com.google.guava:guava:30.1.1-jre' } } From d4e5687da81bab1d8f6352c261512b516b6a86f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:22 +0000 Subject: [PATCH 1284/4969] Bump guava from 30.1-jre to 30.1.1-jre in /modules/jdbc-test Bumps [guava](https://github.com/google/guava) from 30.1-jre to 30.1.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 3da4eb0f691..98ee2ce0880 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -2,7 +2,7 @@ dependencies { api project(':jdbc') api project(':test-support') - api 'com.google.guava:guava:30.1-jre' + api 'com.google.guava:guava:30.1.1-jre' api 'org.apache.commons:commons-lang3:3.12.0' api 'com.zaxxer:HikariCP-java6:2.3.13' api 'commons-dbutils:commons-dbutils:1.7' From bb9ead01af722fa6c52d84b1461b0656b0ec21bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:24 +0000 Subject: [PATCH 1285/4969] Bump amqp-client from 5.9.0 to 5.12.0 in /core Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.9.0 to 5.12.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.9.0...v5.12.0) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d260ae5317a..3d273fc62f0 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -190,7 +190,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:3.6.0' - testImplementation 'com.rabbitmq:amqp-client:5.9.0' + testImplementation 'com.rabbitmq:amqp-client:5.12.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.7' testImplementation ('org.mockito:mockito-core:3.10.0') { From aaad895f8ee1550a2e2d2fd7fb0ed5d43f52f87e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:25 +0000 Subject: [PATCH 1286/4969] Bump snakeyaml from 1.27 to 1.29 in /core Bumps [snakeyaml](https://bitbucket.org/asomov/snakeyaml) from 1.27 to 1.29. - [Commits](https://bitbucket.org/asomov/snakeyaml/branches/compare/snakeyaml-1.29..snakeyaml-1.27) --- updated-dependencies: - dependency-name: org.yaml:snakeyaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d260ae5317a..7d05b168ea3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -180,7 +180,7 @@ dependencies { api 'com.github.docker-java:docker-java-transport-zerodep:3.2.8' - shaded "org.yaml:snakeyaml:1.27" + shaded "org.yaml:snakeyaml:1.29" shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From 345b9f76bdceb0a4a7ef0dae880a3e2d4fc2e722 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:25 +0000 Subject: [PATCH 1287/4969] Bump kafka-clients from 2.3.1 to 2.8.0 in /examples Bumps kafka-clients from 2.3.1 to 2.8.0. Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 6ba1a966dae..1ba81fda105 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompileOnly "org.projectlombok:lombok:1.18.20" testAnnotationProcessor "org.projectlombok:lombok:1.18.10" testImplementation 'org.testcontainers:kafka' - testImplementation 'org.apache.kafka:kafka-clients:2.3.1' + testImplementation 'org.apache.kafka:kafka-clients:2.8.0' testImplementation 'org.assertj:assertj-core:3.14.0' testImplementation 'com.google.guava:guava:23.0' testImplementation 'org.slf4j:slf4j-simple:1.7.30' From d60123822c81b77fda450cbac74840d85cb51237 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:26 +0000 Subject: [PATCH 1288/4969] Bump postgresql from 42.2.18 to 42.2.20 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.18 to 42.2.20. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.20/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.18...REL42.2.20) Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 013a79dbc59..214005466ce 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.2.18' + testRuntimeOnly 'org.postgresql:postgresql:42.2.20' testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' testCompileClasspath 'org.jetbrains:annotations:21.0.1' From 0c775ca5517c6487683b164b25c2646f1046f76b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:27 +0000 Subject: [PATCH 1289/4969] Bump postgresql from 42.2.18 to 42.2.20 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.18 to 42.2.20. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.20/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.18...REL42.2.20) Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index fe9e58820d8..c44dbe7d009 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.2.18' + testImplementation 'org.postgresql:postgresql:42.2.20' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' From d2370c82ee22e0fab74776b55cf92f2fa77be0b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:34 +0000 Subject: [PATCH 1290/4969] Bump jedis from 3.4.0 to 3.6.0 in /examples Bumps [jedis](https://github.com/redis/jedis) from 3.4.0 to 3.6.0. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.4.0...jedis-3.6.0) Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 42553843710..c19c5b22f23 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.4.0' + implementation 'redis.clients:jedis:3.6.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index de1e2d8a0a8..a968a6d2bf3 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.4.0' + implementation 'redis.clients:jedis:3.6.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 54a16b25230..dfbe856ea62 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.4.0' + implementation 'redis.clients:jedis:3.6.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.30' From 80a082661b470a526e89037c26a54d14a2a235ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:36 +0000 Subject: [PATCH 1291/4969] Bump tomcat-jdbc from 9.0.40 to 10.0.6 in /modules/jdbc-test Bumps tomcat-jdbc from 9.0.40 to 10.0.6. Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 3da4eb0f691..8ccf8ee5f88 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:9.0.40' + api 'org.apache.tomcat:tomcat-jdbc:10.0.6' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.25' } From 6df46bf62622098c3a7286fa6d510bd9bb67867f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:39 +0000 Subject: [PATCH 1292/4969] Bump annotations from 20.1.0 to 21.0.1 in /examples Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- examples/mongodb-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 8a4c727f069..8d8c8731c86 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -9,5 +9,5 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testCompileClasspath 'org.jetbrains:annotations:20.1.0' + testCompileClasspath 'org.jetbrains:annotations:21.0.1' } From 89a336843c555480ba9e8af2683bea1a464dff23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:40 +0000 Subject: [PATCH 1293/4969] Bump spock-core from 1.3-groovy-2.5 to 2.0-groovy-3.0 in /modules/spock Bumps spock-core from 1.3-groovy-2.5 to 2.0-groovy-3.0. Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 013a79dbc59..e51bb311d4d 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -6,7 +6,7 @@ description = "Testcontainers :: Spock-Extension" dependencies { api project(':testcontainers') - api 'org.spockframework:spock-core:1.3-groovy-2.5' + api 'org.spockframework:spock-core:2.0-groovy-3.0' testImplementation project(':selenium') testImplementation project(':mysql') From 66ef00a5573c3e20890562c4dc2fb2b8023ee3c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:43 +0000 Subject: [PATCH 1294/4969] Bump junit-jupiter-api from 5.7.1 to 5.7.2 in /modules/junit-jupiter Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.1...r5.7.2) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ad74eb3ec26..3bd78867f70 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { api project(':testcontainers') - api 'org.junit.jupiter:junit-jupiter-api:5.7.1' + api 'org.junit.jupiter:junit-jupiter-api:5.7.2' testImplementation project(':mysql') testImplementation project(':postgresql') From 685997b28fa7d3c5eedb62db365f664bff5fdc24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:44 +0000 Subject: [PATCH 1295/4969] Bump postgresql from 42.2.18 to 42.2.20 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.18 to 42.2.20. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.18...REL42.2.20) Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index b3d339d4db8..edb545e79d3 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'org.json:json:20210307' - testImplementation 'org.postgresql:postgresql:42.2.18' + testImplementation 'org.postgresql:postgresql:42.2.20' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From a7a6c18843c00756b56101b69c59f24c01f52791 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:45 +0000 Subject: [PATCH 1296/4969] Bump transport from 7.12.1 to 7.13.1 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.12.1 to 7.13.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.12.1...v7.13.1) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index e66e045ead4..e1921e755f8 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.13.0" - testImplementation "org.elasticsearch.client:transport:7.12.1" + testImplementation "org.elasticsearch.client:transport:7.13.1" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From a8156a0f413ec5094a03524ffff4c09abb1032db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:45 +0000 Subject: [PATCH 1297/4969] Bump junit-jupiter-params from 5.7.1 to 5.7.2 in /modules/junit-jupiter Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.1...r5.7.2) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ad74eb3ec26..5f242c549ae 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.18.1' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.1' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' testRuntimeOnly 'org.postgresql:postgresql:42.2.20' testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' From 7c7829072f34992b7607b211a94afc2b049c6eae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:46 +0000 Subject: [PATCH 1298/4969] Bump s3 from 2.16.62 to 2.16.80 in /modules/localstack Bumps s3 from 2.16.62 to 2.16.80. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 503a3a7bf49..87cc407468d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.1' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.11.807' - testImplementation 'software.amazon.awssdk:s3:2.16.62' + testImplementation 'software.amazon.awssdk:s3:2.16.80' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 04baf3743197ec8cdfb8a70be66054d0a2376d07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:48 +0000 Subject: [PATCH 1299/4969] Bump clickhouse-jdbc from 0.2.4 to 0.3.1-patch in /modules/clickhouse Bumps [clickhouse-jdbc](https://github.com/ClickHouse/clickhouse-jdbc) from 0.2.4 to 0.3.1-patch. - [Release notes](https://github.com/ClickHouse/clickhouse-jdbc/releases) - [Changelog](https://github.com/ClickHouse/clickhouse-jdbc/blob/master/CHANGELOG) - [Commits](https://github.com/ClickHouse/clickhouse-jdbc/compare/release_0.2.4...v0.3.1-patch) --- updated-dependencies: - dependency-name: ru.yandex.clickhouse:clickhouse-jdbc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/clickhouse/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/clickhouse/build.gradle b/modules/clickhouse/build.gradle index 7eb68eb2e51..39b269d794b 100644 --- a/modules/clickhouse/build.gradle +++ b/modules/clickhouse/build.gradle @@ -5,5 +5,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'ru.yandex.clickhouse:clickhouse-jdbc:0.2.4' + testImplementation 'ru.yandex.clickhouse:clickhouse-jdbc:0.3.1-patch' } From b77e22f81fcb0308a99c9c9c6e54e9f9dbbb270f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 15:49:51 +0000 Subject: [PATCH 1300/4969] Bump annotations from 20.1.0 to 21.0.1 in /core Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.1.0 to 21.0.1. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.1.0...21.0.1) Signed-off-by: dependabot[bot] --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index d260ae5317a..a02aad3ddf7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -154,8 +154,8 @@ dependencies { api 'junit:junit:4.12' api 'org.slf4j:slf4j-api:1.7.30' - compileOnly 'org.jetbrains:annotations:20.1.0' - testCompileClasspath 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:21.0.1' + testCompileClasspath 'org.jetbrains:annotations:21.0.1' api 'org.apache.commons:commons-compress:1.20' api ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') From 4d93101cbbbe1dd97da88d86006d51a5a4ec9884 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 9 Jun 2021 22:21:44 +0200 Subject: [PATCH 1301/4969] Cleanup japicmp excludes (#4192) --- core/build.gradle | 59 +++-------------------------------------------- 1 file changed, 3 insertions(+), 56 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index d260ae5317a..353df75b0c4 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -72,64 +72,11 @@ task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { "org.testcontainers.shaded.*", ] - // TODO remove once 1.15.0 is released - classExcludes = [ - "org.testcontainers.containers.AmbassadorContainer", - "org.testcontainers.containers.traits.VncService", - "org.testcontainers.containers.wait.HostPortWaitStrategy", - "org.testcontainers.containers.wait.HttpWaitStrategy", - "org.testcontainers.containers.wait.LogMessageWaitStrategy", - "org.testcontainers.containers.wait.Wait", - "org.testcontainers.containers.wait.WaitAllStrategy", - "org.testcontainers.containers.wait.WaitStrategy", - "org.testcontainers.dockerclient.AuditLoggingDockerClient", - "org.testcontainers.dockerclient.LogToStringContainerCallback", - "org.testcontainers.dockerclient.DockerMachineClientProviderStrategy", - "org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy", - "org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy", - "org.testcontainers.dockerclient.ProxiedUnixSocketClientProviderStrategy", - "org.testcontainers.dockerclient.WindowsClientProviderStrategy", - "org.testcontainers.dockerclient.UnixSocketClientProviderStrategy", - "org.testcontainers.dockerclient.auth.AuthDelegatingDockerClientConfig", - "org.testcontainers.containers.GenericContainer\$AbstractWaitStrategy", - "org.testcontainers.dockerclient.transport.okhttp.NamedPipeSocketFactory", - "org.testcontainers.dockerclient.transport.okhttp.OkHttpDockerCmdExecFactory", - "org.testcontainers.dockerclient.transport.okhttp.UnixSocketFactory", - "org.testcontainers.containers.output.FrameConsumerResultCallback", - "org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback", - ] - - methodExcludes = [ - "org.testcontainers.dockerclient.DockerClientConfigUtils#getDetectedDockerHostIp()", - "org.testcontainers.dockerclient.DockerClientConfigUtils#getDockerHostIpAddress(com.github.dockerjava.core.DockerClientConfig)", - - "org.testcontainers.dockerclient.DockerClientProviderStrategy#checkOSType()", - "org.testcontainers.dockerclient.DockerClientProviderStrategy#getClientForConfig(com.github.dockerjava.core.DockerClientConfig)", - "org.testcontainers.dockerclient.DockerClientProviderStrategy#ping(com.github.dockerjava.api.DockerClient, int)", - "org.testcontainers.dockerclient.DockerClientProviderStrategy#test()", - - "org.testcontainers.dockerclient.UnixSocketClientProviderStrategy#tryConfiguration(java.lang.String)", - - "org.testcontainers.utility.ResourceReaper#start(java.lang.String, com.github.dockerjava.api.DockerClient, boolean)", + classExcludes = [] - "org.testcontainers.containers.Container#fetchDockerDaemonInfo()", - "org.testcontainers.containers.Container#getDockerDaemonInfo()", + methodExcludes = [] - "org.testcontainers.containers.GenericContainer#fetchDockerDaemonInfo()", - "org.testcontainers.containers.GenericContainer#getDockerDaemonInfo()", - - "org.testcontainers.containers.Container\$ExecResult#Container\$ExecResult(java.lang.String, java.lang.String)", - ] - - fieldExcludes = [ - "org.testcontainers.containers.GenericContainer#containerId", - "org.testcontainers.containers.GenericContainer#containerName", - "org.testcontainers.containers.GenericContainer#dockerDaemonInfo", - - "org.testcontainers.dockerclient.DockerClientProviderStrategy#LOGGER", - "org.testcontainers.dockerclient.DockerClientProviderStrategy#client", - "org.testcontainers.dockerclient.DockerClientProviderStrategy#config", - ] + fieldExcludes = [] onlyBinaryIncompatibleModified = true htmlOutputFile = file("$buildDir/reports/japi.html") From b86410e694f54c28ecf2c25448ff86c7b37c82ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 08:19:18 +0000 Subject: [PATCH 1302/4969] Bump assertj-core from 3.18.1 to 3.19.0 in /modules/pulsar Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.1 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.1...assertj-core-3.19.0) Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 92cf910f259..61e1208381d 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' - testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.18.1' + testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.19.0' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' } From c903ae0b17c82f18153b99d0a65f163d0c88079c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 08:19:21 +0000 Subject: [PATCH 1303/4969] Bump assertj-core from 3.14.0 to 3.19.0 in /examples Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.14.0 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.19.0) Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 1ba81fda105..cb1e9e31e7b 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -11,7 +11,7 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:1.18.10" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:2.8.0' - testImplementation 'org.assertj:assertj-core:3.14.0' + testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'com.google.guava:guava:23.0' testImplementation 'org.slf4j:slf4j-simple:1.7.30' } From c75a9dc96d523b119d4b513e8b6d9e9a23e999a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 08:19:24 +0000 Subject: [PATCH 1304/4969] Bump assertj-core from 3.18.1 to 3.19.0 in /modules/kafka Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.1 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.1...assertj-core-3.19.0) Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 56abadbce47..bb112755352 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation 'org.apache.kafka:kafka-clients:2.8.0' - testImplementation 'org.assertj:assertj-core:3.18.1' + testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'com.google.guava:guava:23.0' } From ae8926f712815790cc80c5defd73ad44641de1cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 08:19:37 +0000 Subject: [PATCH 1305/4969] Bump assertj-core from 3.18.1 to 3.19.0 in /core Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.1 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.1...assertj-core-3.19.0) Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 1c469f379d1..adc97a6c69f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -147,7 +147,7 @@ dependencies { testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testImplementation 'org.assertj:assertj-core:3.18.1' + testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" From edbad59ef7e7874c17b2c976858bb742ea93864e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 08:19:41 +0000 Subject: [PATCH 1306/4969] Bump assertj-core from 3.18.1 to 3.19.0 in /modules/junit-jupiter Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.18.1 to 3.19.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.18.1...assertj-core-3.19.0) Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index a21a97824ed..ab2477ed883 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testImplementation ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') } - testImplementation 'org.assertj:assertj-core:3.18.1' + testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' testRuntimeOnly 'org.postgresql:postgresql:42.2.20' From eac7bbb963ee8233a90e537b495c2fa7e5a0ef86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 08:33:37 +0000 Subject: [PATCH 1307/4969] Bump org.springframework.boot from 2.4.1 to 2.5.0 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.4.1 to 2.5.0. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.4.1...v2.5.0) Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index a671c1832fe..bcd2f97100b 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.4.1' + id 'org.springframework.boot' version '2.5.0' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 61a74a3950e..3f3469f8548 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.4.1" + id("org.springframework.boot") version "2.5.0" id("org.jetbrains.kotlin.jvm") version "1.5.10" id("org.jetbrains.kotlin.plugin.spring") version "1.5.10" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index ce2c028f83a..33f5b9aa878 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.4.1' + id 'org.springframework.boot' version '2.5.0' } apply plugin: 'io.spring.dependency-management' From 618dd80ac383221c18022548bfd7a20ad7695ce0 Mon Sep 17 00:00:00 2001 From: Fedor Korotkov Date: Mon, 14 Jun 2021 05:37:17 -0400 Subject: [PATCH 1308/4969] Fixed NPE when `getContextClassLoader()` returns `null` (#4193) --- .../main/java/org/testcontainers/utility/MountableFile.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 1982538f45d..071d36631b0 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -130,6 +130,10 @@ private static URL getClasspathResource(@NotNull final String resourcePath, @Not classLoadersToSearch.add(MountableFile.class.getClassLoader()); for (final ClassLoader classLoader : classLoadersToSearch) { + if (classLoader == null) { + continue; + } + URL resource = classLoader.getResource(resourcePath); if (resource != null) { return resource; From f2ec729b7fee7e7119a25e11269fbfadbc17e65d Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 17 Jun 2021 21:29:56 +0200 Subject: [PATCH 1309/4969] Update docker-java to 3.2.10 (#4202) --- core/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index adc97a6c69f..f4cdfbea410 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,9 +108,9 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } - api "com.github.docker-java:docker-java-api:3.2.8" + api "com.github.docker-java:docker-java-api:3.2.10" - shaded ('com.github.docker-java:docker-java-core:3.2.8') { + shaded ('com.github.docker-java:docker-java-core:3.2.10') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') @@ -119,13 +119,13 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.8') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.10') { exclude(group: 'com.github.docker-java', module: 'docker-java-core') exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } - api 'com.github.docker-java:docker-java-transport-zerodep:3.2.8' + api 'com.github.docker-java:docker-java-transport-zerodep:3.2.10' shaded "org.yaml:snakeyaml:1.29" From f68994f4a2af1940b29c0709b720c5b69680cc0e Mon Sep 17 00:00:00 2001 From: gradle-update-robot Date: Thu, 24 Jun 2021 00:06:26 +0000 Subject: [PATCH 1310/4969] Update Gradle Wrapper from 7.0.2 to 7.1. Signed-off-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 3 +- examples/gradlew | 4 +- examples/gradlew.bat | 193 ++++++++---------- 4 files changed, 93 insertions(+), 107 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.jar b/examples/gradle/wrapper/gradle-wrapper.jar index 62d4c053550b91381bbd28b1afc82d634bf73a8a..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 18328 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 Y(TzS~Xdo8@nTUZrK}a{fL*HNQe=4o%4FCWD delta 17568 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 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From ad264f0b0e47eba6005244d0ff58d26749002c42 Mon Sep 17 00:00:00 2001 From: gradle-update-robot Date: Thu, 24 Jun 2021 00:06:34 +0000 Subject: [PATCH 1311/4969] Update Gradle Wrapper from 7.0.2 to 7.1. Signed-off-by: gradle-update-robot --- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 6 +++--- gradlew | 4 +++- gradlew.bat | 25 +++++++---------------- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 26482 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 delta 22605 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4a66b0f1980..283500479a3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Apr 05 19:28:23 BST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionSha256Sum=a9e356a21595348b6f04b024ed0b08ac8aea6b2ac37e6c0ef58e51549cd7b9cb +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7d95e..744e882ed57 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 24467a141f7..ac1b06f9382 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From 6756ed465ea89d870a16de6a291e29e19364175a Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 25 Jun 2021 16:39:50 +0100 Subject: [PATCH 1312/4969] Remove GitHub Sponsors button --- docs/index.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/index.md b/docs/index.md index 139cbcd3f4e..16f61899947 100644 --- a/docs/index.md +++ b/docs/index.md @@ -93,10 +93,6 @@ testImplementation('org.testcontainers:mysql') //no version specified ## Sponsors -Testcontainers is on Github Sponsors! Please consider sponsoring us to sustain the project and help us improve it further. - - - A huge thank you to our sponsors: ### Bronze sponsors From e01c5a3214a0903fc3bf0dfc4c1fc3d5bc24e028 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 29 Jun 2021 11:23:34 +0100 Subject: [PATCH 1313/4969] Remove stalebot (#4216) --- .github/stale.yml | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 5f903fb0189..00000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,25 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 90 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 14 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security - - "resolution/acknowledged" - - "help wanted" - - "good first issue" -# Label to use when marking an issue as stale -staleLabel: stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. If you believe - this is a mistake, please reply to this comment to keep it open. If there isn't - one already, a PR to fix or at least reproduce the problem in a test case will - always help us get back on track to tackle this. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: > - This issue has been automatically closed due to inactivity. We apologise if - this is still an active problem for you, and would ask you to re-open the - issue if this is the case. From 271ae2f6cd864d3963da9908b677a837263c9885 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 29 Jun 2021 14:52:55 +0200 Subject: [PATCH 1314/4969] Update `docker-java` to 3.2.11 (#4220) --- core/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index f4cdfbea410..b27031af1bb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,9 +108,9 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } - api "com.github.docker-java:docker-java-api:3.2.10" + api "com.github.docker-java:docker-java-api:3.2.11" - shaded ('com.github.docker-java:docker-java-core:3.2.10') { + shaded ('com.github.docker-java:docker-java-core:3.2.11') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') @@ -119,13 +119,13 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.10') { + shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.11') { exclude(group: 'com.github.docker-java', module: 'docker-java-core') exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } - api 'com.github.docker-java:docker-java-transport-zerodep:3.2.10' + api 'com.github.docker-java:docker-java-transport-zerodep:3.2.11' shaded "org.yaml:snakeyaml:1.29" From 655110a6cefb5a7ea26628d15d27b8339b5001a2 Mon Sep 17 00:00:00 2001 From: Tobias Happ Date: Tue, 29 Jun 2021 18:25:45 +0200 Subject: [PATCH 1315/4969] Couchbase: Update to latest version, add flushEnabled flag (#4041) Co-authored-by: Richard North --- docs/modules/databases/couchbase.md | 7 +- modules/couchbase/AUTHORS | 1 + modules/couchbase/build.gradle | 3 +- .../couchbase/BucketDefinition.java | 16 ++++ .../couchbase/CouchbaseContainer.java | 1 + .../couchbase/CouchbaseContainerTest.java | 90 ++++++++++++------- 6 files changed, 78 insertions(+), 40 deletions(-) diff --git a/docs/modules/databases/couchbase.md b/docs/modules/databases/couchbase.md index f8ed7465dd9..e45a971f626 100644 --- a/docs/modules/databases/couchbase.md +++ b/docs/modules/databases/couchbase.md @@ -18,16 +18,11 @@ Running Couchbase as a stand-in in a test: [Container definition](../../../modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java) inside_block:container_definition -3. create an environment & cluster: +3. create an cluster: [Cluster creation](../../../modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java) inside_block:cluster_creation -4. authenticate: - - [Authentication](../../../modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java) inside_block:auth - - ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/couchbase/AUTHORS b/modules/couchbase/AUTHORS index db292de72f1..480841c2906 100644 --- a/modules/couchbase/AUTHORS +++ b/modules/couchbase/AUTHORS @@ -1 +1,2 @@ Tayeb Chlyah +Tobias Happ diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 88eb537269d..1ce51019607 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,5 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') - testImplementation 'com.couchbase.client:java-client:2.7.15' + testImplementation 'com.couchbase.client:java-client:3.1.6' + testImplementation 'org.awaitility:awaitility:3.0.0' } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java index 8c2b11403ad..3778833182e 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java @@ -22,6 +22,7 @@ public class BucketDefinition { private final String name; + private boolean flushEnabled = false; private boolean queryPrimaryIndex = true; private int quota = 100; @@ -29,6 +30,17 @@ public BucketDefinition(final String name) { this.name = name; } + /** + * Enables flush for this bucket (disabled by default). + * + * @param flushEnabled if true, the bucket can be flushed. + * @return this {@link BucketDefinition} for chaining purposes. + */ + public BucketDefinition withFlushEnabled(final boolean flushEnabled) { + this.flushEnabled = flushEnabled; + return this; + } + /** * Sets a custom bucket quota (100MB by default). * @@ -58,6 +70,10 @@ public String getName() { return name; } + public boolean hasFlushEnabled() { + return flushEnabled; + } + public boolean hasPrimaryIndex() { return queryPrimaryIndex; } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 8df5844f538..64489f30531 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -368,6 +368,7 @@ private void createBuckets() { @Cleanup Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder() .add("name", bucket.getName()) .add("ramQuotaMB", Integer.toString(bucket.getQuota())) + .add("flushEnabled", bucket.hasFlushEnabled() ? "1" : "0") .build(), true); checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName()); diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index 3a4438c1fc6..57b726eb663 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -18,16 +18,17 @@ import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; -import com.couchbase.client.java.CouchbaseCluster; -import com.couchbase.client.java.document.JsonDocument; -import com.couchbase.client.java.document.json.JsonObject; -import com.couchbase.client.java.env.CouchbaseEnvironment; -import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.json.JsonObject; import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import java.time.Duration; +import java.util.function.Consumer; + +import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; public class CouchbaseContainerTest { @@ -45,37 +46,60 @@ public void testBasicContainerUsage() { .withBucket(bucketDefinition) // } ) { - container.start(); - - // cluster_creation { - CouchbaseEnvironment environment = DefaultCouchbaseEnvironment - .builder() - .bootstrapCarrierDirectPort(container.getBootstrapCarrierDirectPort()) - .bootstrapHttpDirectPort(container.getBootstrapHttpDirectPort()) - .build(); - - Cluster cluster = CouchbaseCluster.create( - environment, - container.getHost() - ); - // } + setUpClient(container, cluster -> { + Bucket bucket = cluster.bucket(bucketDefinition.getName()); + bucket.waitUntilReady(Duration.ofSeconds(10L)); + + Collection collection = bucket.defaultCollection(); + + collection.upsert("foo", JsonObject.create().put("key", "value")); + + JsonObject fooObject = collection.get("foo").contentAsObject(); + + assertEquals("value", fooObject.getString("key")); + }); + } + } + + @Test + public void testBucketIsFlushableIfEnabled() { + BucketDefinition bucketDefinition = new BucketDefinition("mybucket") + .withFlushEnabled(true); - try { - // auth { - cluster.authenticate(container.getUsername(), container.getPassword()); - // } + try ( + CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE) + .withBucket(bucketDefinition) + ) { + setUpClient(container, cluster -> { + Bucket bucket = cluster.bucket(bucketDefinition.getName()); + bucket.waitUntilReady(Duration.ofSeconds(10L)); + + Collection collection = bucket.defaultCollection(); - Bucket bucket = cluster.openBucket(bucketDefinition.getName()); + collection.upsert("foo", JsonObject.create().put("key", "value")); - bucket.upsert(JsonDocument.create("foo", JsonObject.empty())); + cluster.buckets().flushBucket(bucketDefinition.getName()); - assertTrue(bucket.exists("foo")); - assertNotNull(cluster.clusterManager().getBucket(bucketDefinition.getName())); - } finally { - cluster.disconnect(); - environment.shutdown(); - } + await().untilAsserted(() -> assertFalse(collection.exists("foo").exists())); + }); } } + private void setUpClient(CouchbaseContainer container, Consumer consumer) { + container.start(); + + // cluster_creation { + Cluster cluster = Cluster.connect( + container.getConnectionString(), + container.getUsername(), + container.getPassword() + ); + // } + + try { + consumer.accept(cluster); + } finally { + cluster.disconnect(); + } + } } From adae983eb93bb83c97e7a6b49a0b83344865f83a Mon Sep 17 00:00:00 2001 From: Dennis Federico Date: Wed, 30 Jun 2021 11:24:45 +0200 Subject: [PATCH 1316/4969] Fix KafkaContainer with multiple networks defined (#4213) Current implementation exposes only two listeners PLAINTEXT and BROKER. BROKER must be advertised to explicitly specified network or bridge. If a host port is exposed using `Testcontainers.exposeHostPorts` and a network is specified, the container will be "attached" to an additional network, creating to listeners with the same name Configure the BROKER listener using the network specified (withNetwork) or "bridge" if not specified, instead of iterating over all the networks in the container info. Additional test cases when a port of the host is exposed (proxy container started) and a external network is specified to the container placing multiple network entries in the container info, making additional Kafka Broker listener entries with the same name "BROKER" Co-authored-by: Sergei Egorov --- .../containers/KafkaContainer.java | 38 ++++++++++++++----- .../containers/KafkaContainerTest.java | 19 ++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index b1bc3d735f9..d9c8e35e852 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -6,8 +6,7 @@ import org.testcontainers.utility.DockerImageName; import java.nio.charset.StandardCharsets; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.Comparator; /** * This container wraps Confluent Kafka and Zookeeper (optionally) @@ -122,13 +121,8 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole } command += "export KAFKA_ZOOKEEPER_CONNECT='" + zookeeperConnect + "'\n"; - command += "export KAFKA_ADVERTISED_LISTENERS='" + Stream - .concat( - Stream.of(getBootstrapServers()), - containerInfo.getNetworkSettings().getNetworks().values().stream() - .map(it -> "BROKER://" + it.getIpAddress() + ":9092") - ) - .collect(Collectors.joining(",")) + "'\n"; + + command += "export KAFKA_ADVERTISED_LISTENERS='" + String.join(",", getBootstrapServers(), brokerAdvertisedListener(containerInfo)) + "'\n"; command += ". /etc/confluent/docker/bash-config \n"; command += "/etc/confluent/docker/configure \n"; @@ -139,4 +133,30 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole STARTER_SCRIPT ); } + + protected String brokerAdvertisedListener(InspectContainerResponse containerInfo) { + // Kafka supports only one INTER_BROKER listener, so we have to pick one. + // The current algorithm uses the following order of resolving the IP: + // 1. Custom network's IP set via `withNetwork` + // 2. Bridge network's IP + // 3. Best effort fallback to getNetworkSettings#ipAddress + String ipAddress = containerInfo.getNetworkSettings().getNetworks().entrySet() + .stream() + .filter(it -> it.getValue().getIpAddress() != null) + .max(Comparator.comparingInt(entry -> { + if (getNetwork() != null && getNetwork().getId().equals(entry.getValue().getNetworkID())) { + return 2; + } + + if ("bridge".equals(entry.getKey())) { + return 1; + } + + return 0; + })) + .map(it -> it.getValue().getIpAddress()) + .orElseGet(() -> containerInfo.getNetworkSettings().getIpAddress()); + + return String.format("BROKER://%s:%s", ipAddress, "9092"); + } } diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index d219aa17b13..e16081d16d9 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -24,6 +24,7 @@ import org.junit.ClassRule; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.Testcontainers; import org.testcontainers.utility.DockerImageName; public class KafkaContainerTest { @@ -113,6 +114,24 @@ public void testConfluentPlatformVersion6() throws Exception { } } + @Test + public void testWithHostExposedPort() throws Exception { + Testcontainers.exposeHostPorts(12345); + try (KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE)) { + kafka.start(); + testKafkaFunctionality(kafka.getBootstrapServers()); + } + } + + @Test + public void testWithHostExposedPortAndExternalNetwork() throws Exception { + Testcontainers.exposeHostPorts(12345); + try (KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE).withNetwork(Network.newNetwork())) { + kafka.start(); + testKafkaFunctionality(kafka.getBootstrapServers()); + } + } + protected void testKafkaFunctionality(String bootstrapServers) throws Exception { testKafkaFunctionality(bootstrapServers, 1, 1); } From 40807676491effb9878fce92c11fe26303218e4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:27 +0000 Subject: [PATCH 1317/4969] Bump tomcat-jdbc from 10.0.6 to 10.0.7 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.6 to 10.0.7. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 87e33f804a0..99cba7dcb70 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.6' + api 'org.apache.tomcat:tomcat-jdbc:10.0.7' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.25' } From 18a3efd8003bb0a9d8ffdd70f8b0ab0d7b129ea3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:28 +0000 Subject: [PATCH 1318/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /modules/vault Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 50797658fbb..18897f66908 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testImplementation 'com.bettercloud:vault-java-driver:5.1.0' testImplementation 'io.rest-assured:rest-assured:4.4.0' - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' } From 36eaee53b29fb5841b286ac46e9e2ad80b848bae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:29 +0000 Subject: [PATCH 1319/4969] Bump awaitility from 3.0.0 to 4.1.0 in /modules/couchbase Bumps [awaitility](https://github.com/awaitility/awaitility) from 3.0.0 to 4.1.0. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-3.0.0...awaitility-4.1.0) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 1ce51019607..40f59128ec8 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':testcontainers') testImplementation 'com.couchbase.client:java-client:3.1.6' - testImplementation 'org.awaitility:awaitility:3.0.0' + testImplementation 'org.awaitility:awaitility:4.1.0' } From b1b04bdc7734ee9015e3ccb6f4685718f069814f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:29 +0000 Subject: [PATCH 1320/4969] Bump jedis from 3.6.0 to 3.6.1 in /modules/junit-jupiter Bumps [jedis](https://github.com/redis/jedis) from 3.6.0 to 3.6.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.6.0...jedis-3.6.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ab2477ed883..f33bff6398b 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:3.6.0' + testImplementation 'redis.clients:jedis:3.6.1' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testImplementation ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') From a6210dc258fa10a957941ed4a1dd6fce9614f5d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:30 +0000 Subject: [PATCH 1321/4969] Bump postgresql from 42.2.20 to 42.2.22 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.20 to 42.2.22. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.22/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.20...REL42.2.22) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index c44dbe7d009..9b7063e3a0c 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.2.20' + testImplementation 'org.postgresql:postgresql:42.2.22' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' From 50d4922384cc09139e5011f68729631972c981ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:30 +0000 Subject: [PATCH 1322/4969] Bump jedis from 3.6.0 to 3.6.1 in /core Bumps [jedis](https://github.com/redis/jedis) from 3.6.0 to 3.6.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.6.0...jedis-3.6.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b27031af1bb..7cbabcd4783 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -136,7 +136,7 @@ dependencies { } testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' - testImplementation 'redis.clients:jedis:3.6.0' + testImplementation 'redis.clients:jedis:3.6.1' testImplementation 'com.rabbitmq:amqp-client:5.12.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.7' From cb12788039131c1a6c2d5a8f7b450c3d3cb7fcad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:30 +0000 Subject: [PATCH 1323/4969] Bump postgresql from 42.2.20 to 42.2.22 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.20 to 42.2.22. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.22/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.20...REL42.2.22) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index eb82bdcfc41..6ee936b7ca7 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.2.20' + testRuntimeOnly 'org.postgresql:postgresql:42.2.22' testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' testCompileClasspath 'org.jetbrains:annotations:21.0.1' From 496728436f742052acbbfc2b191715bc1917c828 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:30 +0000 Subject: [PATCH 1324/4969] Bump aws-java-sdk-s3 from 1.11.1030 to 1.12.16 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.11.1030 to 1.12.16. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.1030...1.12.16) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 87cc407468d..6d7b683200c 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.1030' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.16' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.1' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.11.807' From 9974c8f02d36d8916349c5a53b76f5fcfb3de8ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:30 +0000 Subject: [PATCH 1325/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /modules/jdbc Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 16b95af77bf..2f776044169 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -11,5 +11,5 @@ dependencies { testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' } From ce5c685d18229fafbd5a0356d676d82f841ba959 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:30 +0000 Subject: [PATCH 1326/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /modules/kafka Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index bb112755352..c83859e0c20 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation 'org.apache.kafka:kafka-clients:2.8.0' - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'com.google.guava:guava:23.0' } From 10768c88d4db87e0adf88f326fba4e909295e008 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:31 +0000 Subject: [PATCH 1327/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /modules/junit-jupiter Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ab2477ed883..b333b71c1b6 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testImplementation ('org.mockito:mockito-core:3.10.0') { exclude(module: 'hamcrest-core') } - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' testRuntimeOnly 'org.postgresql:postgresql:42.2.20' From 5189aebedfc13b643c9b4daf65672ccef2bfc90f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:31 +0000 Subject: [PATCH 1328/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.11.1030 to 1.12.16. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.1030...1.12.16) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index e3a49df5be2..c92b1969147 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.16' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From b1ada036d900e60b8e6c7e978d53c66d0e0d7431 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:32 +0000 Subject: [PATCH 1329/4969] Bump org.springframework.boot from 2.5.0 to 2.5.2 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.5.0 to 2.5.2. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.5.0...v2.5.2) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index bcd2f97100b..70c4a2683b0 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.0' + id 'org.springframework.boot' version '2.5.2' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 3f3469f8548..d39de1a995d 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.5.0" + id("org.springframework.boot") version "2.5.2" id("org.jetbrains.kotlin.jvm") version "1.5.10" id("org.jetbrains.kotlin.plugin.spring") version "1.5.10" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 33f5b9aa878..00f6f22728d 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.0' + id 'org.springframework.boot' version '2.5.2' } apply plugin: 'io.spring.dependency-management' From 5514570afcf8e6537174f2e8b725851c6c5ee5e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:33 +0000 Subject: [PATCH 1330/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /modules/neo4j Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index f556c96095a..08eda371597 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { api project(":testcontainers") testImplementation "org.neo4j.driver:neo4j-java-driver:1.7.5" - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' } From 7ebefec50e0adaaaee3ab084dbca689479d3ecde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:34 +0000 Subject: [PATCH 1331/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /modules/pulsar Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 61e1208381d..478c47fff29 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' - testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.19.0' + testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.20.2' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' } From 3b8149d89f575378fa50959f63f35c1e2db5a464 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:34 +0000 Subject: [PATCH 1332/4969] Bump postgresql from 42.2.20 to 42.2.22 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.20 to 42.2.22. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.22/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.20...REL42.2.22) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ab2477ed883..8c97073a540 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' - testRuntimeOnly 'org.postgresql:postgresql:42.2.20' + testRuntimeOnly 'org.postgresql:postgresql:42.2.22' testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } From dd68c10acf0200c4640bb7c55b810902d695f98d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:35 +0000 Subject: [PATCH 1333/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /examples Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index cb1e9e31e7b..79c14941c11 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -11,7 +11,7 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:1.18.10" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:2.8.0' - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'com.google.guava:guava:23.0' testImplementation 'org.slf4j:slf4j-simple:1.7.30' } From 9eed46bf9e3290682b7a0528a043958925abe7e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:35 +0000 Subject: [PATCH 1334/4969] Bump mockito-core from 3.10.0 to 3.11.2 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 3.10.0 to 3.11.2. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.10.0...v3.11.2) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b27031af1bb..762e30054e7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -140,7 +140,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.12.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.7' - testImplementation ('org.mockito:mockito-core:3.10.0') { + testImplementation ('org.mockito:mockito-core:3.11.2') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 17bdb7ce09e79b896501a1fe0513de49ddb9354b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:35 +0000 Subject: [PATCH 1335/4969] Bump transport from 7.13.1 to 7.13.2 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.13.1 to 7.13.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.13.1...v7.13.2) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index e1921e755f8..67e03df2945 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.13.0" - testImplementation "org.elasticsearch.client:transport:7.13.1" + testImplementation "org.elasticsearch.client:transport:7.13.2" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From a027522e063de7d43a06706e771f63df14327213 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:38 +0000 Subject: [PATCH 1336/4969] Bump mockito-core from 3.10.0 to 3.11.2 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 3.10.0 to 3.11.2. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.10.0...v3.11.2) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ab2477ed883..3203f13ca11 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:3.6.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:3.10.0') { + testImplementation ('org.mockito:mockito-core:3.11.2') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.19.0' From be077663330869adcad683faac658ae04a6078fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:40 +0000 Subject: [PATCH 1337/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.5.10 to 1.5.20. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 3f3469f8548..bd1e474b411 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.5.0" id("org.jetbrains.kotlin.jvm") version "1.5.10" - id("org.jetbrains.kotlin.plugin.spring") version "1.5.10" + id("org.jetbrains.kotlin.plugin.spring") version "1.5.20" } apply plugin: 'io.spring.dependency-management' From 58960f3a5c1b431424664fbde7a61c48d54c2f23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:40 +0000 Subject: [PATCH 1338/4969] Bump solr-solrj from 8.8.2 to 8.9.0 in /examples Bumps solr-solrj from 8.8.2 to 8.9.0. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index e0a6f356a77..d416c4d8c45 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.16" - implementation 'org.apache.solr:solr-solrj:8.8.2' + implementation 'org.apache.solr:solr-solrj:8.9.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From 47afef9c6bf274d8318a19317af08f47d0e98ae6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:41 +0000 Subject: [PATCH 1339/4969] Bump aws-java-sdk-logs from 1.11.807 to 1.12.16 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.11.807 to 1.12.16. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.11.807...1.12.16) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 87cc407468d..08e8202e09b 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.1' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.11.807' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.16' testImplementation 'software.amazon.awssdk:s3:2.16.80' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From c797df1bd6b2cc6323ac4a8589399645b5157e54 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:47 +0000 Subject: [PATCH 1340/4969] Bump postgresql from 42.2.20 to 42.2.22 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.20 to 42.2.22. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.22/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.20...REL42.2.22) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index edb545e79d3..c5706da277a 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'org.json:json:20210307' - testImplementation 'org.postgresql:postgresql:42.2.20' + testImplementation 'org.postgresql:postgresql:42.2.22' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From 37bdb1cb6c42a12cd8bdb50749216b7c6e5787fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:00:50 +0000 Subject: [PATCH 1341/4969] Bump gson from 2.8.6 to 2.8.7 in /examples Bumps [gson](https://github.com/google/gson) from 2.8.6 to 2.8.7. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.8.6...gson-parent-2.8.7) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 82d1bb548ee..04d8f249511 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.20" implementation 'biz.paluch.redis:spinach:0.3' - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.mockito:mockito-all:1.10.19' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index c19c5b22f23..aad845a5d78 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'redis.clients:jedis:3.6.0' - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index a968a6d2bf3..f1c900708ae 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'redis.clients:jedis:3.6.0' - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index dfbe856ea62..490f85abfeb 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation 'redis.clients:jedis:3.6.0' - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.30' From 149882905ddc7a1672ce8cfe8d5292eee1ed68bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:01:08 +0000 Subject: [PATCH 1342/4969] Bump actions/github-script from 3 to 4.0.2 Bumps [actions/github-script](https://github.com/actions/github-script) from 3 to 4.0.2. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v3...v4.0.2) --- updated-dependencies: - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/combine-prs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index 749cc648fb5..e1d96a20895 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -30,7 +30,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v4.0.2 id: fetch-branch-names name: Fetch branch names with: @@ -121,7 +121,7 @@ jobs: git pull origin $sourcebranches --no-edit git push origin $COMBINE_BRANCH_NAME # Creates a PR with the new combined branch - - uses: actions/github-script@v3 + - uses: actions/github-script@v4.0.2 name: Create Combined Pull Request with: github-token: ${{secrets.GITHUB_TOKEN}} From 9cd1a5abe8f3a3a9056ed66561d71a6e0e3e1a27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 22:01:13 +0000 Subject: [PATCH 1343/4969] Bump gradle-update/update-gradle-wrapper-action from 1.0.13 to 1.0.14 Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 1.0.13 to 1.0.14. - [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases) - [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/af940e8bff73d435137caae9d08cf7a1badf5497...6356f411fa7c14aab1fb2ac2fd20762a629e2fbf) --- updated-dependencies: - dependency-name: gradle-update/update-gradle-wrapper-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 329230640e7..272594c26df 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@af940e8bff73d435137caae9d08cf7a1badf5497 # v1.0.13 + uses: gradle-update/update-gradle-wrapper-action@6356f411fa7c14aab1fb2ac2fd20762a629e2fbf # v1.0.13 with: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies From 5d87f611fb628a201f30690b9141188754da0699 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 8 Jul 2021 11:35:31 +0100 Subject: [PATCH 1344/4969] Switch from using Travis to GitHub Actions for release (#3434) --- .github/workflows/release.yml | 31 +++++++++++++++++++++++++++++++ .travis.yml | 24 ------------------------ README.md | 2 -- build.gradle | 16 ---------------- gradle/bintray.gradle | 24 ------------------------ gradle/publishing.gradle | 21 +++++++++++++++++---- 6 files changed, 48 insertions(+), 70 deletions(-) create mode 100644 .github/workflows/release.yml delete mode 100644 .travis.yml delete mode 100644 gradle/bintray.gradle diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000000..943dfcf005a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,31 @@ +name: Release + +on: + release: + types: [published] + +env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + +jobs: + release: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '1.8' + - name: Clear existing docker image cache + run: docker image prune -af + + - name: Run Gradle Build + run: ./gradlew build --scan --no-daemon -i + + - name: Run Gradle Publish + run: | + ./gradlew publish \ + -Pversion="${{github.event.release.tag_name}}" --scan --no-daemon -i + env: + OSSRH_USERNAME: ${{secrets.OSSRH_USERNAME}} + OSSRH_PASSWORD: ${{secrets.OSSRH_PASSWORD}} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ec7a5d343d9..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -if: tag is present - -language: java -jdk: - - openjdk8 - -sudo: required -services: - - docker - -jobs: - include: - - - stage: deploy - sudo: false - services: [] - install: skip - script: skip - deploy: - provider: script - script: ./gradlew -Pversion=$TRAVIS_TAG release --scan --no-daemon -i - on: - tags: true - branch: master diff --git a/README.md b/README.md index c87138e7d1a..d3446cbb31e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ > Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. -[![Build Status](https://travis-ci.org/testcontainers/testcontainers-java.svg?branch=master)](https://travis-ci.org/testcontainers/testcontainers-java)[ ![Download](https://api.bintray.com/packages/testcontainers/releases/testcontainers/images/download.svg) ](https://bintray.com/testcontainers/releases/testcontainers/_latestVersion) - ![Testcontainers logo](docs/logo.png) # [Read the documentation here](http://www.testcontainers.org) diff --git a/build.gradle b/build.gradle index 40f5bfed399..98b9b5a30bc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,6 @@ plugins { id 'io.franzbecker.gradle-lombok' version '4.0.0' id 'com.github.johnrengelman.shadow' version '7.0.0' - id "com.jfrog.bintray" version "1.8.4" apply false } apply from: "$rootDir/gradle/ci-support.gradle" @@ -20,7 +19,6 @@ subprojects { compileTestJava.options.encoding = 'UTF-8' repositories { - jcenter() mavenCentral() } @@ -48,20 +46,6 @@ subprojects { // specific modules should be excluded from publication if ( ! ["test-support", "jdbc-test"].contains(it.name) && !it.path.startsWith(":docs:") && it != project(":docs") ) { apply from: "$rootDir/gradle/publishing.gradle" - apply from: "$rootDir/gradle/bintray.gradle" - - jar.archiveClassifier.set("original") - - publishing { - publications { - mavenJava(MavenPublication) { publication -> - artifacts.removeAll { it.classifier == jar.archiveClassifier.get() } - artifact project.tasks.shadowJar - } - } - } - - task release(dependsOn: bintrayUpload) } test { diff --git a/gradle/bintray.gradle b/gradle/bintray.gradle deleted file mode 100644 index 5ddfefd8e49..00000000000 --- a/gradle/bintray.gradle +++ /dev/null @@ -1,24 +0,0 @@ -apply plugin: "com.jfrog.bintray" - -bintray { - user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') - key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') - - publications = ['mavenJava'] - - pkg { - userOrg = 'testcontainers' - repo = 'releases' - name = 'testcontainers' - - publish = true - override = true - - version { - name = project.version - vcsTag = project.version - released = new Date() - gpg.sign = true - } - } -} diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 84fad9994e5..e6bf5d2acbd 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -1,24 +1,28 @@ apply plugin: 'maven-publish' task sourceJar(type: Jar) { - classifier = 'sources' + archiveClassifier.set( 'sources') from sourceSets.main.allJava } task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' + archiveClassifier.set('javadoc') from javadoc } +jar.archiveClassifier.set("original") + publishing { publications { mavenJava(MavenPublication) { publication -> artifactId = project.name - - artifact project.tasks.jar artifact sourceJar artifact javadocJar + artifact project.tasks.jar + artifacts.removeAll { it.classifier == jar.archiveClassifier.get() } + artifact project.tasks.shadowJar + pom.withXml { def rootNode = asNode() rootNode.children().last() + { @@ -77,4 +81,13 @@ publishing { } } } + repositories { + maven { + url("https://oss.sonatype.org/service/local/staging/deploy/maven2") + credentials { + username = System.getenv("OSSRH_USERNAME") + password = System.getenv("OSSRH_PASSWORD") + } + } + } } From c3429ac64c8cbf86180739e2ef4c09831a024c5d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 11:42:19 +0100 Subject: [PATCH 1345/4969] Update Gradle Wrapper to 7.1.1 (#4266) Co-authored-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 234b6472e12..2957f437446 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=2debee19271e1b82c6e41137d78e44e6e841035230a1a169ca47fd3fb09ed87b -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip +distributionSha256Sum=bf8b869948901d422e9bb7d1fa61da6a6e19411baa7ad6ee929073df85d6365d +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 283500479a3..17ba19021b8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=a9e356a21595348b6f04b024ed0b08ac8aea6b2ac37e6c0ef58e51549cd7b9cb -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip +distributionSha256Sum=9bb8bc05f562f2d42bdf1ba8db62f6b6fa1c3bf6c392228802cc7cb0578fe7e0 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From a3f659f7a3bbcac1782dac8a8a0a9ec9bc66f416 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:03:29 +0000 Subject: [PATCH 1346/4969] Bump s3 from 2.16.80 to 2.16.97 in /modules/localstack Bumps s3 from 2.16.80 to 2.16.97. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3770c37f4e3..ca14658a287 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.1' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.16' - testImplementation 'software.amazon.awssdk:s3:2.16.80' + testImplementation 'software.amazon.awssdk:s3:2.16.97' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 4a83864aab94dd8f9fe94849ffd2b5f30d1f582f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:03:31 +0000 Subject: [PATCH 1347/4969] Bump tomcat-jdbc from 10.0.6 to 10.0.8 in /modules/jdbc Bumps tomcat-jdbc from 10.0.6 to 10.0.8. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 2f776044169..4f6c6608b4d 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:21.0.1' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.6' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.8' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 590676316d27945ccf632b6fc0caadb5e7e1cd73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:03:31 +0000 Subject: [PATCH 1348/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /modules/database-commons Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 7bba8548c95..35578b55d68 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { api project(':testcontainers') - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' } From 30cbc6937e2b04f4607df26d65144c57a2a1ef64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:03:41 +0000 Subject: [PATCH 1349/4969] Bump aws-java-sdk-sqs from 1.12.1 to 1.12.19 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.1 to 1.12.19. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.1...1.12.19) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3770c37f4e3..802905df563 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.16' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.1' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.19' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.16' testImplementation 'software.amazon.awssdk:s3:2.16.80' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 6df76958c9bfad06f90169e699f199399ba01446 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:03:45 +0000 Subject: [PATCH 1350/4969] Bump assertj-core from 3.19.0 to 3.20.2 in /core Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.19.0 to 3.20.2. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.19.0...assertj-core-3.20.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 2634bc4cae6..384c1caf1f2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -147,13 +147,13 @@ dependencies { testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testImplementation 'org.assertj:assertj-core:3.19.0' + testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestImplementation 'junit:junit:4.12' - jarFileTestImplementation 'org.assertj:assertj-core:3.18.1' + jarFileTestImplementation 'org.assertj:assertj-core:3.20.2' jarFileTestImplementation 'org.ow2.asm:asm-debug-all:5.2' } From 6d1c0d6847c3fc11cba09dc0cce2e186407b39cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:03:49 +0000 Subject: [PATCH 1351/4969] Bump jedis from 3.6.0 to 3.6.1 in /examples Bumps [jedis](https://github.com/redis/jedis) from 3.6.0 to 3.6.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.6.0...jedis-3.6.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index aad845a5d78..58f31827717 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.6.0' + implementation 'redis.clients:jedis:3.6.1' implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index f1c900708ae..4fb93cb71b5 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' - implementation 'redis.clients:jedis:3.6.0' + implementation 'redis.clients:jedis:3.6.1' implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 490f85abfeb..e803f616998 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.6.0' + implementation 'redis.clients:jedis:3.6.1' implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.30' From f4c1add362eda0ef684baf975aa17052ba8455f6 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 16 Jul 2021 12:00:59 +0200 Subject: [PATCH 1352/4969] Use Apache HttpClient5 transport as the default (#4287) --- .../org/testcontainers/utility/TestcontainersConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 9b2ab707a2e..2f3f4370e50 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -176,7 +176,7 @@ public String getDockerClientStrategyClassName() { } public String getTransportType() { - return getEnvVarOrProperty("transport.type", "okhttp"); + return getEnvVarOrProperty("transport.type", "httpclient5"); } public Integer getImagePullPauseTimeout() { From 014500b18964e9780355a8c5c7152632357124ef Mon Sep 17 00:00:00 2001 From: Tobias Happ Date: Fri, 16 Jul 2021 13:08:27 +0200 Subject: [PATCH 1353/4969] Add support for community edition of couchbase server (#4221) --- .../couchbase/CouchbaseContainer.java | 18 +++++++++- .../couchbase/CouchbaseContainerTest.java | 34 ++++++++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 64489f30531..844917c053f 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -88,6 +88,8 @@ public class CouchbaseContainer extends GenericContainer { private final List buckets = new ArrayList<>(); + private boolean isEnterprise = false; + /** * Creates a new couchbase container with the default image and version. * @deprecated use {@link CouchbaseContainer(DockerImageName)} instead @@ -220,6 +222,7 @@ protected void containerIsStarting(final InspectContainerResponse containerInfo) logger().debug("Couchbase container is starting, performing configuration."); waitUntilNodeIsOnline(); + initializeIsEnterprise(); renameNode(); initializeServices(); configureAdminUser(); @@ -246,6 +249,19 @@ private void waitUntilNodeIsOnline() { .waitUntilReady(this); } + /** + * Fetches edition (enterprise or community) of started container. + */ + private void initializeIsEnterprise() { + @Cleanup Response response = doHttpRequest(MGMT_PORT, "/pools", "GET", null, true); + + try { + isEnterprise = MAPPER.readTree(response.body().string()).get("isEnterprise").asBoolean(); + } catch (IOException e) { + throw new IllegalStateException("Couchbase /pools did not return valid JSON"); + } + } + /** * Rebinds/renames the internal hostname. *

@@ -349,7 +365,7 @@ private void configureIndexer() { logger().debug("Configuring the indexer service"); @Cleanup Response response = doHttpRequest(MGMT_PORT, "/settings/indexes", "POST", new FormBody.Builder() - .add("storageMode", "memory_optimized") + .add("storageMode", isEnterprise ? "memory_optimized" : "forestdb") .build(), true ); diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index 57b726eb663..fcebbe2bb62 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -32,17 +32,20 @@ public class CouchbaseContainerTest { - private static final DockerImageName COUCHBASE_IMAGE = DockerImageName.parse("couchbase/server:6.5.1"); + private static final DockerImageName COUCHBASE_IMAGE_ENTERPRISE = + DockerImageName.parse("couchbase/server:enterprise-6.6.2"); + private static final DockerImageName COUCHBASE_IMAGE_COMMUNITY = + DockerImageName.parse("couchbase/server:community-6.6.0"); @Test - public void testBasicContainerUsage() { + public void testBasicContainerUsageForEnterpriseContainer() { // bucket_definition { BucketDefinition bucketDefinition = new BucketDefinition("mybucket"); // } try ( // container_definition { - CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE) + CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_ENTERPRISE) .withBucket(bucketDefinition) // } ) { @@ -61,13 +64,36 @@ public void testBasicContainerUsage() { } } + @Test + public void testBasicContainerUsageForCommunityContainer() { + BucketDefinition bucketDefinition = new BucketDefinition("mybucket"); + + try ( + CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) + .withBucket(bucketDefinition) + ) { + setUpClient(container, cluster -> { + Bucket bucket = cluster.bucket(bucketDefinition.getName()); + bucket.waitUntilReady(Duration.ofSeconds(10L)); + + Collection collection = bucket.defaultCollection(); + + collection.upsert("foo", JsonObject.create().put("key", "value")); + + JsonObject fooObject = collection.get("foo").contentAsObject(); + + assertEquals("value", fooObject.getString("key")); + }); + } + } + @Test public void testBucketIsFlushableIfEnabled() { BucketDefinition bucketDefinition = new BucketDefinition("mybucket") .withFlushEnabled(true); try ( - CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE) + CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_ENTERPRISE) .withBucket(bucketDefinition) ) { setUpClient(container, cluster -> { From e89dce16e6471513772aa2a9dbb67430740b13b7 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Fri, 16 Jul 2021 08:55:50 -0400 Subject: [PATCH 1354/4969] Allow for docker timestamps with timezone offsets (#4073) Docker prefers to use UTC time when making images/containers, but it's happy to parse non-UTC times too. It will then pass those on in its output. DateTimeFormatter.ISO_OFFSET_DATE_TIME accepts a superset of what DateTimeFormatter.ISO_INSTANT accepts, so replace use of ISO_INSTANT with ISO_OFFSET_DATE_TIME. Co-authored-by: Richard North --- .../testcontainers/utility/DockerStatus.java | 4 +- .../utility/DockerStatusTest.java | 53 ++++++++++++------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/DockerStatus.java b/core/src/main/java/org/testcontainers/utility/DockerStatus.java index 63b19db410b..a410597dcfb 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerStatus.java +++ b/core/src/main/java/org/testcontainers/utility/DockerStatus.java @@ -40,7 +40,7 @@ public static boolean isContainerRunning(InspectContainerResponse.ContainerState if (minimumRunningDuration == null) { return true; } - Instant startedAt = DateTimeFormatter.ISO_INSTANT.parse( + Instant startedAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse( state.getStartedAt(), Instant::from); if (startedAt.isBefore(now.minus(minimumRunningDuration))) { @@ -75,7 +75,7 @@ public static boolean isDockerTimestampNonEmpty(String dockerTimestamp) { return dockerTimestamp != null && !dockerTimestamp.isEmpty() && !dockerTimestamp.equals(DOCKER_TIMESTAMP_ZERO) - && DateTimeFormatter.ISO_INSTANT.parse(dockerTimestamp, Instant::from).getEpochSecond() >= 0L; + && DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(dockerTimestamp, Instant::from).getEpochSecond() >= 0L; } public static boolean isContainerExitCodeSuccess(InspectContainerResponse.ContainerState state) { diff --git a/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java b/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java index 4b63719f928..1ef8e136a32 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java @@ -2,10 +2,13 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import org.mockito.Mockito; import java.time.Duration; import java.time.Instant; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import static org.junit.Assert.assertFalse; @@ -15,33 +18,47 @@ /** * */ + @RunWith(Parameterized.class) public class DockerStatusTest { + private final DateTimeFormatter dateTimeFormatter; - private static Instant now = Instant.now(); + private static final Instant now = Instant.now(); - private static InspectContainerResponse.ContainerState running = - buildState(true, false, buildTimestamp(now.minusMillis(30)), DockerStatus.DOCKER_TIMESTAMP_ZERO); + private final InspectContainerResponse.ContainerState running; - private static InspectContainerResponse.ContainerState runningVariant = - buildState(true, false, buildTimestamp(now.minusMillis(30)), ""); + private final InspectContainerResponse.ContainerState runningVariant; - private static InspectContainerResponse.ContainerState shortRunning = - buildState(true, false, buildTimestamp(now.minusMillis(10)), DockerStatus.DOCKER_TIMESTAMP_ZERO); + private final InspectContainerResponse.ContainerState shortRunning; - private static InspectContainerResponse.ContainerState created = - buildState(false, false, DockerStatus.DOCKER_TIMESTAMP_ZERO, DockerStatus.DOCKER_TIMESTAMP_ZERO); + private final InspectContainerResponse.ContainerState created; // a container in the "created" state is not running, and has both startedAt and finishedAt empty. - private static InspectContainerResponse.ContainerState createdVariant = - buildState(false, false, null, null); + private final InspectContainerResponse.ContainerState createdVariant; - private static InspectContainerResponse.ContainerState exited = - buildState(false, false, buildTimestamp(now.minusMillis(100)), buildTimestamp(now.minusMillis(90))); + private final InspectContainerResponse.ContainerState exited; - private static InspectContainerResponse.ContainerState paused = - buildState(false, true, buildTimestamp(now.minusMillis(100)), DockerStatus.DOCKER_TIMESTAMP_ZERO); + private final InspectContainerResponse.ContainerState paused; - private static Duration minimumDuration = Duration.ofMillis(20); + private static final Duration minimumDuration = Duration.ofMillis(20); + + public DockerStatusTest(DateTimeFormatter dateTimeFormatter) { + this.dateTimeFormatter = dateTimeFormatter; + running = buildState(true, false, buildTimestamp(now.minusMillis(30)), DockerStatus.DOCKER_TIMESTAMP_ZERO); + runningVariant = buildState(true, false, buildTimestamp(now.minusMillis(30)), ""); + shortRunning = buildState(true, false, buildTimestamp(now.minusMillis(10)), DockerStatus.DOCKER_TIMESTAMP_ZERO); + created = buildState(false, false, DockerStatus.DOCKER_TIMESTAMP_ZERO, DockerStatus.DOCKER_TIMESTAMP_ZERO); + createdVariant = buildState(false, false, null, null); + exited = buildState(false, false, buildTimestamp(now.minusMillis(100)), buildTimestamp(now.minusMillis(90))); + paused = buildState(false, true, buildTimestamp(now.minusMillis(100)), DockerStatus.DOCKER_TIMESTAMP_ZERO); + } + + @Parameterized.Parameters + public static Object[][] parameters() { + return new Object[][] { + { DateTimeFormatter.ISO_INSTANT}, + { DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.of("America/New_York")) } + }; + } @Test public void testRunning() throws Exception { @@ -65,8 +82,8 @@ public void testStopped() throws Exception { assertFalse(DockerStatus.isContainerStopped(paused)); } - private static String buildTimestamp(Instant instant) { - return DateTimeFormatter.ISO_INSTANT.format(instant); + private String buildTimestamp(Instant instant) { + return dateTimeFormatter.format(instant); } // ContainerState is a non-static inner class, with private member variables, in a different package. From bfd61d7eda8502c2bd93542fa45a509fd6ecfea8 Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 18 Jul 2021 15:53:53 +0100 Subject: [PATCH 1355/4969] Use implicit strategy when `docker.host` configuration is set (#4175) --- .../utility/TestcontainersConfiguration.java | 24 ++++++++++++++- .../TestcontainersConfigurationTest.java | 29 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 2f3f4370e50..fddeec9c9b7 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.testcontainers.UnstableAPI; +import org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy; import java.io.File; import java.io.FileNotFoundException; @@ -23,6 +24,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; @@ -172,7 +174,27 @@ public String getDockerClientStrategyClassName() { // Because of this overlap, and the desire to not change this specific TESTCONTAINERS_DOCKER_CLIENT_STRATEGY setting, // we special-case the logic here so that docker.client.strategy is used when reading properties files and // TESTCONTAINERS_DOCKER_CLIENT_STRATEGY is used when searching environment variables. - return getEnvVarOrUserProperty("docker.client.strategy", environment.get("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY")); + + // looks for TESTCONTAINERS_ prefixed env var only + String prefixedEnvVarStrategy = environment.get("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY"); + if (prefixedEnvVarStrategy != null) { + return prefixedEnvVarStrategy; + } + + // looks for unprefixed env var or unprefixed property + String unprefixedEnvVarOrProperty = getEnvVarOrUserProperty("docker.client.strategy", null); + if (unprefixedEnvVarOrProperty != null) { + return unprefixedEnvVarOrProperty; + } + + // If docker.host is set then EnvironmentAndSystemPropertyClientProviderStrategy is likely to work + String dockerHostProperty = getEnvVarOrUserProperty("docker.host", null); + if (dockerHostProperty != null) { + return EnvironmentAndSystemPropertyClientProviderStrategy.class.getCanonicalName(); + } + + // No value set, and no implicit value to use either + return null; } public String getTransportType() { diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index 0fca36f0f2f..ff56f62e4e4 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -2,6 +2,7 @@ import org.junit.Before; import org.junit.Test; +import org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy; import java.util.HashMap; import java.util.Map; @@ -155,6 +156,34 @@ public void shouldReadDockerClientStrategyFromEnvironment() { assertEquals("Docker client strategy is changed by env var", "foo", newConfig().getDockerClientStrategyClassName()); } + @Test + public void shouldUseImplicitDockerClientStrategyWhenDockerHostPropertyIsSet() { + userProperties.remove("docker.client.strategy"); + userProperties.put("docker.host", "tcp://1.2.3.4:5678"); + assertEquals("Docker client strategy is implicitly set when docker host property is set", EnvironmentAndSystemPropertyClientProviderStrategy.class.getCanonicalName(), newConfig().getDockerClientStrategyClassName()); + } + + @Test + public void shouldNotUseImplicitDockerClientStrategyWhenDockerHostAndStrategyAreBothSet() { + userProperties.put("docker.client.strategy", "foo"); + userProperties.put("docker.host", "tcp://1.2.3.4:5678"); + assertEquals("Docker client strategy is can be explicitly set", "foo", newConfig().getDockerClientStrategyClassName()); + + userProperties.remove("docker.client.strategy"); + + environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "bar"); + userProperties.put("docker.client.strategy", "foo"); + assertEquals("Docker client strategy is can be explicitly set", "bar", newConfig().getDockerClientStrategyClassName()); + + environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "bar"); + userProperties.remove("docker.client.strategy"); + assertEquals("Docker client strategy is can be explicitly set", "bar", newConfig().getDockerClientStrategyClassName()); + + environment.remove("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY"); + userProperties.put("docker.client.strategy", "foo"); + assertEquals("Docker client strategy is can be explicitly set", "foo", newConfig().getDockerClientStrategyClassName()); + } + @Test public void shouldNotReadReuseFromClasspathProperties() { assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); From b837bb15dbbe784155922cc4b13f0cbe8b296ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lef=C3=A8vre?= Date: Mon, 19 Jul 2021 15:07:40 +0200 Subject: [PATCH 1356/4969] Spock Testcontainers annotation is now inherited (#4053) --- .../groovy/org/testcontainers/spock/Testcontainers.groovy | 4 +++- .../groovy/org/testcontainers/spock/TestHierarchyIT.groovy | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy index 7bbd47a4629..675ed68c4a6 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy @@ -3,13 +3,15 @@ package org.testcontainers.spock import org.spockframework.runtime.extension.ExtensionAnnotation import java.lang.annotation.ElementType +import java.lang.annotation.Inherited import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy import java.lang.annotation.Target +@Inherited @Retention(RetentionPolicy.RUNTIME) @Target([ElementType.TYPE, ElementType.METHOD]) @ExtensionAnnotation(TestcontainersExtension) @interface Testcontainers { -} \ No newline at end of file +} diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy index 7fb37446ca5..c28643910a4 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy @@ -4,9 +4,9 @@ import org.testcontainers.containers.PostgreSQLContainer import spock.lang.Shared /** - * This test verifies that integration tests can subclass each other + * This test verifies that integration tests can subclass each other. + * Also verifies that the @Testcontainers annotation is inherited. */ -@Testcontainers class TestHierarchyIT extends MySqlContainerIT { @Shared From 71314ab78f7105a939d257e05ea2b335dfba7dbf Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 19 Jul 2021 20:34:50 +0200 Subject: [PATCH 1357/4969] Fallback to x86 image if image pulling fails (#4290) * Fallback to x86 image if image pulling fails * Add the fallback to `checkAndPullImage` --- .../testcontainers/DockerClientFactory.java | 18 +++++++++++++----- .../DockerClientProviderStrategy.java | 2 +- .../images/RemoteDockerImage.java | 19 +++++++++++++++---- docs/supported_docker_environment/index.md | 12 ++++++------ 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 98e8249e4e5..411b5139de4 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -3,13 +3,13 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerCmd; -import com.github.dockerjava.api.command.ListImagesCmd; +import com.github.dockerjava.api.command.PullImageCmd; +import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AccessMode; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Frame; -import com.github.dockerjava.api.model.Image; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Version; import com.github.dockerjava.api.model.Volume; @@ -37,7 +37,6 @@ import java.io.InputStream; import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; @@ -330,8 +329,17 @@ private boolean checkMountableFile() { public void checkAndPullImage(DockerClient client, String image) { try { client.inspectImageCmd(image).exec(); - } catch (NotFoundException e) { - client.pullImageCmd(image).exec(new TimeLimitedLoggedPullImageResultCallback(log)).awaitCompletion(); + } catch (NotFoundException notFoundException) { + PullImageCmd pullImageCmd = client.pullImageCmd(image); + try { + pullImageCmd.exec(new TimeLimitedLoggedPullImageResultCallback(log)).awaitCompletion(); + } catch (DockerClientException e) { + // Try to fallback to x86 + pullImageCmd + .withPlatform("linux/amd64") + .exec(new TimeLimitedLoggedPullImageResultCallback(log)) + .awaitCompletion(); + } } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 35e3b6eabb8..248e40790aa 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -240,7 +240,7 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) { DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder(); if (configBuilder.build().getApiVersion() == RemoteApiVersion.UNKNOWN_VERSION) { - configBuilder.withApiVersion(RemoteApiVersion.VERSION_1_30); + configBuilder.withApiVersion(RemoteApiVersion.VERSION_1_32); } return DockerClientImpl.getInstance( new AuthDelegatingDockerClientConfig( diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index f4b04712913..4ce38124fe7 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -1,6 +1,7 @@ package org.testcontainers.images; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.google.common.util.concurrent.Futures; @@ -75,11 +76,21 @@ protected final String resolve() { while (Instant.now().isBefore(lastRetryAllowed)) { try { - dockerClient + PullImageCmd pullImageCmd = dockerClient .pullImageCmd(imageName.getUnversionedPart()) - .withTag(imageName.getVersionPart()) - .exec(new TimeLimitedLoggedPullImageResultCallback(logger)) - .awaitCompletion(); + .withTag(imageName.getVersionPart()); + + try { + pullImageCmd + .exec(new TimeLimitedLoggedPullImageResultCallback(logger)) + .awaitCompletion(); + } catch (DockerClientException e) { + // Try to fallback to x86 + pullImageCmd + .withPlatform("linux/amd64") + .exec(new TimeLimitedLoggedPullImageResultCallback(logger)) + .awaitCompletion(); + } LocalImagesCache.INSTANCE.refreshCache(imageName); diff --git a/docs/supported_docker_environment/index.md b/docs/supported_docker_environment/index.md index 04cc0c9ee2b..62a2bbe0af2 100644 --- a/docs/supported_docker_environment/index.md +++ b/docs/supported_docker_environment/index.md @@ -4,15 +4,15 @@ | Host Operating System / Environment | Minimum recommended docker versions | Known issues / tips | |-------------------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Linux - general | Docker v1.10 | | -| Linux - Travis CI | Docker v1.10 | See [example .travis.yml](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/.travis.yml) for baseline Travis CI configuration | -| Linux - CircleCI (LXC driver) | Docker v1.9.1 | The `exec` feature is not compatible with CircleCI. See CircleCI configuration [example](./continuous_integration/circle_ci.md) | -| Linux - within a Docker container | Docker v1.12 | See [Running inside Docker](continuous_integration/dind_patterns.md) for Docker-in-Docker and Docker wormhole patterns | +| Linux - general | Docker v17.09 | | +| Linux - Travis CI | Docker v17.09 | See [example .travis.yml](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/.travis.yml) for baseline Travis CI configuration | +| Linux - CircleCI (LXC driver) | Docker v17.09 | The `exec` feature is not compatible with CircleCI. See CircleCI configuration [example](./continuous_integration/circle_ci.md) | +| Linux - within a Docker container | Docker v17.09 | See [Running inside Docker](continuous_integration/dind_patterns.md) for Docker-in-Docker and Docker wormhole patterns | | Mac OS X - Docker Toolbox | Docker Machine v0.8.0 | | -| Mac OS X - Docker for Mac | 1.12.0 | *Support is best-efforts at present*. `getTestHostIpAddress()` is [not currently supported](https://github.com/testcontainers/testcontainers-java/issues/166) due to limitations in Docker for Mac. | +| Mac OS X - Docker for Mac | v17.09 | *Support is best-efforts at present*. `getTestHostIpAddress()` is [not currently supported](https://github.com/testcontainers/testcontainers-java/issues/166) due to limitations in Docker for Mac. | | Windows - Docker Toolbox | | *Support is limited at present and this is not currently tested on a regular basis*. | | Windows - Docker for Windows | | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md) | -| Windows - Windows Subsystem for Linux (WSL) | Docker v17.06 | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md). | +| Windows - Windows Subsystem for Linux (WSL) | Docker v17.09 | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md). | ## Docker environment discovery From 3c614f2538bce1564ea6fab5cd51e560721b2030 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 20 Jul 2021 08:34:49 +0100 Subject: [PATCH 1358/4969] Upgrade alpine images for better M1 compatibility (#4291) --- .../main/java/org/testcontainers/DockerClientFactory.java | 2 +- core/src/test/java/org/testcontainers/TestImages.java | 4 ++-- .../testcontainers/containers/DockerComposeFilesTest.java | 2 +- .../containers/ParsedDockerComposeFileValidationTest.java | 8 ++++---- .../containers/output/ToStringConsumerTest.java | 8 ++++---- .../org/testcontainers/dockerclient/ImagePullTest.java | 7 ++----- .../java/org/testcontainers/junit/DockerfileTest.java | 6 +++--- .../testcontainers/junit/FixedHostPortContainerTest.java | 2 +- .../junit/ParameterizedDockerfileContainerTest.java | 8 +++----- .../testcontainers/utility/DirectoryTarResourceTest.java | 6 +++--- core/src/test/resources/compose-dockerfile/Dockerfile | 4 ++-- .../resources/compose-scaling-multiple-containers.yml | 2 +- .../test/resources/dockerfile-build-invalid/Dockerfile | 2 +- core/src/test/resources/dockerfile-build-test/Dockerfile | 2 +- .../test/resources/dockerfile-build-test/Dockerfile-alt | 2 +- .../resources/dockerfile-build-test/Dockerfile-buildarg | 2 +- .../resources/dockerfile-build-test/Dockerfile-currentdir | 2 +- .../resources/health-wait-strategy-dockerfile/Dockerfile | 2 +- core/src/test/resources/mappable-dockerfile/Dockerfile | 4 ++-- .../src/test/java/generic/ContainerCreationTest.java | 2 +- .../generic/src/test/java/generic/ContainerLabelTest.java | 4 ++-- .../junit4/generic/src/test/java/generic/ExecTest.java | 2 +- docs/features/configuration.md | 2 +- docs/features/creating_images.md | 2 +- .../org/testcontainers/spock/SpockTestImages.groovy | 2 +- 25 files changed, 42 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 411b5139de4..554860d8985 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -64,7 +64,7 @@ public class DockerClientFactory { TESTCONTAINERS_SESSION_ID_LABEL, SESSION_ID ); - private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.5"); + private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14"); private static DockerClientFactory instance; // Cached client configuration diff --git a/core/src/test/java/org/testcontainers/TestImages.java b/core/src/test/java/org/testcontainers/TestImages.java index 7052f7e8f9d..3798f42af0d 100644 --- a/core/src/test/java/org/testcontainers/TestImages.java +++ b/core/src/test/java/org/testcontainers/TestImages.java @@ -6,7 +6,7 @@ public interface TestImages { DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:3.0.2"); DockerImageName RABBITMQ_IMAGE = DockerImageName.parse("rabbitmq:3.5.3"); DockerImageName MONGODB_IMAGE = DockerImageName.parse("mongo:3.1.5"); - DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.2"); + DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.14"); DockerImageName DOCKER_REGISTRY_IMAGE = DockerImageName.parse("registry:2.7.0"); - DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.5"); + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14"); } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java index 8dbcde2181d..81586c8290b 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java @@ -20,6 +20,6 @@ public void shouldGetDependencyImagesWhenOverriding() { Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-overriding-a.yml"), new File("src/test/resources/docker-compose-imagename-overriding-b.yml"))); Assertions.assertThat(dockerComposeFiles.getDependencyImages()) - .containsExactlyInAnyOrder("alpine:3.2", "redis:b", "mysql:b", "aservice"); + .containsExactlyInAnyOrder("alpine:3.14", "redis:b", "mysql:b", "aservice"); } } diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java index bdceba343d9..ef70d06ada1 100644 --- a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -104,8 +104,8 @@ public void shouldObtainImageFromDockerfileBuild() { .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.2"))) - .as("all defined images are found"); // r/ redis, mysql from compose file, alpine:3.2 from Dockerfile build + entry("custom", Sets.newHashSet("alpine:3.14"))) + .as("all defined images are found"); // r/ redis, mysql from compose file, alpine:3.14 from Dockerfile build } @Test @@ -116,7 +116,7 @@ public void shouldObtainImageFromDockerfileBuildWithContext() { .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.2"))) - .as("all defined images are found"); // redis, mysql from compose file, alpine:3.2 from Dockerfile build + entry("custom", Sets.newHashSet("alpine:3.14"))) + .as("all defined images are found"); // redis, mysql from compose file, alpine:3.14 from Dockerfile build } } diff --git a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java index 1610c688931..8da67e897e9 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java @@ -24,7 +24,7 @@ public class ToStringConsumerTest { @Test public void newlines_are_not_added_to_exec_output() throws Exception { - try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { container.withCommand("sleep", "2m"); container.start(); @@ -37,7 +37,7 @@ public void newlines_are_not_added_to_exec_output() throws Exception { @Test(timeout = 60_000L) public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { - try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { container.withCreateContainerCmdModifier(cmd -> { cmd .withAttachStdin(true) @@ -56,7 +56,7 @@ public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { @Test public void newlines_are_not_added_to_container_output() { - try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { container.withCommand("echo", "-n", LARGE_PAYLOAD); container.setStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); @@ -71,7 +71,7 @@ public void newlines_are_not_added_to_container_output() { @Test public void newlines_are_not_added_to_container_output_with_tty() { - try (GenericContainer container = new GenericContainer<>("alpine:3.13")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { container.withCreateContainerCmdModifier(cmd -> { cmd.withTty(true); }); diff --git a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java index fd936d26c19..8691e8f5f56 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java @@ -16,12 +16,9 @@ public class ImagePullTest { public static String[] parameters() { return new String[] { "alpine:latest", - "alpine:3.6", + "alpine:3.14", "alpine", // omitting the tag should work and default to latest - "alpine@sha256:8fd4b76819e1e5baac82bd0a3d03abfe3906e034cc5ee32100d12aaaf3956dc7", - "gliderlabs/alpine:latest", - "gliderlabs/alpine:3.5", - "gliderlabs/alpine@sha256:a19aa4a17a525c97e5a90a0c53a9f3329d2dc61b0a14df5447757a865671c085", + "alpine@sha256:1775bebec23e1f3ce486989bfc9ff3c4e951690df84aa9f926497d82f2ffca9d", "quay.io/testcontainers/ryuk:latest", "quay.io/testcontainers/ryuk:0.2.3", "quay.io/testcontainers/ryuk@sha256:bb5a635cac4bd96c93cc476969ce11dc56436238ec7cd028d0524462f4739dd9", diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java index 7390b21fce2..2197d7be0e7 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java @@ -40,7 +40,7 @@ protected void configure(BuildImageCmd buildImageCmd) { super.configure(buildImageCmd); List dockerfile = Arrays.asList( - "FROM alpine:3.2", + "FROM alpine:3.14", "RUN echo 'hello from Docker build process'", "CMD yes" ); @@ -59,7 +59,7 @@ public void dockerfileBuilderWorks() { .withFileFromClasspath("test.txt", "mappable-resource/test-resource.txt") .withFileFromString("folder/someFile.txt", "hello") .withDockerfileFromBuilder(builder -> builder - .from("alpine:3.2") + .from("alpine:3.14") .workDir("/app") .add("test.txt", "test file.txt") .run("ls", "-la", "/app/test file.txt") @@ -101,7 +101,7 @@ public int getFileMode() { }) .withDockerfileFromBuilder(builder -> builder - .from("alpine:3.2") + .from("alpine:3.14") .copy("someFile.txt", "/someFile.txt") .cmd("stat -c \"%a\" /someFile.txt") ); diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index 34c039b4fd3..02fad53fb1e 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -24,7 +24,7 @@ */ public class FixedHostPortContainerTest { - private static final String TEST_IMAGE = "alpine:3.2"; + private static final String TEST_IMAGE = "alpine:3.14"; /** * Default http server port (just something different from default) diff --git a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java index 4ea261e68fd..969d2836b2e 100644 --- a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java @@ -35,11 +35,9 @@ public ParameterizedDockerfileContainerTest(String baseImage, String expectedVer @Parameterized.Parameters(name = "{0}") public static Object[][] data() { return new Object[][] { - { "alpine:3.2", "3.2"}, - { "alpine:3.3", "3.3"}, - { "alpine:3.4", "3.4"}, - { "alpine:3.5", "3.5"}, - { "alpine:3.6", "3.6"} + { "alpine:3.12", "3.12"}, + { "alpine:3.13", "3.13"}, + { "alpine:3.14", "3.14"} }; } diff --git a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java index 3789a654c20..f439c55c3ea 100644 --- a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java +++ b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java @@ -26,7 +26,7 @@ public void simpleRecursiveFileTest() { GenericContainer container = new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> - builder.from("alpine:3.3") + builder.from("alpine:3.14") .copy("/tmp/foo", "/foo") .cmd("cat /foo/test/resources/test-recursive-file.txt") .build() @@ -45,7 +45,7 @@ public void simpleRecursiveFileWithPermissionTest() { GenericContainer container = new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> - builder.from("alpine:3.3") + builder.from("alpine:3.14") .copy("/tmp/foo", "/foo") .cmd("ls", "-al", "/") .build() @@ -68,7 +68,7 @@ public void simpleRecursiveClasspathResourceTest() { GenericContainer container = new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> - builder.from("alpine:3.3") + builder.from("alpine:3.14") .copy("/tmp/foo", "/foo") .cmd("ls -lRt /foo") .build() diff --git a/core/src/test/resources/compose-dockerfile/Dockerfile b/core/src/test/resources/compose-dockerfile/Dockerfile index 64613d2cd32..7252932b104 100644 --- a/core/src/test/resources/compose-dockerfile/Dockerfile +++ b/core/src/test/resources/compose-dockerfile/Dockerfile @@ -1,5 +1,5 @@ -FROM alpine:3.2 +FROM alpine:3.14 ADD passthrough.sh /passthrough.sh -CMD /passthrough.sh \ No newline at end of file +CMD /passthrough.sh diff --git a/core/src/test/resources/compose-scaling-multiple-containers.yml b/core/src/test/resources/compose-scaling-multiple-containers.yml index da5ac6f3a07..3ea528d4574 100644 --- a/core/src/test/resources/compose-scaling-multiple-containers.yml +++ b/core/src/test/resources/compose-scaling-multiple-containers.yml @@ -3,5 +3,5 @@ services: redis: image: redis other: - image: alpine:3.5 + image: alpine:3.14 command: sleep 10000 diff --git a/core/src/test/resources/dockerfile-build-invalid/Dockerfile b/core/src/test/resources/dockerfile-build-invalid/Dockerfile index 6140f575ef7..b0198eb3e02 100644 --- a/core/src/test/resources/dockerfile-build-invalid/Dockerfile +++ b/core/src/test/resources/dockerfile-build-invalid/Dockerfile @@ -1 +1 @@ -FROM alpine:3.2 +FROM alpine:3.14 diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile b/core/src/test/resources/dockerfile-build-test/Dockerfile index eee182f21c1..9ae7dba8658 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile @@ -1,2 +1,2 @@ -FROM alpine:3.2 +FROM alpine:3.14 COPY localfile.txt /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-alt b/core/src/test/resources/dockerfile-build-test/Dockerfile-alt index f6938e5fc8d..43e5c556fe9 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile-alt +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-alt @@ -1,2 +1,2 @@ -FROM alpine:3.2 +FROM alpine:3.14 RUN echo "test4567" > /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg b/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg index 4ae26f50f77..b37f4193643 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg @@ -1,3 +1,3 @@ -FROM alpine:3.2 +FROM alpine:3.14 ARG CUSTOM_ARG RUN echo "${CUSTOM_ARG}" > /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir b/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir index 97f80bdfa65..e8456e1bc1f 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir @@ -1,2 +1,2 @@ -FROM alpine:3.2 +FROM alpine:3.14 COPY . / diff --git a/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile b/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile index ddb0f82bce7..c0abb7bb597 100644 --- a/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile +++ b/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.7 +FROM alpine:3.14 HEALTHCHECK --interval=1s CMD test -e /testfile diff --git a/core/src/test/resources/mappable-dockerfile/Dockerfile b/core/src/test/resources/mappable-dockerfile/Dockerfile index b1afd24a3ec..df186f6579c 100644 --- a/core/src/test/resources/mappable-dockerfile/Dockerfile +++ b/core/src/test/resources/mappable-dockerfile/Dockerfile @@ -1,6 +1,6 @@ -FROM alpine:3.2 +FROM alpine:3.14 ADD folder/someFile.txt /someFile.txt RUN cat /someFile.txt ADD test.txt /test.txt RUN cat /test.txt -CMD ping -c 5 www.google.com \ No newline at end of file +CMD ping -c 5 www.google.com diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java index b0e8c98a0e4..83b45f0435d 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java @@ -20,7 +20,7 @@ public class ContainerCreationTest { .withExposedPorts(6379); // } - public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.2"); + public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.14"); // withOptions { // Set up a plain OS container and customize environment, diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java index ca0878e89d4..08d57e31057 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java @@ -8,7 +8,7 @@ public class ContainerLabelTest { // single_label { - public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.6")) + public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.14")) .withLabel("key", "value"); // } @@ -17,7 +17,7 @@ public class ContainerLabelTest { private Map mapOfLabels = new HashMap<>(); // populate map, e.g. mapOfLabels.put("key1", "value1"); - public GenericContainer containerWithMultipleLabels = new GenericContainer(DockerImageName.parse("alpine:3.6")) + public GenericContainer containerWithMultipleLabels = new GenericContainer(DockerImageName.parse("alpine:3.14")) .withLabels(mapOfLabels); // } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java index e35ae18af70..2530cadb410 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java @@ -13,7 +13,7 @@ public class ExecTest { @Rule - public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.6")) + public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.14")) .withCommand("top"); @Test diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 2336ec840c5..ba4487f8722 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -50,7 +50,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **ryuk.container.image = testcontainers/ryuk:0.3.1** > Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) -> **tinyimage.container.image = alpine:3.5** +> **tinyimage.container.image = alpine:3.14** > Used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](#disabling-the-startup-checks)) > **sshd.container.image = testcontainers/sshd:1.0.0** diff --git a/docs/features/creating_images.md b/docs/features/creating_images.md index 0539642e159..6a06627efa0 100644 --- a/docs/features/creating_images.md +++ b/docs/features/creating_images.md @@ -51,7 +51,7 @@ new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> builder - .from("alpine:3.2") + .from("alpine:3.14") .run("apk add --update nginx") .cmd("nginx", "-g", "daemon off;") .build())) diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy index f18bc8dc96d..b9ef64fe475 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy @@ -6,5 +6,5 @@ interface SpockTestImages { DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.34") DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") - DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.5") + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14") } From 034daa6e3d4a99c4ce71332ac49bf66957f903db Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 20 Jul 2021 10:37:37 +0200 Subject: [PATCH 1359/4969] Remove withPublishAllPorts from Ryuk and stabilize containerInfo content on start (#4263) `containerInfo` is queried until all ports expected by Testcontainers are mapped. Introduces Awaitility for retry logic. Removing `withPublishAllPorts` is especially important because else this can lead to publishing of excluded ports on Windows Co-authored-by: Sergei Egorov --- core/build.gradle | 2 + .../containers/GenericContainer.java | 35 +++++++++++++--- .../utility/DynamicPollInterval.java | 42 +++++++++++++++++++ .../utility/ResourceReaper.java | 34 +++++++++++++-- .../containers/GenericContainerTest.java | 27 ++++++++++++ .../containers/ReusabilityUnitTests.java | 7 +++- 6 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java diff --git a/core/build.gradle b/core/build.gradle index 384c1caf1f2..d7ccb9364f8 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -108,6 +108,8 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } + shaded 'org.awaitility:awaitility:4.1.0' + api "com.github.docker-java:docker-java-api:3.2.11" shaded ('com.github.docker-java:docker-java-core:3.2.11') { diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 10f8e1e7195..56ca5345ecd 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -57,6 +57,7 @@ import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.DockerMachineClient; +import org.testcontainers.utility.DynamicPollInterval; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.PathUtils; import org.testcontainers.utility.ResourceReaper; @@ -84,6 +85,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -97,6 +99,7 @@ import java.util.zip.Checksum; import static com.google.common.collect.Lists.newArrayList; +import static org.awaitility.Awaitility.await; import static org.testcontainers.utility.CommandLine.runShellCommand; /** @@ -216,10 +219,10 @@ public class GenericContainer> private static final Set AVAILABLE_IMAGE_NAME_CACHE = new HashSet<>(); private static final RateLimiter DOCKER_CLIENT_RATE_LIMITER = RateLimiterBuilder - .newBuilder() - .withRate(1, TimeUnit.SECONDS) - .withConstantThroughput() - .build(); + .newBuilder() + .withRate(1, TimeUnit.SECONDS) + .withConstantThroughput() + .build(); @Nullable private Map tmpFsMapping; @@ -425,8 +428,30 @@ private void tryStart(Instant startedAt) { // For all registered output consumers, start following as close to container startup as possible this.logConsumers.forEach(this::followOutput); + // Wait until inspect container returns the mapped ports + containerInfo = await() + .atMost(5, TimeUnit.SECONDS) + .pollInterval(DynamicPollInterval.ofMillis(50)) + .pollInSameThread() + .until( + () -> dockerClient.inspectContainerCmd(containerId).exec(), + inspectContainerResponse -> { + Set exposedAndMappedPorts = inspectContainerResponse + .getNetworkSettings() + .getPorts() + .getBindings() + .entrySet() + .stream() + .filter(it -> Objects.nonNull(it.getValue())) // filter out exposed but not yet mapped + .map(Entry::getKey) + .map(ExposedPort::getPort) + .collect(Collectors.toSet()); + + return exposedAndMappedPorts.containsAll(exposedPorts); + } + ); + // Tell subclasses that we're starting - containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); containerIsStarting(containerInfo, reused); // Wait until the container has reached the desired running state diff --git a/core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java b/core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java new file mode 100644 index 00000000000..1252fb2c3a1 --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java @@ -0,0 +1,42 @@ +package org.testcontainers.utility; + +import org.awaitility.pollinterval.PollInterval; + +import java.time.Duration; +import java.time.Instant; + +/** + * Awaitility {@link org.awaitility.pollinterval.PollInterval} that takes execution time into consideration, + * to allow a constant poll-interval, as opposed to Awaitility's default poll-delay behaviour. + * + * @deprecated For internal usage only. + */ +@Deprecated +public class DynamicPollInterval implements PollInterval { + + final Duration interval; + Instant lastTimestamp; + + private DynamicPollInterval(Duration interval) { + this.interval = interval; + lastTimestamp = Instant.now(); + } + + public static DynamicPollInterval of(Duration duration) { + return new DynamicPollInterval(duration); + } + + public static DynamicPollInterval ofMillis(long millis) { + return DynamicPollInterval.of(Duration.ofMillis(millis)); + } + + @Override + public Duration next(int pollCount, Duration previousDuration) { + Instant now = Instant.now(); + Duration executionDuration = Duration.between(lastTimestamp, now); + + Duration result = interval.minusMillis(Math.min(interval.toMillis(), executionDuration.toMillis())); + lastTimestamp = now.plus(result); + return result; + } +} diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 7adbc95bb4c..75c6e209960 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -9,6 +9,8 @@ import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Network; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; import com.github.dockerjava.api.model.Volume; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; @@ -32,11 +34,13 @@ import java.net.Socket; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; @@ -45,6 +49,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.awaitility.Awaitility.await; + /** * Component that responsible for container removal and automatic cleanup of dead containers at JVM shutdown. */ @@ -96,10 +102,14 @@ public static String start(DockerClient client) { List binds = new ArrayList<>(); binds.add(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); + ExposedPort ryukExposedPort = ExposedPort.tcp(8080); String ryukContainerId = client.createContainerCmd(ryukImage) - .withHostConfig(new HostConfig().withAutoRemove(true)) - .withExposedPorts(new ExposedPort(8080)) - .withPublishAllPorts(true) + .withHostConfig( + new HostConfig() + .withAutoRemove(true) + .withPortBindings(new PortBinding(Ports.Binding.empty(), ryukExposedPort)) + ) + .withExposedPorts(ryukExposedPort) .withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID) .withLabels(Collections.singletonMap(DockerClientFactory.TESTCONTAINERS_LABEL, "true")) .withBinds(binds) @@ -125,7 +135,23 @@ public void onNext(Frame frame) { ContainerState containerState = new ContainerState() { - final InspectContainerResponse inspectedContainer = client.inspectContainerCmd(ryukContainerId).exec(); + // inspect container response might initially not contain the mapped port + final InspectContainerResponse inspectedContainer = await() + .atMost(5, TimeUnit.SECONDS) + .pollInterval(DynamicPollInterval.ofMillis(50)) + .pollInSameThread() + .until( + () -> client.inspectContainerCmd(ryukContainerId).exec(), + inspectContainerResponse -> { + return inspectContainerResponse + .getNetworkSettings() + .getPorts() + .getBindings() + .values() + .stream() + .anyMatch(Objects::nonNull); + } + ); @Override public List getExposedPorts() { diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 1e2cb041cf1..93a9cd96479 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -17,6 +17,7 @@ import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.DockerClientFactory; import org.testcontainers.TestImages; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; import org.testcontainers.images.builder.ImageFromDockerfile; @@ -29,9 +30,11 @@ import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.CoreMatchers.equalTo; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.TINY_IMAGE; public class GenericContainerTest { @@ -119,6 +122,30 @@ public void shouldOnlyPublishExposedPorts() { } } + @Test + public void shouldWaitUntilExposedPortIsMapped() { + + ImageFromDockerfile image = new ImageFromDockerfile("publish-multiple") + .withDockerfileFromBuilder(builder -> + builder + .from("testcontainers/helloworld:1.1.0") + .expose(8080, 8081) // one additional port exposed in image + .build() + ); + + try ( + GenericContainer container = new GenericContainer<>(image) + .withExposedPorts(8080) + .withCreateContainerCmdModifier(it -> it.withExposedPorts(ExposedPort.tcp(8082))) // another port exposed by modifier + ) { + + container.start(); + + assertEquals("Only withExposedPort should be exposed", 1, container.getExposedPorts().size()); + assertTrue("withExposedPort should be exposed", container.getExposedPorts().contains(8080)); + } + } + static class NoopStartupCheckStrategy extends StartupCheckStrategy { @Override diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index c212d04c33a..0540fcdba9d 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -10,6 +10,7 @@ import com.github.dockerjava.api.command.ListContainersCmd; import com.github.dockerjava.api.command.StartContainerCmd; import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.NetworkSettings; import com.github.dockerjava.core.command.CreateContainerCmdImpl; import com.github.dockerjava.core.command.InspectContainerCmdImpl; import com.github.dockerjava.core.command.ListContainersCmdImpl; @@ -22,6 +23,8 @@ import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.Parameterized; +import org.mockito.Answers; +import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.rnorth.visibleassertions.VisibleAssertions; @@ -520,7 +523,9 @@ protected Answer startContainerAnswer() { protected Answer inspectContainerAnswer() { return invocation -> { InspectContainerCmd.Exec exec = command -> { - return new InspectContainerResponse(); + InspectContainerResponse stubResponse = Mockito.mock(InspectContainerResponse.class, Answers.RETURNS_DEEP_STUBS); + when(stubResponse.getNetworkSettings().getPorts().getBindings()).thenReturn(Collections.emptyMap()); + return stubResponse; }; return new InspectContainerCmdImpl(exec, invocation.getArgument(0)); }; From 3b3d130c823adf0364815f5bb87df256efbce786 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 20 Jul 2021 13:54:46 +0100 Subject: [PATCH 1360/4969] Split Windows CI into core and non-core steps (#4293) --- azure-pipelines.yml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1471f9948ca..247948901d8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,10 +18,10 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - # Run all tests when running the Windows CI tests + # Run all core tests when running the Windows CI tests - task: Gradle@2 condition: eq(variables['Agent.OS'], 'Windows_NT') - displayName: Build & test (Windows - all modules) + displayName: Build & test (Windows - core) env: AWS_ACCESS_KEY_ID: $(aws.accessKeyId) AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) @@ -29,6 +29,21 @@ jobs: gradleWrapperFile: 'gradlew' jdkVersionOption: '1.11' options: '--no-daemon --continue' - tasks: 'clean check' + tasks: 'clean testcontainers:check' + publishJUnitResults: true + testResultsFiles: '**/TEST-*.xml' + + # Run all non-core tests when running the Windows CI tests + - task: Gradle@2 + condition: eq(variables['Agent.OS'], 'Windows_NT') + displayName: Build & test (Windows - all non-core modules) + env: + AWS_ACCESS_KEY_ID: $(aws.accessKeyId) + AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) + inputs: + gradleWrapperFile: 'gradlew' + jdkVersionOption: '1.11' + options: '--no-daemon --continue' + tasks: 'clean check -x testcontainers:test' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' From 38a443f098c3407a65330bc38ae016cbe4bae8e1 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 29 Jul 2021 16:56:49 +0200 Subject: [PATCH 1361/4969] Update RELEASING.md (#4295) Update the docs to reflect our current release process. --- RELEASING.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index aaba172d20e..34a6b55ae26 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,19 +1,23 @@ # Release process -Testcontainers' release process is automated as a Travis deployment. This describes the basic steps for a project member to perform a release. +Testcontainers' release process is semi-automated through GitHub Actions. This describes the basic steps for a project member to perform a release. ## Steps 1. Ensure that the master branch is building and that tests are passing. -1. Ensure that the [`CHANGELOG`](CHANGELOG.md) file is up to date and includes all merged features. 1. Create a new release on GitHub. **The tag name is used as the version**, so please keep the tag name plain (e.g. 1.2.3). -1. Check that the Travis build passed. -1. Release of published artifacts to Bintray is fully automated. -1. After successful publication to Bintray, the artifacts must be synced to Maven Central. +1. The release triggers a GitHub Action workflow, but it gets mostly build using results from the Gradle remote-cache. Therefore, this should be fairly fast. +1. Login to Sonatype to check the staging repository. +1. Get the staging url after GitHub Action workflow finished. +1. Manually test the release with the staging url as maven repository url (e.g. critical issues and features). +1. Run [TinSalver](https://github.com/bsideup/tinsalver) from GitHub using `npx` to sign artifact (see [TinsSalver README](https://github.com/bsideup/tinsalver/blob/main/README.md)). +1. Close the release in Sonatype. This will evaluate the release based on given Sontaype rules and afterwards automatically sync to Maven Central. +1. Handcraft and polish some of the release notes (e.g. substitute combinded dependency PRs and highlight certain features). 1. When available through Maven Central, poke [Richard North](https://github.com/rnorth) to announce the release on Twitter! ## Internal details -* The process is done with Gradle and Bintray. -* Bintray will automatically promote the release to Maven Central. -* Travis secrets hold Bintray username/passwords that are used for publishing. +* The process is done with GitHub Actions, TinSalver and Sonatype. +* Sonatype will automatically promote the staging release to Maven Central. +* Keybase needs to be installed on the developer machine. +* GPG key of signing developer needs to be uplodaed to the Ubuntu keyserver (or other server supported by Sonatype). From 520cfeb5345f4230a1611b9b1c7708c2b1d8353e Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 30 Jul 2021 23:08:49 +0200 Subject: [PATCH 1362/4969] Disable Chrome's GPU support in `BrowserWebDriverContainer` (#4315) * Trigger selenium build on CI * Try again to trigger build * Apply potential fix by disabling GPU * Also --disable-dev-shm-usage * Alwas add disable-gpu flag * Smaller check for hack * Smaller check for hack --- .../containers/BrowserWebDriverContainer.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 4a25ae486cd..1209b7af019 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -166,6 +166,13 @@ protected void configure() { } } + // Hack for new selenium-chrome image that contains Chrome 92. + // If not disabled, container startup will fail in most cases and consume excessive amounts of CPU. + if (capabilities instanceof ChromeOptions) { + ChromeOptions options = (ChromeOptions) this.capabilities; + options.addArguments("--disable-gpu"); + } + if (recordingMode != VncRecordingMode.SKIP) { if (vncRecordingDirectory == null) { From 4df9b900e79e4a3033ef0975abacf9064a0e7353 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 30 Jul 2021 23:56:49 +0200 Subject: [PATCH 1363/4969] Update Kafka config dynamically (#4316) * Update Kafka config dynamically * Simplify further, fix the Kafka Cluster example --- .../containers/GenericContainer.java | 2 +- .../containers/KafkaContainer.java | 106 ++++++------------ 2 files changed, 37 insertions(+), 71 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 56ca5345ecd..50e4b927617 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -135,7 +135,7 @@ public class GenericContainer> @NonNull private String networkMode; - @NonNull + @Nullable private Network network; @NonNull diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index d9c8e35e852..f62ca23eb57 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -2,12 +2,8 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import lombok.SneakyThrows; -import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; -import java.nio.charset.StandardCharsets; -import java.util.Comparator; - /** * This container wraps Confluent Kafka and Zookeeper (optionally) * @@ -17,20 +13,14 @@ public class KafkaContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("confluentinc/cp-kafka"); private static final String DEFAULT_TAG = "5.4.3"; - private static final String STARTER_SCRIPT = "/testcontainers_start.sh"; - public static final int KAFKA_PORT = 9093; public static final int ZOOKEEPER_PORT = 2181; private static final String DEFAULT_INTERNAL_TOPIC_RF = "1"; - private static final int PORT_NOT_ASSIGNED = -1; - protected String externalZookeeperConnect = null; - private int port = PORT_NOT_ASSIGNED; - /** * @deprecated use {@link KafkaContainer(DockerImageName)} instead */ @@ -80,83 +70,59 @@ public KafkaContainer withExternalZookeeper(String connectString) { } public String getBootstrapServers() { - if (port == PORT_NOT_ASSIGNED) { - throw new IllegalStateException("You should start Kafka container first"); - } - return String.format("PLAINTEXT://%s:%s", getHost(), port); - } - - @Override - protected void doStart() { - withCommand("sh", "-c", "while [ ! -f " + STARTER_SCRIPT + " ]; do sleep 0.1; done; " + STARTER_SCRIPT); - - if (externalZookeeperConnect == null) { - addExposedPort(ZOOKEEPER_PORT); - } - - super.doStart(); + return String.format("PLAINTEXT://%s:%s", getHost(), getMappedPort(KAFKA_PORT)); } @Override - @SneakyThrows - protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { - super.containerIsStarting(containerInfo, reused); - - port = getMappedPort(KAFKA_PORT); - - if (reused) { - return; - } + protected void configure() { + withEnv( + "KAFKA_ADVERTISED_LISTENERS", + String.format( + "BROKER://%s:9092", + getNetwork() != null + ? getNetworkAliases().get(0) + : "localhost" + ) + ); String command = "#!/bin/bash\n"; - final String zookeeperConnect; if (externalZookeeperConnect != null) { - zookeeperConnect = externalZookeeperConnect; + withEnv("KAFKA_ZOOKEEPER_CONNECT", externalZookeeperConnect); } else { - zookeeperConnect = "localhost:" + ZOOKEEPER_PORT; + addExposedPort(ZOOKEEPER_PORT); + withEnv("KAFKA_ZOOKEEPER_CONNECT", "localhost:" + ZOOKEEPER_PORT); command += "echo 'clientPort=" + ZOOKEEPER_PORT + "' > zookeeper.properties\n"; command += "echo 'dataDir=/var/lib/zookeeper/data' >> zookeeper.properties\n"; command += "echo 'dataLogDir=/var/lib/zookeeper/log' >> zookeeper.properties\n"; command += "zookeeper-server-start zookeeper.properties &\n"; } - command += "export KAFKA_ZOOKEEPER_CONNECT='" + zookeeperConnect + "'\n"; - - command += "export KAFKA_ADVERTISED_LISTENERS='" + String.join(",", getBootstrapServers(), brokerAdvertisedListener(containerInfo)) + "'\n"; - - command += ". /etc/confluent/docker/bash-config \n"; - command += "/etc/confluent/docker/configure \n"; - command += "/etc/confluent/docker/launch \n"; + // Optimization: skip the checks + command += "echo '' > /etc/confluent/docker/ensure \n"; + // Run the original command + command += "/etc/confluent/docker/run \n"; + withCommand("sh", "-c", command); + } - copyFileToContainer( - Transferable.of(command.getBytes(StandardCharsets.UTF_8), 0777), - STARTER_SCRIPT + @Override + @SneakyThrows + protected void containerIsStarted(InspectContainerResponse containerInfo) { + String brokerAdvertisedListener = brokerAdvertisedListener(containerInfo); + ExecResult result = execInContainer( + "kafka-configs", + "--alter", + "--bootstrap-server", brokerAdvertisedListener, + "--entity-type", "brokers", + "--entity-name", getEnvMap().get("KAFKA_BROKER_ID"), + "--add-config", + "advertised.listeners=[" + String.join(",", getBootstrapServers(), brokerAdvertisedListener) + "]" ); + if (result.getExitCode() != 0) { + throw new IllegalStateException(result.getStderr()); + } } protected String brokerAdvertisedListener(InspectContainerResponse containerInfo) { - // Kafka supports only one INTER_BROKER listener, so we have to pick one. - // The current algorithm uses the following order of resolving the IP: - // 1. Custom network's IP set via `withNetwork` - // 2. Bridge network's IP - // 3. Best effort fallback to getNetworkSettings#ipAddress - String ipAddress = containerInfo.getNetworkSettings().getNetworks().entrySet() - .stream() - .filter(it -> it.getValue().getIpAddress() != null) - .max(Comparator.comparingInt(entry -> { - if (getNetwork() != null && getNetwork().getId().equals(entry.getValue().getNetworkID())) { - return 2; - } - - if ("bridge".equals(entry.getKey())) { - return 1; - } - - return 0; - })) - .map(it -> it.getValue().getIpAddress()) - .orElseGet(() -> containerInfo.getNetworkSettings().getIpAddress()); - - return String.format("BROKER://%s:%s", ipAddress, "9092"); + return String.format("BROKER://%s:%s", containerInfo.getConfig().getHostName(), "9092"); } } From 6d257e682ad01f87645317c21c851fb8db952ff1 Mon Sep 17 00:00:00 2001 From: Martin Gjaldbaek Date: Sun, 1 Aug 2021 07:44:33 +0200 Subject: [PATCH 1364/4969] Fix potential injection vulnerability (#4314) See https://github.com/hrvey/combine-prs-workflow/releases/tag/1.2.0 --- .github/workflows/combine-prs.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index e1d96a20895..2e8177458a0 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -105,7 +105,7 @@ jobs: BRANCHES_TO_COMBINE: ${{ steps.fetch-branch-names.outputs.result }} COMBINE_BRANCH_NAME: ${{ github.event.inputs.combineBranchName }} run: | - echo "${{steps.fetch-branch-names.outputs.result}}" + echo "$BRANCHES_TO_COMBINE" sourcebranches="${BRANCHES_TO_COMBINE%\"}" sourcebranches="${sourcebranches#\"}" @@ -123,10 +123,12 @@ jobs: # Creates a PR with the new combined branch - uses: actions/github-script@v4.0.2 name: Create Combined Pull Request + env: + PRS_STRING: ${{ steps.fetch-branch-names.outputs.prs-string }} with: github-token: ${{secrets.GITHUB_TOKEN}} script: | - const prString = `${{ steps.fetch-branch-names.outputs.prs-string }}`; + const prString = process.env.PRS_STRING; const body = 'This PR was created by the Combine PRs action by combining the following PRs:\n' + prString; await github.pulls.create({ owner: context.repo.owner, From 289521d84555b7680af3edb15a623a210cf08def Mon Sep 17 00:00:00 2001 From: Richard North Date: Sun, 1 Aug 2021 06:46:26 +0100 Subject: [PATCH 1365/4969] Delete combine-prs.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing because we’re now using an external script based on `gh` Which works pretty well for us. --- .github/workflows/combine-prs.yml | 140 ------------------------------ 1 file changed, 140 deletions(-) delete mode 100644 .github/workflows/combine-prs.yml diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml deleted file mode 100644 index 2e8177458a0..00000000000 --- a/.github/workflows/combine-prs.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: 'Combine PRs' - -# Controls when the action will run - in this case triggered manually -on: - workflow_dispatch: - inputs: - branchPrefix: - description: 'Branch prefix to find combinable PRs based on' - required: true - default: 'dependabot' - mustBeGreen: - description: 'Only combine PRs that are green (status is success)' - required: true - default: 'true' - combineBranchName: - description: 'Name of the branch to combine PRs into' - required: true - default: 'combine-prs-branch' - ignoreLabel: - description: 'Exclude PRs with this label' - required: true - default: 'nocombine' - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "combine-prs" - combine-prs: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - uses: actions/github-script@v4.0.2 - id: fetch-branch-names - name: Fetch branch names - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', { - owner: context.repo.owner, - repo: context.repo.repo - }); - branches = []; - prs = []; - base_branch = null; - for (const pull of pulls) { - const branch = pull['head']['ref']; - console.log('Pull for branch: ' + branch); - if (branch.startsWith('${{ github.event.inputs.branchPrefix }}')) { - console.log('Branch matched: ' + branch); - statusOK = true; - if(${{ github.event.inputs.mustBeGreen }}) { - console.log('Checking green status: ' + branch); - const checkRuns = await github.request('GET /repos/{owner}/{repo}/commits/{ref}/check-runs', { - owner: context.repo.owner, - repo: context.repo.repo, - ref: branch - }); - for await (const cr of checkRuns.data.check_runs) { - console.log('Validating check conclusion: ' + cr.conclusion); - if(cr.conclusion != 'success') { - console.log('Discarding ' + branch + ' with check conclusion ' + cr.conclusion); - statusOK = false; - } - } - } - console.log('Checking labels: ' + branch); - const labels = pull['labels']; - for(const label of labels) { - const labelName = label['name']; - console.log('Checking label: ' + labelName); - if(labelName == '${{ github.event.inputs.ignoreLabel }}') { - console.log('Discarding ' + branch + ' with label ' + labelName); - statusOK = false; - } - } - if (statusOK) { - console.log('Adding branch to array: ' + branch); - branches.push(branch); - prs.push('#' + pull['number'] + ' ' + pull['title']); - base_branch = pull['base']['ref']; - } - } - } - - if (branches.length == 0) { - core.setFailed('No PRs/branches matched criteria'); - return; - } - - core.setOutput('base-branch', base_branch); - core.setOutput('prs-string', prs.join('\n')); - - combined = branches.join(' ') - console.log('Combined: ' + combined); - return combined - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2.3.3 - with: - fetch-depth: 0 - # Creates a branch with other PR branches merged together - - name: Created combined branch - env: - BASE_BRANCH: ${{ steps.fetch-branch-names.outputs.base-branch }} - BRANCHES_TO_COMBINE: ${{ steps.fetch-branch-names.outputs.result }} - COMBINE_BRANCH_NAME: ${{ github.event.inputs.combineBranchName }} - run: | - echo "$BRANCHES_TO_COMBINE" - sourcebranches="${BRANCHES_TO_COMBINE%\"}" - sourcebranches="${sourcebranches#\"}" - - basebranch="${BASE_BRANCH%\"}" - basebranch="${basebranch#\"}" - - git config pull.rebase false - git config user.name github-actions - git config user.email github-actions@github.com - - git branch $COMBINE_BRANCH_NAME $basebranch - git checkout $COMBINE_BRANCH_NAME - git pull origin $sourcebranches --no-edit - git push origin $COMBINE_BRANCH_NAME - # Creates a PR with the new combined branch - - uses: actions/github-script@v4.0.2 - name: Create Combined Pull Request - env: - PRS_STRING: ${{ steps.fetch-branch-names.outputs.prs-string }} - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - const prString = process.env.PRS_STRING; - const body = 'This PR was created by the Combine PRs action by combining the following PRs:\n' + prString; - await github.pulls.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: 'Combined PR', - head: '${{ github.event.inputs.combineBranchName }}', - base: '${{ steps.fetch-branch-names.outputs.base-branch }}', - body: body - }); From 676845417c88ac136fd5df323e788f16beec817f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:35 +0000 Subject: [PATCH 1366/4969] Bump mysql-connector-java from 8.0.25 to 8.0.26 in /modules/jdbc-test Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.25 to 8.0.26. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.25...8.0.26) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 99cba7dcb70..17c44383f74 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -16,5 +16,5 @@ dependencies { api 'org.apache.tomcat:tomcat-jdbc:10.0.7' api 'org.vibur:vibur-dbcp:25.0' - api 'mysql:mysql-connector-java:8.0.25' + api 'mysql:mysql-connector-java:8.0.26' } From d5d91b5d80efa0d95ee5e0b52fd028951e539615 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:36 +0000 Subject: [PATCH 1367/4969] Bump java-client from 3.1.6 to 3.2.0 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.1.6 to 3.2.0. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.1.6...java-client-3.2.0) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 40f59128ec8..823b88a983e 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') - testImplementation 'com.couchbase.client:java-client:3.1.6' + testImplementation 'com.couchbase.client:java-client:3.2.0' testImplementation 'org.awaitility:awaitility:4.1.0' } From 42a4fddccf1de98a7b7d1b4b98f4e9a0f5a40100 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:37 +0000 Subject: [PATCH 1368/4969] Bump slf4j-api from 1.7.30 to 1.7.32 in /core Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.30 to 1.7.32. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.30...v_1.7.32) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d7ccb9364f8..29c521a97e8 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -100,7 +100,7 @@ dependencies { } api 'junit:junit:4.12' - api 'org.slf4j:slf4j-api:1.7.30' + api 'org.slf4j:slf4j-api:1.7.32' compileOnly 'org.jetbrains:annotations:21.0.1' testCompileClasspath 'org.jetbrains:annotations:21.0.1' api 'org.apache.commons:commons-compress:1.20' From 41e7cede1a4bee67c1d72504168c2579b5e46d84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:37 +0000 Subject: [PATCH 1369/4969] Bump postgresql from 42.2.22 to 42.2.23 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.22 to 42.2.23. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.23/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.22...REL42.2.23) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 9b7063e3a0c..410706429d5 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.2.22' + testImplementation 'org.postgresql:postgresql:42.2.23' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' From a622e0d06c3dbcf3086ecc4f21963f07362f6f2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:37 +0000 Subject: [PATCH 1370/4969] Bump mysql-connector-java in /modules/junit-jupiter Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.25 to 8.0.26. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.25...8.0.26) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 9554f2c9e5b..2722f659bdd 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' testRuntimeOnly 'org.postgresql:postgresql:42.2.22' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } From f120d5e64b1173bb2b30db9566e70fead0443286 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:37 +0000 Subject: [PATCH 1371/4969] Bump r2dbc-mariadb from 1.0.1 to 1.0.2 in /modules/mariadb Bumps [r2dbc-mariadb](https://github.com/mariadb-corporation/mariadb-connector-r2dbc) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/compare/1.0.1...1.0.2) --- updated-dependencies: - dependency-name: org.mariadb:r2dbc-mariadb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index ca267a1fe7c..e9080ce6131 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,11 +7,11 @@ dependencies { api project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'org.mariadb:r2dbc-mariadb:1.0.1' + compileOnly 'org.mariadb:r2dbc-mariadb:1.0.2' testImplementation project(':jdbc-test') testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3' testImplementation testFixtures(project(':r2dbc')) - testImplementation 'org.mariadb:r2dbc-mariadb:1.0.0' + testImplementation 'org.mariadb:r2dbc-mariadb:1.0.2' } From 25880f94fd70c0443d83f493ef3c71ee2f9caa9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:41 +0000 Subject: [PATCH 1372/4969] Bump aws-java-sdk-dynamodb from 1.12.16 to 1.12.37 in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.16 to 1.12.37. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.16...1.12.37) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index c92b1969147..85c91332c12 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.16' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.11.1030' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.37' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.37' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 2ef95ba8d7c1f171d9d4eefbdc639c91ceaddc65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:42 +0000 Subject: [PATCH 1373/4969] Bump jedis from 3.6.1 to 3.6.3 in /modules/junit-jupiter Bumps [jedis](https://github.com/redis/jedis) from 3.6.1 to 3.6.3. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.6.1...v3.6.3) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 9554f2c9e5b..e48d28a5e5e 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:3.6.1' + testImplementation 'redis.clients:jedis:3.6.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testImplementation ('org.mockito:mockito-core:3.11.2') { exclude(module: 'hamcrest-core') From 1f84c2af02453e841297b306d61e3e234c9f102a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:43 +0000 Subject: [PATCH 1374/4969] Bump mysql-connector-java from 8.0.25 to 8.0.26 in /modules/mysql Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.25 to 8.0.26. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.25...8.0.26) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index a14fa678280..db2deac2d10 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.25' + testImplementation 'mysql:mysql-connector-java:8.0.26' testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' From 695c77f73e56406d55aeb18800fcf73f0901c858 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:43 +0000 Subject: [PATCH 1375/4969] Bump mongo-java-driver from 3.12.7 to 3.12.9 in /core Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.7 to 3.12.9. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.7...r3.12.9) --- updated-dependencies: - dependency-name: org.mongodb:mongo-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d7ccb9364f8..2677486fa58 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -140,7 +140,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:3.6.1' testImplementation 'com.rabbitmq:amqp-client:5.12.0' - testImplementation 'org.mongodb:mongo-java-driver:3.12.7' + testImplementation 'org.mongodb:mongo-java-driver:3.12.9' testImplementation ('org.mockito:mockito-core:3.11.2') { exclude(module: 'hamcrest-core') From ab2ede992f69dab8379177832a4fe95b330db930 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:44 +0000 Subject: [PATCH 1376/4969] Bump HikariCP from 4.0.3 to 5.0.0 in /modules/spock Bumps [HikariCP](https://github.com/brettwooldridge/HikariCP) from 4.0.3 to 5.0.0. - [Release notes](https://github.com/brettwooldridge/HikariCP/releases) - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-4.0.3...HikariCP-5.0.0) --- updated-dependencies: - dependency-name: com.zaxxer:HikariCP dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 6ee936b7ca7..56f35ffe695 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -12,7 +12,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') - testImplementation 'com.zaxxer:HikariCP:4.0.3' + testImplementation 'com.zaxxer:HikariCP:5.0.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.2.22' From d8737a9154b35ed3981803ac81a3f3ded6e16631 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:48 +0000 Subject: [PATCH 1377/4969] Bump transport from 7.13.2 to 7.13.4 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.13.2 to 7.13.4. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.13.2...v7.13.4) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 67e03df2945..180f373bddd 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.13.0" - testImplementation "org.elasticsearch.client:transport:7.13.2" + testImplementation "org.elasticsearch.client:transport:7.13.4" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 2e53d6deba8df7aba18502bc86b56f0ba510200f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:48 +0000 Subject: [PATCH 1378/4969] Bump aws-java-sdk-s3 from 1.12.16 to 1.12.37 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.16 to 1.12.37. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.16...1.12.37) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 031a601bdc9..5158325fa92 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.16' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.37' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.19' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.16' testImplementation 'software.amazon.awssdk:s3:2.16.97' From f8ff174917c480019cf2bd361eab01d33397d974 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:52 +0000 Subject: [PATCH 1379/4969] Bump slf4j-api from 1.7.30 to 1.7.32 in /examples Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.30 to 1.7.32. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.30...v_1.7.32) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index c5706da277a..6ca8b1ae664 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { jcenter() } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.30' + compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.2.22' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 58f31827717..56dab9c4951 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.30' + compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:3.6.1' implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 4fb93cb71b5..771f55551ea 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.30' + compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:3.6.1' implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index e803f616998..a806f483938 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:3.6.1' implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:1.7.30' + compileOnly 'org.slf4j:slf4j-api:1.7.32' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:testcontainers' From 3063021a6bc1d6739611339c0cfb0234ce78554d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:54 +0000 Subject: [PATCH 1380/4969] Bump postgresql from 42.2.22 to 42.2.23 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.22 to 42.2.23. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.23/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.22...REL42.2.23) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 6ee936b7ca7..7720067b620 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.2.22' + testRuntimeOnly 'org.postgresql:postgresql:42.2.23' testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' testCompileClasspath 'org.jetbrains:annotations:21.0.1' From e2cb908c5f67180d4ee7ba5bd39ab44fcc5a3cc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:55 +0000 Subject: [PATCH 1381/4969] Bump testcontainers from 1.15.3 to 1.16.0 in /core Bumps [testcontainers](https://github.com/testcontainers/testcontainers-java) from 1.15.3 to 1.16.0. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.15.3...1.16.0) --- updated-dependencies: - dependency-name: org.testcontainers:testcontainers dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d7ccb9364f8..3ea1a33a7e3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -95,7 +95,7 @@ configurations.all { } dependencies { - baseline 'org.testcontainers:testcontainers:1.15.3', { + baseline 'org.testcontainers:testcontainers:1.16.0', { exclude group: "*", module: "*" } From a6f300c4bb1ec0af91f722a14701c68a11c504a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:57 +0000 Subject: [PATCH 1382/4969] Bump aws-java-sdk-logs from 1.12.16 to 1.12.37 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.16 to 1.12.37. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.16...1.12.37) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 031a601bdc9..21652d15fa6 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.16' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.11.1030' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.19' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.16' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.37' testImplementation 'software.amazon.awssdk:s3:2.16.97' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From d489acff1bd25b95aadc0c8ef4188d1c971ef2d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:00:59 +0000 Subject: [PATCH 1383/4969] Bump slf4j-simple from 1.7.30 to 1.7.32 in /examples Bumps [slf4j-simple](https://github.com/qos-ch/slf4j) from 1.7.30 to 1.7.32. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.30...v_1.7.32) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-simple dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 79c14941c11..2a4650930a4 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:2.8.0' testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'org.slf4j:slf4j-simple:1.7.30' + testImplementation 'org.slf4j:slf4j-simple:1.7.32' } From f5f0dc65f5b872c60cccfc20911a39b89e39b03a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:01:01 +0000 Subject: [PATCH 1384/4969] Bump jedis from 3.6.1 to 3.6.3 in /core Bumps [jedis](https://github.com/redis/jedis) from 3.6.1 to 3.6.3. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.6.1...v3.6.3) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d7ccb9364f8..8b4abdb11c4 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -138,7 +138,7 @@ dependencies { } testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' - testImplementation 'redis.clients:jedis:3.6.1' + testImplementation 'redis.clients:jedis:3.6.3' testImplementation 'com.rabbitmq:amqp-client:5.12.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.7' From 381fa285b6f296c76fb2d7a533a5666bec8db91d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:01:07 +0000 Subject: [PATCH 1385/4969] Bump postgresql from 42.2.22 to 42.2.23 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.22 to 42.2.23. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.23/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.22...REL42.2.23) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index c5706da277a..2bb27ae83cf 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.30' implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'org.json:json:20210307' - testImplementation 'org.postgresql:postgresql:42.2.22' + testImplementation 'org.postgresql:postgresql:42.2.23' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.testcontainers:postgresql' } From b3f10668ec911d55dd16a2b420f13301affc8a60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:01:09 +0000 Subject: [PATCH 1386/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.5.20 to 1.5.21. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 7e832956303..db7e4ebe957 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.5.2" id("org.jetbrains.kotlin.jvm") version "1.5.10" - id("org.jetbrains.kotlin.plugin.spring") version "1.5.20" + id("org.jetbrains.kotlin.plugin.spring") version "1.5.21" } apply plugin: 'io.spring.dependency-management' From ed781dd45ecebb21b11de85d3ff9a79be66fe912 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 08:48:23 +0000 Subject: [PATCH 1387/4969] Bump aws-java-sdk-sqs from 1.12.19 to 1.12.37 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.19 to 1.12.37. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.19...1.12.37) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 20c2f18a968..3d250f86087 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.19' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.37' testImplementation 'software.amazon.awssdk:s3:2.16.97' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 62c9be485de33406a121f541663ee192f79f1d22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 08:48:23 +0000 Subject: [PATCH 1388/4969] Bump tomcat-jdbc from 10.0.7 to 10.0.8 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.7 to 10.0.8. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 17c44383f74..32b7429f1b6 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.7' + api 'org.apache.tomcat:tomcat-jdbc:10.0.8' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.26' } From 226b5a0dcd81d95f6a998b78c101b5dd8b777e6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 08:48:24 +0000 Subject: [PATCH 1389/4969] Bump s3 from 2.16.97 to 2.17.9 in /modules/localstack Bumps s3 from 2.16.97 to 2.17.9. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 20c2f18a968..540ba35008d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.19' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.37' - testImplementation 'software.amazon.awssdk:s3:2.16.97' + testImplementation 'software.amazon.awssdk:s3:2.17.9' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 8272e80ed53951c169b67cec272f83a799e556e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 08:48:34 +0000 Subject: [PATCH 1390/4969] Bump commons-compress from 1.20 to 1.21 in /core Bumps commons-compress from 1.20 to 1.21. --- updated-dependencies: - dependency-name: org.apache.commons:commons-compress dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index ca1fde00aae..7d62a9fb153 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -103,7 +103,7 @@ dependencies { api 'org.slf4j:slf4j-api:1.7.32' compileOnly 'org.jetbrains:annotations:21.0.1' testCompileClasspath 'org.jetbrains:annotations:21.0.1' - api 'org.apache.commons:commons-compress:1.20' + api 'org.apache.commons:commons-compress:1.21' api ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') } From 97d0959b50dbad55ff1152f978da1b061d4bf660 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 08:48:35 +0000 Subject: [PATCH 1391/4969] Bump logback-classic from 1.2.3 to 1.2.5 in /examples Bumps logback-classic from 1.2.3 to 1.2.5. --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 04d8f249511..1c01bc73a2e 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.2.5' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 8169ea8cf12..ff1b2995e02 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.2.23' - testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.2.5' testImplementation 'org.testcontainers:postgresql' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 56dab9c4951..aae31424f66 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.7' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.2.5' testImplementation 'org.testng:testng:7.4.0' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 771f55551ea..5da9e48a8e0 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -13,6 +13,6 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.2.5' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index a806f483938..4635eceff7e 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' - testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.2.5' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From e58faa5c80bd0a242888d4911ea4ed73b22885da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 08:48:35 +0000 Subject: [PATCH 1392/4969] Bump postgresql from 42.2.22 to 42.2.23 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.22 to 42.2.23. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.2.23/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.22...REL42.2.23) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index a3e271b0d59..abd1ae9feeb 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' - testRuntimeOnly 'org.postgresql:postgresql:42.2.22' + testRuntimeOnly 'org.postgresql:postgresql:42.2.23' testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } From b5331f48342521b7c0b1f27135b275835a04c44d Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 2 Aug 2021 12:27:52 +0200 Subject: [PATCH 1393/4969] Fix failing `PublicBinaryAPITest` for `DynamicPollInterval` (#4353) Also change `jarFileTest` to take the shadowJar into consideration as input for the cache key. --- core/build.gradle | 1 + .../jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java | 1 + 2 files changed, 2 insertions(+) diff --git a/core/build.gradle b/core/build.gradle index ca1fde00aae..824c1bb0c4e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -50,6 +50,7 @@ task jarFileTest(type: Test) { testClassesDirs = sourceSets.jarFileTest.output.classesDirs classpath = sourceSets.jarFileTest.runtimeClasspath + file(shadowJar.outputs.files.singleFile) // input for correct caching systemProperty("jarFile", shadowJar.outputs.files.singleFile) dependsOn(shadowJar) diff --git a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java index 6a5a766d24e..208c8702654 100644 --- a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java +++ b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java @@ -93,6 +93,7 @@ public void setUp() { case "org/testcontainers/dockerclient/UnixSocketClientProviderStrategy": case "org/testcontainers/dockerclient/DockerClientProviderStrategy": case "org/testcontainers/dockerclient/WindowsClientProviderStrategy": + case "org/testcontainers/utility/DynamicPollInterval": Assume.assumeTrue(false); } } From 12b41272fdf9983dc6e9aed9b3ffd9b617c1f499 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 3 Aug 2021 11:52:38 +0100 Subject: [PATCH 1394/4969] Upgrade ryuk image to 0.3.2 (#4359) --- .../main/java/org/testcontainers/utility/ResourceReaper.java | 2 +- .../utility/TestcontainersConfigurationTest.java | 4 ++-- docs/features/configuration.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 75c6e209960..ca657675da4 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -95,7 +95,7 @@ public static String start(String hostIpAddress, DockerClient client) { @SneakyThrows(InterruptedException.class) public static String start(DockerClient client) { String ryukImage = ImageNameSubstitutor.instance() - .apply(DockerImageName.parse("testcontainers/ryuk:0.3.1")) + .apply(DockerImageName.parse("testcontainers/ryuk:0.3.2")) .asCanonicalNameString(); DockerClientFactory.instance().checkAndPullImage(client, ryukImage); diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index ff56f62e4e4..cbb36baf580 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -210,8 +210,8 @@ public void shouldReadReuseFromEnvironment() { @Test public void shouldTrimImageNames() { - userProperties.setProperty("ryuk.container.image", " testcontainers/ryuk:0.3.1 "); - assertEquals("trailing whitespace was not removed from image name property", "testcontainers/ryuk:0.3.1",newConfig().getRyukImage()); + userProperties.setProperty("ryuk.container.image", " testcontainers/ryuk:0.3.2 "); + assertEquals("trailing whitespace was not removed from image name property", "testcontainers/ryuk:0.3.2",newConfig().getRyukImage()); } private TestcontainersConfiguration newConfig() { diff --git a/docs/features/configuration.md b/docs/features/configuration.md index ba4487f8722..821d0cc7629 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -47,7 +47,7 @@ It takes a couple of seconds, but if you want to speed up your tests, you can di Testcontainers uses public Docker images to perform different actions like startup checks, VNC recording and others. Some companies disallow the usage of Docker Hub, but you can override `*.image` properties with your own images from your private registry to workaround that. -> **ryuk.container.image = testcontainers/ryuk:0.3.1** +> **ryuk.container.image = testcontainers/ryuk:0.3.2** > Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) > **tinyimage.container.image = alpine:3.14** @@ -74,7 +74,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` ## Customizing Ryuk resource reaper -> **ryuk.container.image = testcontainers/ryuk:0.3.1** +> **ryuk.container.image = testcontainers/ryuk:0.3.2** > The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown > **ryuk.container.privileged = false** From 611ebf5313a8148f4d7233227f2c0f1abaa5290a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:52:55 +0000 Subject: [PATCH 1395/4969] Bump mysql-connector-java from 8.0.25 to 8.0.26 in /modules/spock Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.25 to 8.0.26. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.25...8.0.26) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 1e8e8f88503..a883d6027d0 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.2.23' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' testCompileClasspath 'org.jetbrains:annotations:21.0.1' } From c6f0eaa12d0b99d3ed5005b3220fedfbdcee3a28 Mon Sep 17 00:00:00 2001 From: pioorg Date: Tue, 3 Aug 2021 13:00:27 +0200 Subject: [PATCH 1396/4969] Remove accidental overwrite of user properties (#4311) `userProperties` shall be saved only after successful update of config file. Co-authored-by: Sergei Egorov --- .../org/testcontainers/utility/TestcontainersConfiguration.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index fddeec9c9b7..fd189a0ad59 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -306,8 +306,6 @@ public boolean updateUserConfig(@NonNull String prop, @NonNull String value) { return false; } - userProperties.setProperty(prop, value); - USER_CONFIG_FILE.createNewFile(); try (OutputStream outputStream = new FileOutputStream(USER_CONFIG_FILE)) { userProperties.store(outputStream, "Modified by Testcontainers"); From 1699e4708b15fcbf26b80f65fbbee48fa0b0c4d0 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 6 Aug 2021 14:49:53 +0200 Subject: [PATCH 1397/4969] Add japicmp to every module (#4364) --- build.gradle | 18 ++++++++++++++++++ core/build.gradle | 36 +----------------------------------- gradle/japicmp.gradle | 29 +++++++++++++++++++++++++++++ modules/kafka/build.gradle | 9 +++++++++ 4 files changed, 57 insertions(+), 35 deletions(-) create mode 100644 gradle/japicmp.gradle diff --git a/build.gradle b/build.gradle index 98b9b5a30bc..723c429271d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,18 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + // https://github.com/melix/japicmp-gradle-plugin/issues/36 + classpath 'com.google.guava:guava:30.1.1-jre' + } +} + plugins { id 'io.franzbecker.gradle-lombok' version '4.0.0' id 'com.github.johnrengelman.shadow' version '7.0.0' + id 'me.champeau.gradle.japicmp' version '0.2.9' apply false } apply from: "$rootDir/gradle/ci-support.gradle" @@ -46,6 +58,12 @@ subprojects { // specific modules should be excluded from publication if ( ! ["test-support", "jdbc-test"].contains(it.name) && !it.path.startsWith(":docs:") && it != project(":docs") ) { apply from: "$rootDir/gradle/publishing.gradle" + + if (it.name != "bom") { + apply plugin: "me.champeau.gradle.japicmp" + tasks.register('japicmp', me.champeau.gradle.japicmp.JapicmpTask) + apply from: "$rootDir/gradle/japicmp.gradle" + } } test { diff --git a/core/build.gradle b/core/build.gradle index 824c1bb0c4e..00d9cfda688 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,18 +1,3 @@ -buildscript { - repositories { - jcenter() - } - - dependencies { - // https://github.com/melix/japicmp-gradle-plugin/issues/36 - classpath 'com.google.guava:guava:30.1.1-jre' - } -} - -plugins { - id 'me.champeau.gradle.japicmp' version '0.2.9' -} - apply plugin: 'com.github.johnrengelman.shadow' description = "Testcontainers Core" @@ -24,7 +9,6 @@ sourceSets { idea.module.testSourceDirs += sourceSets.jarFileTest.allSource.srcDirs configurations { - baseline shaded [api, compileOnly, testCompile]*.extendsFrom shaded } @@ -57,17 +41,7 @@ task jarFileTest(type: Test) { } project.tasks.check.dependsOn(jarFileTest) -task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { - dependsOn(tasks.shadowJar) - - oldClasspath = configurations.baseline - newClasspath = shadowJar.outputs.files - ignoreMissingClasses = true - - accessModifier = "protected" - failOnModification = true - failOnSourceIncompatibility = true - +tasks.japicmp { packageExcludes = [ "com.github.dockerjava.*", "org.testcontainers.shaded.*", @@ -78,14 +52,6 @@ task japicmp(type: me.champeau.gradle.japicmp.JapicmpTask) { methodExcludes = [] fieldExcludes = [] - - onlyBinaryIncompatibleModified = true - htmlOutputFile = file("$buildDir/reports/japi.html") -} -// do not run on Windows by default -// TODO investigate zip issue on Windows -if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { - project.tasks.check.dependsOn(japicmp) } configurations.all { diff --git a/gradle/japicmp.gradle b/gradle/japicmp.gradle new file mode 100644 index 00000000000..58fbec9c0b7 --- /dev/null +++ b/gradle/japicmp.gradle @@ -0,0 +1,29 @@ +configurations { + baseline +} + +dependencies { + baseline "org.testcontainers:${project.name}:1.16.0", { + exclude group: "*", module: "*" + } +} + +tasks.japicmp { + dependsOn(tasks.shadowJar) + + oldClasspath = configurations.baseline + newClasspath = shadowJar.outputs.files + ignoreMissingClasses = true + + accessModifier = "protected" + failOnModification = true + failOnSourceIncompatibility = true + + onlyBinaryIncompatibleModified = true + htmlOutputFile = file("$buildDir/reports/japi.html") +} +// do not run on Windows by default +// TODO investigate zip issue on Windows +if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) { + project.tasks.check.dependsOn(japicmp) +} diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index c83859e0c20..f7e9acda9a0 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -1,5 +1,14 @@ description = "Testcontainers :: Kafka" +tasks.japicmp { + // TODO clean after 1.17.0 is released + methodExcludes = [ + // Overrides removed, not a breaking change per se + "org.testcontainers.containers.KafkaContainer#containerIsStarting(com.github.dockerjava.api.command.InspectContainerResponse,boolean)", + "org.testcontainers.containers.KafkaContainer#doStart()", + ] +} + dependencies { api project(':testcontainers') From ef921c3c60d1c74d0eab9f9fed85fcd1ee8bf228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 12 Aug 2021 13:26:10 +0200 Subject: [PATCH 1398/4969] docs: add Elastic as user (#4369) * docs: adds Elastic as a user * docs: wording --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 16f61899947..8894e6bec73 100644 --- a/docs/index.md +++ b/docs/index.md @@ -173,6 +173,8 @@ A huge thank you to our sponsors: * [CloudBees](https://www.cloudbees.com/) - Integration testing of products, including but not limited to database and AWS/Localstack integration testing. * [Jenkins](https://www.jenkins.io/) - Integration testing of multiple plugins and the Trilead SSH2 fork maintained by the Jenkins community ([query](https://github.com/search?l=Maven+POM&q=org%3Ajenkinsci+testcontainers&type=Code)). +* [Elastic](https://www.elastic.co) - Integration testing of the Java APM agent + ## License From 8638330ba6b3d53ce8e72ac898b8aef7d5f3fc57 Mon Sep 17 00:00:00 2001 From: Sankeerth Date: Tue, 17 Aug 2021 03:24:03 -0400 Subject: [PATCH 1399/4969] Adding Alkira to list of TC users (#4370) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 8894e6bec73..af5bb4edcdb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -174,6 +174,7 @@ A huge thank you to our sponsors: * [Jenkins](https://www.jenkins.io/) - Integration testing of multiple plugins and the Trilead SSH2 fork maintained by the Jenkins community ([query](https://github.com/search?l=Maven+POM&q=org%3Ajenkinsci+testcontainers&type=Code)). * [Elastic](https://www.elastic.co) - Integration testing of the Java APM agent +* [Alkira](https://www.alkira.com/) - Testing of multiple micro-services using Kafka, PostgreSQL, Apache Zookeeper, Etcd and so on. From 5b660560edbacd6cbbb768e112ce0ca619693a33 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 18 Aug 2021 17:18:28 +0200 Subject: [PATCH 1400/4969] Update mkdocs.yml to 1.16.0 --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index f3cb11f7fe6..9929f5292c2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -96,4 +96,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.15.3 + latest_version: 1.16.0 From 99b91b89b6ee3f8f0e9545e86d9f0744b301db30 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 19 Aug 2021 17:03:28 +0200 Subject: [PATCH 1401/4969] Update `OracleContainer` and re-activate on CI (#4298) Will now use "gvenzl/oracle-xe:18.4.0-slim" by default. Co-authored-by: Piotr Co-authored-by: Sergei Egorov --- .../utility/TestcontainersConfiguration.java | 5 +- .../containers/OracleContainer.java | 48 +++++++++++-------- .../containers/OracleContainerProvider.java | 9 ++-- .../junit/oracle/SimpleOracleTest.java | 13 +++-- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index fd189a0ad59..cbbe92dd76d 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -24,7 +24,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; @@ -61,6 +60,7 @@ public class TestcontainersConfiguration { private static final String PULSAR_IMAGE = "apachepulsar/pulsar"; private static final String LOCALSTACK_IMAGE = "localstack/localstack"; private static final String SSHD_IMAGE = "testcontainers/sshd"; + private static final String ORACLE_IMAGE = "gvenzl/oracle-xe"; private static final ImmutableMap CONTAINER_MAPPING = ImmutableMap.builder() .put(DockerImageName.parse(AMBASSADOR_IMAGE), "ambassador.container.image") @@ -73,6 +73,7 @@ public class TestcontainersConfiguration { .put(DockerImageName.parse(PULSAR_IMAGE), "pulsar.container.image") .put(DockerImageName.parse(LOCALSTACK_IMAGE), "localstack.container.image") .put(DockerImageName.parse(SSHD_IMAGE), "sshd.container.image") + .put(DockerImageName.parse(ORACLE_IMAGE), "oracle.container.image") .build(); @Getter(lazy = true) @@ -146,7 +147,7 @@ public String getKafkaImage() { @Deprecated public String getOracleImage() { - return getEnvVarOrProperty("oracle.container.image", null); + return getImage(ORACLE_IMAGE).asCanonicalNameString(); } @Deprecated diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index 2573ef722e3..ccd705f5af9 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -1,45 +1,39 @@ package org.testcontainers.containers; import com.google.common.collect.Sets; +import org.apache.commons.lang.StringUtils; import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.TestcontainersConfiguration; +import java.util.Arrays; +import java.util.List; import java.util.Set; import java.util.concurrent.Future; -/** - * @author gusohal - */ public class OracleContainer extends JdbcDatabaseContainer { public static final String NAME = "oracle"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe"); + + + static final String DEFAULT_TAG = "18.4.0-slim"; + static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); private static final int ORACLE_PORT = 1521; private static final int APEX_HTTP_PORT = 8080; private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240; private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 120; + private static final List ORACLE_SYSTEM_USERS = Arrays.asList("system", "sys"); - private String username = "system"; - private String password = "oracle"; - - private static String resolveImageName() { - String image = TestcontainersConfiguration.getInstance().getOracleImage(); - - if (image == null) { - throw new IllegalStateException("An image to use for Oracle containers must be configured. " + - "To do this, please place a file on the classpath named `testcontainers.properties`, " + - "containing `oracle.container.image=IMAGE`, where IMAGE is a suitable image name and tag."); - } - return image; - } + private String username = "test"; + private String password = "test"; /** * @deprecated use {@link OracleContainer(DockerImageName)} instead */ @Deprecated public OracleContainer() { - this(resolveImageName()); + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } public OracleContainer(String dockerImageName) { @@ -74,7 +68,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:oracle:thin:" + getUsername() + "/" + getPassword() + "@" + getHost() + ":" + getOraclePort() + ":" + getSid(); + return "jdbc:oracle:thin:" + getUsername() + "/" + getPassword() + "@" + getHost() + ":" + getOraclePort() + "/xepdb1"; } @Override @@ -89,12 +83,21 @@ public String getPassword() { @Override public OracleContainer withUsername(String username) { + if (StringUtils.isEmpty(username)) { + throw new IllegalArgumentException("Username cannot be null or empty"); + } + if (ORACLE_SYSTEM_USERS.contains(username.toLowerCase())) { + throw new IllegalArgumentException("Username cannot be one of " + ORACLE_SYSTEM_USERS); + } this.username = username; return self(); } @Override public OracleContainer withPassword(String password) { + if (StringUtils.isEmpty(password)) { + throw new IllegalArgumentException("Password cannot be null or empty"); + } this.password = password; return self(); } @@ -122,4 +125,11 @@ public Integer getWebPort() { public String getTestQueryString() { return "SELECT 1 FROM DUAL"; } + + @Override + protected void configure() { + withEnv("ORACLE_PASSWORD", password); + withEnv("APP_USER", username); + withEnv("APP_USER_PASSWORD", password); + } } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java index 853ffdaf17a..a298ae23359 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java @@ -1,5 +1,7 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; + /** * Factory for Oracle containers. */ @@ -11,15 +13,14 @@ public boolean supports(String databaseType) { @Override public JdbcDatabaseContainer newInstance() { - return new OracleContainer(); + return newInstance(OracleContainer.DEFAULT_TAG); } @Override public JdbcDatabaseContainer newInstance(String tag) { if (tag != null) { - throw new UnsupportedOperationException("Oracle database tag should be set in the configured image name"); + return new OracleContainer(DockerImageName.parse(OracleContainer.IMAGE).withTag(tag)); } - - return new OracleContainer(); + return newInstance(); } } diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java index 2415fed11f4..7d026924442 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java @@ -1,21 +1,28 @@ package org.testcontainers.junit.oracle; -import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.OracleContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; +import org.testcontainers.utility.DockerImageName; import java.sql.ResultSet; import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -@Ignore public class SimpleOracleTest extends AbstractContainerDatabaseTest { + public static final DockerImageName ORACLE_DOCKER_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe:18.4.0-slim"); + @Test public void testSimple() throws SQLException { - try (OracleContainer oracle = new OracleContainer()) { + + try ( + OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) + .withUsername("baz") + .withPassword("bar") + ) { + oracle.start(); ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual"); int resultSetInt = resultSet.getInt(1); From b1cdaf97c0ad110faab5c21cbd3e6412d5cff5b3 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 30 Aug 2021 13:57:14 +0200 Subject: [PATCH 1402/4969] Tune Cassandra options for faster startup (#4309) * Tune Cassandra options for faster startup * remove `setStartupAttempts` --- .../testcontainers/containers/CassandraContainer.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index 597b1c9b017..e3ae084cb8a 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -58,8 +58,15 @@ public CassandraContainer(DockerImageName dockerImageName) { dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPort(CQL_PORT); - setStartupAttempts(3); this.enableJmxReporting = false; + + withEnv("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch"); + withEnv( + "JVM_OPTS", + "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0" + ); + withEnv("HEAP_NEWSIZE", "128M"); + withEnv("MAX_HEAP_SIZE", "1024M"); } @Override From 9f77a6dff067df4f01b7edd91afe4444a9c9b1d3 Mon Sep 17 00:00:00 2001 From: pioorg Date: Wed, 1 Sep 2021 22:06:21 +0200 Subject: [PATCH 1403/4969] Shorten fallback to another strategy (#4386) * Removed double check of configured Docker client strategy. * Shortened the ping timeout (when choosing docker client) to 5 seconds. * Added `client.ping.timeout` configuration option. * Made relevant change in the docs. --- .../dockerclient/DockerClientProviderStrategy.java | 6 ++++-- .../testcontainers/utility/TestcontainersConfiguration.java | 4 ++++ docs/features/configuration.md | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 248e40790aa..5c797b3b782 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -111,10 +111,11 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List configurationFailures = new ArrayList<>(); + String dockerClientStrategyClassName = TestcontainersConfiguration.getInstance().getDockerClientStrategyClassName(); return Stream .concat( Stream - .of(TestcontainersConfiguration.getInstance().getDockerClientStrategyClassName()) + .of(dockerClientStrategyClassName) .filter(Objects::nonNull) .flatMap(it -> { try { @@ -136,6 +137,7 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List log.info("Loaded {} from ~/.testcontainers.properties, will try it first", strategy.getClass().getName())), strategies .stream() + .filter(it -> !it.getClass().getCanonicalName().equals(dockerClientStrategyClassName)) .filter(DockerClientProviderStrategy::isApplicable) .sorted(Comparator.comparing(DockerClientProviderStrategy::getPriority).reversed()) ) @@ -145,7 +147,7 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List { + info = Unreliables.retryUntilSuccess(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS, () -> { return strategy.PING_RATE_LIMITER.getWhenReady(() -> { log.debug("Pinging docker daemon..."); return dockerClient.infoCmd().exec(); diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index cbbe92dd76d..91d42e45ba0 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -210,6 +210,10 @@ public String getImageSubstitutorClassName() { return getEnvVarOrProperty("image.substitutor", null); } + public Integer getClientPingTimeout() { + return Integer.parseInt(getEnvVarOrProperty("client.ping.timeout", "5")); + } + @Nullable @Contract("_, !null, _ -> !null") private String getConfigurable(@NotNull final String propertyName, @Nullable final String defaultValue, Properties... propertiesSources) { diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 821d0cc7629..73876a51483 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -94,6 +94,11 @@ but does not allow starting privileged containers, you can turn off the Ryuk con > **pull.pause.timeout = 30** > By default Testcontainers will abort the pull of an image if the pull appears stalled (no data transferred) for longer than this duration (in seconds). +## Customizing client ping behaviour + +> **client.ping.timeout = 5** +> Specifies for how long Testcontainers will try to connect to the Docker client to obtain valid info about the client before giving up and trying next strategy, if applicable (in seconds). + ## Customizing Docker host detection Testcontainers will attempt to detect the Docker environment and configure everything to work automatically. From fd9d57387c01a83e448591de8a900e27994454e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:30 +0000 Subject: [PATCH 1404/4969] Bump tomcat-jdbc from 10.0.8 to 10.0.10 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.8 to 10.0.10. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 32b7429f1b6..8145855684f 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.8' + api 'org.apache.tomcat:tomcat-jdbc:10.0.10' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.26' } From eccb15945cb0903f4fc6ea279a5d3de6648e868f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:31 +0000 Subject: [PATCH 1405/4969] Bump jedis from 3.6.3 to 3.7.0 in /modules/junit-jupiter Bumps [jedis](https://github.com/redis/jedis) from 3.6.3 to 3.7.0. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v3.6.3...v3.7.0) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index a3e271b0d59..0ece8912384 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:3.6.3' + testImplementation 'redis.clients:jedis:3.7.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testImplementation ('org.mockito:mockito-core:3.11.2') { exclude(module: 'hamcrest-core') From b976691f0e8bba50555a68d7e003950d087b6016 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:31 +0000 Subject: [PATCH 1406/4969] Bump annotations from 21.0.1 to 22.0.0 in /modules/mysql Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index db2deac2d10..e465acaaee3 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -15,5 +15,5 @@ dependencies { testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' - compileOnly 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:22.0.0' } From a7e047f81bbd0a0897a87ead663123774068ce22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:31 +0000 Subject: [PATCH 1407/4969] Bump mariadb-java-client from 2.7.3 to 2.7.4 in /modules/mariadb Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.7.3 to 2.7.4. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.7.3...2.7.4) --- updated-dependencies: - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index e9080ce6131..037573f6143 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:1.0.2' testImplementation project(':jdbc-test') - testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3' + testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4' testImplementation testFixtures(project(':r2dbc')) testImplementation 'org.mariadb:r2dbc-mariadb:1.0.2' From cdd1033d3ea98fa06a52009f9947610154ace342 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:31 +0000 Subject: [PATCH 1408/4969] Bump annotations from 21.0.1 to 22.0.0 in /modules/jdbc Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 4f6c6608b4d..c7ff4a2e76f 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':database-commons') testImplementation project(':test-support') - compileOnly 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:22.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.8' From ae23f9ef82e3a9ed041d6948060d36d400b80031 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:31 +0000 Subject: [PATCH 1409/4969] Bump jedis from 3.6.3 to 3.7.0 in /core Bumps [jedis](https://github.com/redis/jedis) from 3.6.3 to 3.7.0. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v3.6.3...v3.7.0) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 00d9cfda688..7f1a21ae28d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -105,7 +105,7 @@ dependencies { } testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' - testImplementation 'redis.clients:jedis:3.6.3' + testImplementation 'redis.clients:jedis:3.7.0' testImplementation 'com.rabbitmq:amqp-client:5.12.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.9' From 713d324612d09dc5ad2be301e21cca3e31bfbb89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:31 +0000 Subject: [PATCH 1410/4969] Bump annotations from 21.0.1 to 22.0.0 in /modules/spock Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 1e8e8f88503..5fcdeb5a2c6 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -18,7 +18,7 @@ dependencies { testRuntimeOnly 'org.postgresql:postgresql:42.2.23' testRuntimeOnly 'mysql:mysql-connector-java:8.0.25' - testCompileClasspath 'org.jetbrains:annotations:21.0.1' + testCompileClasspath 'org.jetbrains:annotations:22.0.0' } sourceJar { From 5774925e060c3a7b9861de72dfced5c4cc9f1579 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:31 +0000 Subject: [PATCH 1411/4969] Bump annotations from 21.0.1 to 22.0.0 in /modules/nginx Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/nginx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index 5bfcfae910b..b8f45d394c1 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -2,6 +2,6 @@ description = "Testcontainers :: Nginx" dependencies { api project(':testcontainers') - compileOnly 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:22.0.0' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From e3c118925ec47904f77285e951c013628932e5ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:32 +0000 Subject: [PATCH 1412/4969] Bump annotations from 21.0.1 to 22.0.0 in /modules/selenium Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/selenium/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index f91bb361775..5cff4c544b3 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -12,6 +12,6 @@ dependencies { testImplementation project(':nginx') testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compileOnly 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:22.0.0' testCompileClasspath 'org.jetbrains:annotations:21.0.1' } From bc766614dc994e932c5b76d623b053519e249e84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:32 +0000 Subject: [PATCH 1413/4969] Bump aws-java-sdk-dynamodb from 1.12.37 to 1.12.60 in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.37 to 1.12.60. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.37...1.12.60) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 85c91332c12..4cf9b02f160 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.37' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.60' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.37' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From b86dc29bb1137a76711b41ddce6c9c9be449567f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:32 +0000 Subject: [PATCH 1414/4969] Bump tomcat-jdbc from 10.0.8 to 10.0.10 in /modules/jdbc Bumps tomcat-jdbc from 10.0.8 to 10.0.10. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 4f6c6608b4d..d08b9b68dd8 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:21.0.1' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.8' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.10' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From e48e366577227395c312cc869aa64a058f2fed56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:32 +0000 Subject: [PATCH 1415/4969] Bump mssql-jdbc in /modules/mssqlserver Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 9.3.1.jre8-preview to 9.4.0.jre8. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/dev/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) --- updated-dependencies: - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 74e77d474e9..cd797a9807f 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,12 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.6.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre8' testImplementation project(':r2dbc') testImplementation 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' // MSSQL's wait strategy requires the JDBC driver testImplementation testFixtures(project(':r2dbc')) - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.3.1.jre8-preview' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre8' } From eeb375ee265b28ecd9a83763484639d0c630dfe5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:33 +0000 Subject: [PATCH 1416/4969] Bump java-client from 3.2.0 to 3.2.1 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.2.0 to 3.2.1. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.2.0...java-client-3.2.1) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 823b88a983e..99cf927173e 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') - testImplementation 'com.couchbase.client:java-client:3.2.0' + testImplementation 'com.couchbase.client:java-client:3.2.1' testImplementation 'org.awaitility:awaitility:4.1.0' } From 1a754ff370c5fece493464d49e19caf158141418 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:33 +0000 Subject: [PATCH 1417/4969] Bump annotations from 21.0.1 to 22.0.0 in /modules/postgresql Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 410706429d5..1842a0e7dd7 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -16,5 +16,5 @@ dependencies { testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' - compileOnly 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:22.0.0' } From 4955e7ad871c8fb2fd623f2832a914c94fbf6937 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:35 +0000 Subject: [PATCH 1418/4969] Bump mockito-core from 3.11.2 to 3.12.4 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 3.11.2 to 3.12.4. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.11.2...v3.12.4) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index a3e271b0d59..6c520397d5a 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:3.6.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:3.11.2') { + testImplementation ('org.mockito:mockito-core:3.12.4') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.20.2' From 6f8bebfcb260f6c26994c9b7dfa4fa9206bfca20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:36 +0000 Subject: [PATCH 1419/4969] Bump mockito-core from 3.11.2 to 3.12.4 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 3.11.2 to 3.12.4. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.11.2...v3.12.4) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 00d9cfda688..37fb9e1bae1 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -109,7 +109,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.12.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.9' - testImplementation ('org.mockito:mockito-core:3.11.2') { + testImplementation ('org.mockito:mockito-core:3.12.4') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From faff9872c638dab04e40d601020fb151ed2f5ad3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:37 +0000 Subject: [PATCH 1420/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.13.0 to 7.14.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.13.0...v7.14.1) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 180f373bddd..a27d2b2ecab 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.13.0" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.14.1" testImplementation "org.elasticsearch.client:transport:7.13.4" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 34a912b7da3ea62a10d80e34cf03a6a4ca51892f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:38 +0000 Subject: [PATCH 1421/4969] Bump aws-java-sdk-logs from 1.12.37 to 1.12.60 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.37 to 1.12.60. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.37...1.12.60) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9c3fc24d658..3a307cac1b6 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.37' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.37' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' testImplementation 'software.amazon.awssdk:s3:2.17.9' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From e03d8c5c038270dec66f5416ea049570d4e5becc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:38 +0000 Subject: [PATCH 1422/4969] Bump cucumber-junit from 6.9.1 to 6.11.0 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 6.9.1 to 6.11.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.9.1...v6.11.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index ddffea03dfe..6d3cfc66955 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.9.1' - testImplementation 'io.cucumber:cucumber-junit:6.9.1' + testImplementation 'io.cucumber:cucumber-junit:6.11.0' testImplementation 'org.testcontainers:selenium' } From fd594634f95b0e9d824e3873c8d7b5bf7960cde1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:46 +0000 Subject: [PATCH 1423/4969] Bump annotations from 21.0.1 to 22.0.0 in /examples Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/mongodb-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 8d8c8731c86..86b3e978019 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -9,5 +9,5 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testCompileClasspath 'org.jetbrains:annotations:21.0.1' + testCompileClasspath 'org.jetbrains:annotations:22.0.0' } From ebc61e7438d1c8c0b7a3bfcb3af6f5db086a50a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:47 +0000 Subject: [PATCH 1424/4969] Bump mongo-java-driver from 3.12.9 to 3.12.10 in /core Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.9 to 3.12.10. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.9...r3.12.10) --- updated-dependencies: - dependency-name: org.mongodb:mongo-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 00d9cfda688..df1d8c1579d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -107,7 +107,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:3.6.3' testImplementation 'com.rabbitmq:amqp-client:5.12.0' - testImplementation 'org.mongodb:mongo-java-driver:3.12.9' + testImplementation 'org.mongodb:mongo-java-driver:3.12.10' testImplementation ('org.mockito:mockito-core:3.11.2') { exclude(module: 'hamcrest-core') From ec4cd8bbec86463deb79cb39990fc261a271e566 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:51 +0000 Subject: [PATCH 1425/4969] Bump org.springframework.boot from 2.5.2 to 2.5.4 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.5.2 to 2.5.4. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.5.2...v2.5.4) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 70c4a2683b0..49893845273 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.2' + id 'org.springframework.boot' version '2.5.4' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index db7e4ebe957..e32a1446651 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.5.2" + id("org.springframework.boot") version "2.5.4" id("org.jetbrains.kotlin.jvm") version "1.5.10" id("org.jetbrains.kotlin.plugin.spring") version "1.5.21" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 00f6f22728d..3f93d3c153c 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.2' + id 'org.springframework.boot' version '2.5.4' } apply plugin: 'io.spring.dependency-management' From bb67ee0f411fc28b38268bfb9815f74df0dfadc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:53 +0000 Subject: [PATCH 1426/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.5.21 to 1.5.30. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index db7e4ebe957..9cf3680a2aa 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.5.2" id("org.jetbrains.kotlin.jvm") version "1.5.10" - id("org.jetbrains.kotlin.plugin.spring") version "1.5.21" + id("org.jetbrains.kotlin.plugin.spring") version "1.5.30" } apply plugin: 'io.spring.dependency-management' From c7dcb7a149df3bbbdff127e7447a83677b5bcb39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:00:54 +0000 Subject: [PATCH 1427/4969] Bump gson from 2.8.7 to 2.8.8 in /examples Bumps [gson](https://github.com/google/gson) from 2.8.7 to 2.8.8. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.8.7...gson-parent-2.8.8) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 04d8f249511..c869fd9cdc0 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.20" implementation 'biz.paluch.redis:spinach:0.3' - implementation 'com.google.code.gson:gson:2.8.7' + implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.3' testImplementation 'org.mockito:mockito-all:1.10.19' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 56dab9c4951..541d55839ec 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:3.6.1' - implementation 'com.google.code.gson:gson:2.8.7' + implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.3' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 771f55551ea..21e35752540 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:3.6.1' - implementation 'com.google.code.gson:gson:2.8.7' + implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index a806f483938..1cd86d10bd4 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation 'redis.clients:jedis:3.6.1' - implementation 'com.google.code.gson:gson:2.8.7' + implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From 239fc52a798e25d6ba45ba2a92db98175bf6d335 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:01:11 +0000 Subject: [PATCH 1428/4969] Bump gradle-update/update-gradle-wrapper-action from 1.0.14 to 1.0.15 Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 1.0.14 to 1.0.15. - [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases) - [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/6356f411fa7c14aab1fb2ac2fd20762a629e2fbf...a116d8b533be6c4e71a8b3c3871b7344ca72bf12) --- updated-dependencies: - dependency-name: gradle-update/update-gradle-wrapper-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 272594c26df..f9f1ec85662 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@6356f411fa7c14aab1fb2ac2fd20762a629e2fbf # v1.0.13 + uses: gradle-update/update-gradle-wrapper-action@a116d8b533be6c4e71a8b3c3871b7344ca72bf12 # v1.0.13 with: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies From b588ad8f38da48e0af867a174e2a1e8786b364f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:01:15 +0000 Subject: [PATCH 1429/4969] Bump actions/setup-java from 2.1.0 to 2.3.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2.1.0 to 2.3.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2.1.0...v2.3.0) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 789c4fdd577..88587a6ab61 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -15,7 +15,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.1.0 + - uses: actions/setup-java@v2.3.0 with: java-version: '8.0.292+10' distribution: adopt-hotspot @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.1.0 + - uses: actions/setup-java@v2.3.0 with: java-version: '8.0.292+10' distribution: adopt-hotspot diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 627d69befad..d44cd414fab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.1.0 + - uses: actions/setup-java@v2.3.0 with: java-version: '8.0.292+10' distribution: adopt-hotspot @@ -41,7 +41,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.1.0 + - uses: actions/setup-java@v2.3.0 with: java-version: '8.0.292+10' distribution: adopt-hotspot diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 943dfcf005a..73b3b2152c9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2.3.0 with: java-version: '1.8' - name: Clear existing docker image cache From 36a842728bc0ab73b6c038f29c9155eb3a6d8cbb Mon Sep 17 00:00:00 2001 From: pioorg Date: Sat, 4 Sep 2021 13:28:28 +0200 Subject: [PATCH 1430/4969] Reverted saving user properties. (#4442) --- .../org/testcontainers/utility/TestcontainersConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 91d42e45ba0..85b25ca8e43 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -311,6 +311,8 @@ public boolean updateUserConfig(@NonNull String prop, @NonNull String value) { return false; } + userProperties.setProperty(prop, value); + USER_CONFIG_FILE.createNewFile(); try (OutputStream outputStream = new FileOutputStream(USER_CONFIG_FILE)) { userProperties.store(outputStream, "Modified by Testcontainers"); From 8f99905899cca2df5cc70a174de7ec696127dc2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:25:57 +0000 Subject: [PATCH 1431/4969] Bump transport from 7.13.4 to 7.14.1 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.13.4 to 7.14.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.13.4...v7.14.1) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index a27d2b2ecab..183b2428ba8 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.14.1" - testImplementation "org.elasticsearch.client:transport:7.13.4" + testImplementation "org.elasticsearch.client:transport:7.14.1" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 21e7b0e207c2e6217bb671c5ead7076d338de70d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:07 +0000 Subject: [PATCH 1432/4969] Bump aws-java-sdk-s3 from 1.12.37 to 1.12.62 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.37 to 1.12.62. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.37...1.12.62) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3a307cac1b6..5220306a3f1 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.37' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.62' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' From bf6fa3830f47c0a2930107fc283b4e4cb94870b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:08 +0000 Subject: [PATCH 1433/4969] Bump amqp-client from 5.12.0 to 5.13.1 in /core Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.12.0 to 5.13.1. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.12.0...v5.13.1) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index dcf83d1a6f6..fa0e18e40e8 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -106,7 +106,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:3.7.0' - testImplementation 'com.rabbitmq:amqp-client:5.12.0' + testImplementation 'com.rabbitmq:amqp-client:5.13.1' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' testImplementation ('org.mockito:mockito-core:3.12.4') { From d2e31c172ce1154a229ea5bfeb9a422adbd4ec6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:12 +0000 Subject: [PATCH 1434/4969] Bump cucumber-java from 6.9.1 to 6.11.0 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 6.9.1 to 6.11.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.9.1...v6.11.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 6d3cfc66955..6febeeec483 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:6.9.1' + testImplementation 'io.cucumber:cucumber-java:6.11.0' testImplementation 'io.cucumber:cucumber-junit:6.11.0' testImplementation 'org.testcontainers:selenium' } From 077c648a0e1bb3e3803c99851d711ede9797ab77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:13 +0000 Subject: [PATCH 1435/4969] Bump org.jetbrains.kotlin.jvm from 1.5.10 to 1.5.30 in /examples Bumps org.jetbrains.kotlin.jvm from 1.5.10 to 1.5.30. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 744883204bc..6096fcb37b4 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.5.4" - id("org.jetbrains.kotlin.jvm") version "1.5.10" + id("org.jetbrains.kotlin.jvm") version "1.5.30" id("org.jetbrains.kotlin.plugin.spring") version "1.5.30" } From c15212d73e4467e8c123245eb644333008e03aca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:13 +0000 Subject: [PATCH 1436/4969] Bump annotations from 21.0.1 to 22.0.0 in /core Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index dcf83d1a6f6..e5a33c49ade 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -68,7 +68,7 @@ dependencies { api 'junit:junit:4.12' api 'org.slf4j:slf4j-api:1.7.32' - compileOnly 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:22.0.0' testCompileClasspath 'org.jetbrains:annotations:21.0.1' api 'org.apache.commons:commons-compress:1.21' api ('org.rnorth.duct-tape:duct-tape:1.0.8') { From f829069b8dded7aa3115f4067fa15ee15a9227e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:21 +0000 Subject: [PATCH 1437/4969] Bump aws-java-sdk-sqs from 1.12.37 to 1.12.62 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.37 to 1.12.62. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.37...1.12.62) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3a307cac1b6..a569f7dbf2b 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.37' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.62' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' testImplementation 'software.amazon.awssdk:s3:2.17.9' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From a9f6c44a81e5c36aef961c7f10eed026791b6fba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:23 +0000 Subject: [PATCH 1438/4969] Bump s3 from 2.17.9 to 2.17.34 in /modules/localstack Bumps s3 from 2.17.9 to 2.17.34. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 3a307cac1b6..908055ddfd1 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' - testImplementation 'software.amazon.awssdk:s3:2.17.9' + testImplementation 'software.amazon.awssdk:s3:2.17.34' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From cbed98a8101f23b65a85f8f183ccf18b366a89b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:26:28 +0000 Subject: [PATCH 1439/4969] Bump jedis from 3.6.1 to 3.7.0 in /examples Bumps [jedis](https://github.com/redis/jedis) from 3.6.1 to 3.7.0. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.6.1...v3.7.0) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index b0555f1b38b..fe269d58e77 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:3.6.1' + implementation 'redis.clients:jedis:3.7.0' implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index bba7d9bfc51..2d9f50b86bd 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:3.6.1' + implementation 'redis.clients:jedis:3.7.0' implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 1199b908048..f3a18e685f3 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.6.1' + implementation 'redis.clients:jedis:3.7.0' implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From 475e6192010493e3208d69db8d9637d730df8fd4 Mon Sep 17 00:00:00 2001 From: Oguzhan Ozdemir Date: Tue, 7 Sep 2021 11:07:09 +0300 Subject: [PATCH 1440/4969] Add Thundra Foresight Integration to the CI Build (#4313) --- .github/workflows/ci.yml | 22 ++++++++++++++++++++-- README.md | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d44cd414fab..a6ae55e16b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,14 @@ env: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} jobs: + thundra_test_initializer: + runs-on: ubuntu-latest + outputs: + thundra_agent_testrun_id: ${{ steps.thundra_test_initializer.outputs.thundra_agent_testrun_id }} + steps: + - uses: actions/checkout@v2 + - id: thundra_test_initializer + uses: thundra-io/thundra-test-init-action@v1 find_gradle_jobs: runs-on: ubuntu-18.04 outputs: @@ -34,7 +42,7 @@ jobs: echo $TASKS echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" check: - needs: find_gradle_jobs + needs: [find_gradle_jobs, thundra_test_initializer] strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} @@ -53,9 +61,19 @@ jobs: key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} - name: Clear existing docker image cache run: docker image prune -af + - name: Thundra Gradle Test Instrumentation + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + uses: thundra-io/thundra-gradle-test-action@v1 + with: + apikey: ${{ secrets.THUNDRA_API_KEY }} + project_id: ${{ secrets.THUNDRA_PROJECT_ID }} - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | - ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} + ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} \ + $($THUNDRA_GRADLE_INIT_SCRIPT_PATH || echo "--init-script $THUNDRA_GRADLE_INIT_SCRIPT_PATH") + env: + THUNDRA_AGENT_TEST_RUN_ID: ${{ needs.thundra_test_initializer.outputs.thundra_agent_testrun_id }} + THUNDRA_AGENT_REPORT_REST_BASEURL: https://collector.thundra.us/v1 httpclient5_test: runs-on: ubuntu-18.04 steps: diff --git a/README.md b/README.md index d3446cbb31e..752c501e91f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Testcontainers +[![Thundra Foresight](https://thundra-assets-prod.s3.us-west-2.amazonaws.com/images/badges/thundra-foresight-badge-enabled.svg)](https://foresight.thundra.live/testRuns/5a49cc30-f063-11eb-9a03-0242ac130003) + > Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. ![Testcontainers logo](docs/logo.png) From 8746f20aec2f1f0140a5ae66639e690c3388a4b1 Mon Sep 17 00:00:00 2001 From: Galen S <56940276+schmidt-galen-heb@users.noreply.github.com> Date: Wed, 8 Sep 2021 06:49:34 -0500 Subject: [PATCH 1441/4969] Use POSIX mode for large numbers in tar archives (#4384) (#4388) * Use POSIX mode for large numbers in tar archives (#4384) * PR feedback --- .../main/java/org/testcontainers/containers/ContainerState.java | 1 + .../org/testcontainers/images/builder/ImageFromDockerfile.java | 1 + 2 files changed, 2 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index da87dbdf724..5de9ef7c566 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -272,6 +272,7 @@ default void copyFileToContainer(Transferable transferable, String containerPath TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(byteArrayOutputStream) ) { tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); + tarArchive.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); transferable.transferTo(tarArchive, containerPath); tarArchive.finish(); diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index b36779f1b9e..05bb6911c3e 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -123,6 +123,7 @@ public void onNext(BuildResponseItem item) { // To build an image, we have to send the context to Docker in TAR archive format try (TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(new GZIPOutputStream(out))) { tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); + tarArchive.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); for (Map.Entry entry : transferables.entrySet()) { Transferable transferable = entry.getValue(); From 79b064bcb0e1ffba6058fc2e7347cb41934adc00 Mon Sep 17 00:00:00 2001 From: Denis Zavedeev <13610290+cac03@users.noreply.github.com> Date: Tue, 14 Sep 2021 22:59:40 +0300 Subject: [PATCH 1442/4969] Fix `CmdModifierTest#testMemoryLimitModified` in cgroup2 environment. (#4375) * Fix `CmdModifierTest#testMemoryLimitModified` in cgroup2 environment. The `testMemoryLimitModified` was failing in cgroup2 environment because of the missing `/sys/fs/cgroup/memory/memory.limit_in_bytes` file. In the cgroup2 environment a new file should be checked instead -- `/sys/fs/cgroup/memory.max`. This commit intrdocues changes to `cat` both files: 1. `/sys/fs/cgroup/memory/memory.limit_in_bytes` from the first version of cgroup 2. `/sys/fs/cgroup/memory.max` from the second Similar issues: 1. https://github.com/oracle/docker-images/issues/1939 2. https://github.com/apify/apify-js/issues/693 * Use `docker info` to distinguish cgroup version * Use `DockerClientFactory.instance().client()` instead of `memoryLimitedRedis.getDockerClient()` --- .../src/test/java/generic/CmdModifierTest.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index 73338ba38ee..5306426070f 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -1,12 +1,16 @@ package generic; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Info; import org.junit.Rule; import org.junit.Test; +import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; import java.io.IOException; +import java.util.Objects; import static org.junit.Assert.assertEquals; @@ -39,7 +43,18 @@ public void testHostnameModified() throws IOException, InterruptedException { @Test public void testMemoryLimitModified() throws IOException, InterruptedException { - final Container.ExecResult execResult = memoryLimitedRedis.execInContainer("cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"); + final Container.ExecResult execResult = memoryLimitedRedis.execInContainer("cat", getMemoryLimitFilePath()); assertEquals(String.valueOf(memoryInBytes), execResult.getStdout().trim()); } + + private String getMemoryLimitFilePath() { + DockerClient dockerClient = DockerClientFactory.instance().client(); + Info info = dockerClient.infoCmd().exec(); + Object cgroupVersion = info.getRawValues().get("CgroupVersion"); + boolean cgroup2 = Objects.equals("2", cgroupVersion); + if (cgroup2) { + return "/sys/fs/cgroup/memory.max"; + } + return "/sys/fs/cgroup/memory/memory.limit_in_bytes"; + } } From 5e88d744dcdf26965a8a4176f52c94e19be204f4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 15 Sep 2021 09:05:30 +0200 Subject: [PATCH 1443/4969] Update to `docker-java` 3.2.12 (#4459) * Try `docker-java` 3.2.12 * use shaded configuration * Update build.gradle --- core/build.gradle | 10 ++++++---- .../testcontainers/DockerClientFactory.java | 19 +++++++++++++++++-- .../org/testcontainers/LazyDockerClient.java | 16 ---------------- .../AuthDelegatingDockerClientConfig.java | 16 +++++----------- 4 files changed, 28 insertions(+), 33 deletions(-) delete mode 100644 core/src/main/java/org/testcontainers/LazyDockerClient.java diff --git a/core/build.gradle b/core/build.gradle index ed1e82271ed..f77461a06fc 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -77,9 +77,11 @@ dependencies { shaded 'org.awaitility:awaitility:4.1.0' - api "com.github.docker-java:docker-java-api:3.2.11" + shaded platform('com.github.docker-java:docker-java-bom:3.2.12') - shaded ('com.github.docker-java:docker-java-core:3.2.11') { + api "com.github.docker-java:docker-java-api" + + shaded ('com.github.docker-java:docker-java-core') { exclude(group: 'com.github.docker-java', module: 'docker-java-api') exclude(group: 'com.github.docker-java', module: 'docker-java-transport') exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') @@ -88,13 +90,13 @@ dependencies { exclude(group: 'org.apache.commons', module: 'commons-compress') } - shaded ('com.github.docker-java:docker-java-transport-okhttp:3.2.11') { + shaded ('com.github.docker-java:docker-java-transport-okhttp') { exclude(group: 'com.github.docker-java', module: 'docker-java-core') exclude(group: 'net.java.dev.jna') exclude(group: 'org.slf4j') } - api 'com.github.docker-java:docker-java-transport-zerodep:3.2.11' + api 'com.github.docker-java:docker-java-transport-zerodep' shaded "org.yaml:snakeyaml:1.29" diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 554860d8985..36c4c717b76 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -1,6 +1,7 @@ package org.testcontainers; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.DockerClientDelegate; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.PullImageCmd; @@ -94,7 +95,17 @@ public class DockerClientFactory { } public static DockerClient lazyClient() { - return LazyDockerClient.INSTANCE; + return new DockerClientDelegate() { + @Override + protected DockerClient getDockerClient() { + return instance().client(); + } + + @Override + public String toString() { + return "LazyDockerClient"; + } + }; } /** @@ -177,7 +188,11 @@ public DockerClient client() { final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); - final DockerClient client = new DelegatingDockerClient(strategy.getDockerClient()) { + final DockerClient client = new DockerClientDelegate() { + + @Getter + final DockerClient dockerClient = strategy.getDockerClient(); + @Override public void close() { throw new IllegalStateException("You should never close the global DockerClient!"); diff --git a/core/src/main/java/org/testcontainers/LazyDockerClient.java b/core/src/main/java/org/testcontainers/LazyDockerClient.java deleted file mode 100644 index 49ebf9330a7..00000000000 --- a/core/src/main/java/org/testcontainers/LazyDockerClient.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.testcontainers; - -import com.github.dockerjava.api.DockerClient; -import lombok.ToString; -import lombok.experimental.Delegate; - -@ToString -enum LazyDockerClient implements DockerClient { - - INSTANCE; - - @Delegate - final DockerClient getDockerClient() { - return DockerClientFactory.instance().client(); - } -} diff --git a/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java index 5acb7ab8835..1f534eb59e5 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java @@ -2,7 +2,7 @@ import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.core.DockerClientConfig; -import lombok.experimental.Delegate; +import com.github.dockerjava.core.DockerClientConfigDelegate; import lombok.extern.slf4j.Slf4j; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.RegistryAuthLocator; @@ -18,20 +18,18 @@ * TODO move to docker-java */ @Slf4j -class AuthDelegatingDockerClientConfig implements DockerClientConfig { - - @Delegate(excludes = DelegateExclusions.class) - private DockerClientConfig delegate; +class AuthDelegatingDockerClientConfig extends DockerClientConfigDelegate { public AuthDelegatingDockerClientConfig(DockerClientConfig delegate) { - this.delegate = delegate; + super(delegate); } + @Override public AuthConfig effectiveAuthConfig(String imageName) { // allow docker-java auth config to be used as a fallback AuthConfig fallbackAuthConfig; try { - fallbackAuthConfig = delegate.effectiveAuthConfig(imageName); + fallbackAuthConfig = super.effectiveAuthConfig(imageName); } catch (Exception e) { log.debug("Delegate call to effectiveAuthConfig failed with cause: '{}'. " + "Resolution of auth config will continue using RegistryAuthLocator.", @@ -47,8 +45,4 @@ public AuthConfig effectiveAuthConfig(String imageName) { log.debug("Effective auth config [{}]", toSafeString(effectiveAuthConfig)); return effectiveAuthConfig; } - - private interface DelegateExclusions { - AuthConfig effectiveAuthConfig(String imageName); - } } From 6cde564776d9af26e4b69f80e1344f1ea7d0f678 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 16 Sep 2021 13:45:24 +0300 Subject: [PATCH 1444/4969] Allow to disable configuration of `EnvironmentAndSystemPropertyClientProviderStrategy` through Testcontainers (#4387) Adds the `dockerconfig.source` property that can be used to change the way `EnvironmentAndSystemPropertyClientProviderStrategy` is configured. Additionally, `EnvironmentAndSystemPropertyClientProviderStrategy` is not persistable anymore. Currently supports the following modes: * `auto` (which is the default), meaning that the Testcontainers configuration mechanisms can be used to configure docker-java * `autoIgnoringUserProperties`, same as `auto`, but ignoring values set in the user properties --- ...dSystemPropertyClientProviderStrategy.java | 38 ++++++++++++++----- .../utility/TestcontainersConfiguration.java | 17 +-------- ...temPropertyClientProviderStrategyTest.java | 30 +++++++++++++++ .../TestcontainersConfigurationTest.java | 8 ---- docs/features/configuration.md | 4 ++ 5 files changed, 65 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java index e9bdbd90bea..06fdf387d6a 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java @@ -2,6 +2,7 @@ import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientConfig; +import lombok.Getter; import org.testcontainers.utility.TestcontainersConfiguration; import java.util.Optional; @@ -25,13 +26,32 @@ public final class EnvironmentAndSystemPropertyClientProviderStrategy extends Do private final DockerClientConfig dockerClientConfig; + @Getter + private final boolean applicable; + public EnvironmentAndSystemPropertyClientProviderStrategy() { // use docker-java defaults if present, overridden if our own configuration is set - DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder(); + this(DefaultDockerClientConfig.createDefaultConfigBuilder()); + } + + EnvironmentAndSystemPropertyClientProviderStrategy(DefaultDockerClientConfig.Builder configBuilder) { + String dockerConfigSource = TestcontainersConfiguration.getInstance() + .getEnvVarOrProperty("dockerconfig.source", "auto"); - getSetting("docker.host").ifPresent(configBuilder::withDockerHost); - getSetting("docker.tls.verify").ifPresent(configBuilder::withDockerTlsVerify); - getSetting("docker.cert.path").ifPresent(configBuilder::withDockerCertPath); + switch (dockerConfigSource) { + case "auto": + Optional dockerHost = getSetting("docker.host"); + dockerHost.ifPresent(configBuilder::withDockerHost); + applicable = dockerHost.isPresent(); + getSetting("docker.tls.verify").ifPresent(configBuilder::withDockerTlsVerify); + getSetting("docker.cert.path").ifPresent(configBuilder::withDockerCertPath); + break; + case "autoIgnoringUserProperties": + applicable = configBuilder.isDockerHostSetExplicitly(); + break; + default: + throw new InvalidConfigurationException("Invalid value for dockerconfig.source: " + dockerConfigSource); + } dockerClientConfig = configBuilder.build(); } @@ -40,11 +60,6 @@ private Optional getSetting(final String name) { return Optional.ofNullable(TestcontainersConfiguration.getInstance().getEnvVarOrUserProperty(name, null)); } - @Override - protected boolean isApplicable() { - return getSetting("docker.host").isPresent(); - } - @Override public TransportConfig getTransportConfig() { return TransportConfig.builder() @@ -62,4 +77,9 @@ protected int getPriority() { public String getDescription() { return "Environment variables, system properties and defaults. Resolved dockerHost=" + dockerClientConfig.getDockerHost(); } + + @Override + protected boolean isPersistable() { + return false; + } } diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 85b25ca8e43..bb3febd6b3f 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -13,7 +13,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.testcontainers.UnstableAPI; -import org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy; import java.io.File; import java.io.FileNotFoundException; @@ -182,20 +181,8 @@ public String getDockerClientStrategyClassName() { return prefixedEnvVarStrategy; } - // looks for unprefixed env var or unprefixed property - String unprefixedEnvVarOrProperty = getEnvVarOrUserProperty("docker.client.strategy", null); - if (unprefixedEnvVarOrProperty != null) { - return unprefixedEnvVarOrProperty; - } - - // If docker.host is set then EnvironmentAndSystemPropertyClientProviderStrategy is likely to work - String dockerHostProperty = getEnvVarOrUserProperty("docker.host", null); - if (dockerHostProperty != null) { - return EnvironmentAndSystemPropertyClientProviderStrategy.class.getCanonicalName(); - } - - // No value set, and no implicit value to use either - return null; + // looks for unprefixed env var or unprefixed property, or null if the strategy is not set at all + return getEnvVarOrUserProperty("docker.client.strategy", null); } public String getTransportType() { diff --git a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java index 91f61848d69..c8eec1d38d8 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java @@ -16,10 +16,16 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; 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.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -45,6 +51,7 @@ public void checkEnvironmentClear() { @Test public void testWhenConfigAbsent() { + Mockito.doReturn("auto").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); @@ -58,6 +65,7 @@ public void testWhenConfigAbsent() { @Test public void testWhenDockerHostPresent() { + Mockito.doReturn("auto").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); Mockito.doReturn("tcp://1.2.3.4:2375").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); @@ -74,6 +82,7 @@ public void testWhenDockerHostAndSSLConfigPresent() throws IOException { Path tempDir = Files.createTempDirectory("testcontainers-test"); String tempDirPath = tempDir.toAbsolutePath().toString(); + Mockito.doReturn("auto").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); Mockito.doReturn("tcp://1.2.3.4:2375").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); Mockito.doReturn("1").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); Mockito.doReturn(tempDirPath).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); @@ -88,4 +97,25 @@ public void testWhenDockerHostAndSSLConfigPresent() throws IOException { assertTrue(sslConfig instanceof LocalDirectorySSLConfig); assertEquals(tempDirPath, ((LocalDirectorySSLConfig) sslConfig).getDockerCertPath()); } + + @Test + public void applicableWhenIgnoringUserPropertiesAndConfigured() { + Mockito.doReturn("autoIgnoringUserProperties").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); + + DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerHost("tcp://1.2.3.4:2375"); + + EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(configBuilder); + + assertTrue(strategy.isApplicable()); + } + + @Test + public void notApplicableWhenIgnoringUserPropertiesAndNotConfigured() { + Mockito.doReturn("autoIgnoringUserProperties").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); + + EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); + + assertFalse(strategy.isApplicable()); + } } diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index cbb36baf580..7ca656e1eaf 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -2,7 +2,6 @@ import org.junit.Before; import org.junit.Test; -import org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy; import java.util.HashMap; import java.util.Map; @@ -156,13 +155,6 @@ public void shouldReadDockerClientStrategyFromEnvironment() { assertEquals("Docker client strategy is changed by env var", "foo", newConfig().getDockerClientStrategyClassName()); } - @Test - public void shouldUseImplicitDockerClientStrategyWhenDockerHostPropertyIsSet() { - userProperties.remove("docker.client.strategy"); - userProperties.put("docker.host", "tcp://1.2.3.4:5678"); - assertEquals("Docker client strategy is implicitly set when docker host property is set", EnvironmentAndSystemPropertyClientProviderStrategy.class.getCanonicalName(), newConfig().getDockerClientStrategyClassName()); - } - @Test public void shouldNotUseImplicitDockerClientStrategyWhenDockerHostAndStrategyAreBothSet() { userProperties.put("docker.client.strategy", "foo"); diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 73876a51483..8024dbb15ef 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -126,3 +126,7 @@ docker.host=tcp\://my.docker.host\:1234 # Equivalent to the DOCKER_HOST envi docker.tls.verify=1 # Equivalent to the DOCKER_TLS_VERIFY environment variable docker.cert.path=/some/path # Equivalent to the DOCKER_CERT_PATH environment variable ``` +In addition, you can deactivate this behaviour by specifying: +```properties +dockerconfig.source=autoIgnoringUserProperties # 'auto' by default +``` From 5e6dbc791b6184f0de6d1f9d184a78324c1ec945 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 16 Sep 2021 16:14:45 +0200 Subject: [PATCH 1445/4969] Retry internal port checking in the same exec (#4460) * Retry internal port checking in the same exec * Use just grep * Reduce the changeset --- .../InternalCommandPortListeningCheck.java | 5 +++-- .../InternalCommandPortListeningCheckTest.java | 17 ++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index a3b7a5d4dc7..379840a9d7e 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -24,18 +24,19 @@ public class InternalCommandPortListeningCheck implements java.util.concurrent.C @Override public Boolean call() { - StringBuilder command = new StringBuilder("true"); + StringBuilder command = new StringBuilder("while true; do ( true "); for (int internalPort : internalPorts) { command.append(" && "); command.append(" ("); - command.append(format("cat /proc/net/tcp* | awk '{print $2}' | grep -i ':0*%x'", internalPort)); + command.append(format("grep -i ':0*%x' /proc/net/tcp*", internalPort)); command.append(" || "); command.append(format("nc -vz -w 1 localhost %d", internalPort)); command.append(" || "); command.append(format("/bin/bash -c ' Date: Mon, 20 Sep 2021 10:44:02 +0200 Subject: [PATCH 1446/4969] Use distinct with strategies (#4467) --- .../DockerClientProviderStrategy.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 5c797b3b782..52700df22f3 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -25,10 +25,13 @@ import java.net.URI; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; import java.util.stream.Stream; /** @@ -137,10 +140,18 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List log.info("Loaded {} from ~/.testcontainers.properties, will try it first", strategy.getClass().getName())), strategies .stream() - .filter(it -> !it.getClass().getCanonicalName().equals(dockerClientStrategyClassName)) - .filter(DockerClientProviderStrategy::isApplicable) .sorted(Comparator.comparing(DockerClientProviderStrategy::getPriority).reversed()) ) + .filter(new Predicate() { + + final Set> classes = new HashSet<>(); + + @Override + public boolean test(DockerClientProviderStrategy dockerClientProviderStrategy) { + return classes.add(dockerClientProviderStrategy.getClass()); + } + }) + .filter(DockerClientProviderStrategy::isApplicable) .flatMap(strategy -> { try { DockerClient dockerClient = strategy.getDockerClient(); From c7fa8e22df3b022c883a49199803cbbf00e879c4 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Mon, 20 Sep 2021 13:49:46 +0200 Subject: [PATCH 1447/4969] Update JUnit 4.12 to 4.13.2. (#4167) Co-authored-by: Kevin Wittek --- core/build.gradle | 4 ++-- docs/examples/junit4/generic/build.gradle | 2 +- docs/examples/junit4/redis/build.gradle | 2 +- test-support/build.gradle | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index f77461a06fc..35cecd76ce8 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -66,7 +66,7 @@ dependencies { exclude group: "*", module: "*" } - api 'junit:junit:4.12' + api 'junit:junit:4.13.2' api 'org.slf4j:slf4j-api:1.7.32' compileOnly 'org.jetbrains:annotations:22.0.0' testCompileClasspath 'org.jetbrains:annotations:21.0.1' @@ -123,7 +123,7 @@ dependencies { jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" - jarFileTestImplementation 'junit:junit:4.12' + jarFileTestImplementation 'junit:junit:4.13.2' jarFileTestImplementation 'org.assertj:assertj-core:3.20.2' jarFileTestImplementation 'org.ow2.asm:asm-debug-all:5.2' } diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle index 1021bfeffc0..da4697a4543 100644 --- a/docs/examples/junit4/generic/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -1,7 +1,7 @@ description = "Examples for docs" dependencies { - testImplementation "junit:junit:4.12" + testImplementation "junit:junit:4.13.2" testImplementation project(":testcontainers") testImplementation project(":selenium") testImplementation project(":mysql") diff --git a/docs/examples/junit4/redis/build.gradle b/docs/examples/junit4/redis/build.gradle index 7551c6e578e..ea36761b716 100644 --- a/docs/examples/junit4/redis/build.gradle +++ b/docs/examples/junit4/redis/build.gradle @@ -3,6 +3,6 @@ description = "Examples for docs" dependencies { api "io.lettuce:lettuce-core:5.1.1.RELEASE" - testImplementation "junit:junit:4.12" + testImplementation "junit:junit:4.13.2" testImplementation project(":testcontainers") } diff --git a/test-support/build.gradle b/test-support/build.gradle index 4c6fdd2bed1..bd85b585b0f 100644 --- a/test-support/build.gradle +++ b/test-support/build.gradle @@ -1,4 +1,4 @@ dependencies { - implementation 'junit:junit:4.12' + implementation 'junit:junit:4.13.2' implementation 'org.slf4j:slf4j-api:1.7.30' } From 28d74da529427813accd5d14fd2c522796d4fa2a Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Mon, 20 Sep 2021 16:26:34 +0200 Subject: [PATCH 1448/4969] [couchbase] add debug-level phase timings. (#4466) --- .../couchbase/CouchbaseContainer.java | 66 ++++++++++++------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 844917c053f..e9247b8c84a 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -221,20 +221,22 @@ protected void configure() { protected void containerIsStarting(final InspectContainerResponse containerInfo) { logger().debug("Couchbase container is starting, performing configuration."); - waitUntilNodeIsOnline(); - initializeIsEnterprise(); - renameNode(); - initializeServices(); - configureAdminUser(); - configureExternalPorts(); + timePhase("waitUntilNodeIsOnline", this::waitUntilNodeIsOnline); + timePhase("initializeIsEnterprise", this::initializeIsEnterprise); + timePhase("renameNode", this::renameNode); + timePhase("initializeServices", this::initializeServices); + timePhase("configureAdminUser", this::configureAdminUser); + timePhase("configureExternalPorts", this::configureExternalPorts); + if (enabledServices.contains(CouchbaseService.INDEX)) { - configureIndexer(); + timePhase("configureIndexer", this::configureIndexer); } } @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { - createBuckets(); + timePhase("createBuckets", this::createBuckets); + logger().info("Couchbase container is ready! UI available at http://{}:{}", getHost(), getMappedPort(MGMT_PORT)); } @@ -389,30 +391,34 @@ private void createBuckets() { checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName()); - new HttpWaitStrategy() + timePhase("createBucket:" + bucket.getName() + ":waitForAllServicesEnabled", () -> + new HttpWaitStrategy() .forPath("/pools/default/b/" + bucket.getName()) .forPort(MGMT_PORT) .withBasicCredentials(username, password) .forStatusCode(200) .forResponsePredicate(new AllServicesEnabledPredicate()) - .waitUntilReady(this); + .waitUntilReady(this) + ); if (enabledServices.contains(CouchbaseService.QUERY)) { // If the query service is enabled, make sure that we only proceed if the query engine also // knows about the bucket in its metadata configuration. - Unreliables.retryUntilTrue(1, TimeUnit.MINUTES, () -> { - @Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() - .add("statement", "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" + bucket.getName() + "\"") - .build(), true); - - String body = queryResponse.body() != null ? queryResponse.body().string() : null; - checkSuccessfulResponse(queryResponse, "Could not poll query service state for bucket: " + bucket.getName()); - - return Optional.of(MAPPER.readTree(body)) - .map(n -> n.at("/results/0/present")) - .map(JsonNode::asBoolean) - .orElse(false); - }); + timePhase( + "createBucket:" + bucket.getName() + ":queryKeyspacePresent", + () -> Unreliables.retryUntilTrue(1, TimeUnit.MINUTES, () -> { + @Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() + .add("statement", "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" + bucket.getName() + "\"") + .build(), true); + + String body = queryResponse.body() != null ? queryResponse.body().string() : null; + checkSuccessfulResponse(queryResponse, "Could not poll query service state for bucket: " + bucket.getName()); + + return Optional.of(MAPPER.readTree(body)) + .map(n -> n.at("/results/0/present")) + .map(JsonNode::asBoolean) + .orElse(false); + })); } if (bucket.hasPrimaryIndex()) { @@ -501,6 +507,20 @@ private Response doHttpRequest(final int port, final String path, final String m } } + /** + * Helper method which times an individual phase and logs it for debugging and optimization purposes. + * + * @param name the name of the phase. + * @param toTime the runnable that should be timed. + */ + private void timePhase(final String name, final Runnable toTime) { + long start = System.nanoTime(); + toTime.run(); + long end = System.nanoTime(); + + logger().debug("Phase {} took {}ms", name, TimeUnit.NANOSECONDS.toMillis(end - start)); + } + /** * In addition to getting a 200, we need to make sure that all services we need are enabled and available on * the bucket. From 0ad8154f198cfe6519a845e4ddb4ec564122f85c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Sep 2021 10:11:15 +0100 Subject: [PATCH 1449/4969] Update Gradle Wrapper to 7.2 (#4379) Co-authored-by: gradle-update-robot Co-authored-by: Richard North --- .../gradle/wrapper/gradle-wrapper.properties | 4 +- examples/gradlew | 257 +++++++++++------- gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 257 +++++++++++------- 4 files changed, 310 insertions(+), 212 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 2957f437446..a2e01c0dffe 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=bf8b869948901d422e9bb7d1fa61da6a6e19411baa7ad6ee929073df85d6365d -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +distributionSha256Sum=f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/gradlew b/examples/gradlew index 744e882ed57..1b6c787337f 100755 --- a/examples/gradlew +++ b/examples/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 17ba19021b8..a37233c5e2e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=9bb8bc05f562f2d42bdf1ba8db62f6b6fa1c3bf6c392228802cc7cb0578fe7e0 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip +distributionSha256Sum=a8da5b02437a60819cad23e10fc7e9cf32bcb57029d9cb277e26eeff76ce014b +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882ed57..1b6c787337f 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" From 8712457efea69e0daf4f9add52478d48eb32d68f Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 23 Sep 2021 07:19:45 +0100 Subject: [PATCH 1450/4969] Refactor JDBC URL parsing to support different Oracle URLs (#4476) Detects SID `:` or service name `/` in the supplied TC JDBC URL. In addition, the affected regex patterns have been refactored to use named groups. Co-authored-by: Justin Wyer --- .../testcontainers/jdbc/ConnectionUrl.java | 73 ++++++++++++++----- .../jdbc/ConnectionUrlDriversTests.java | 11 ++- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java index 4f339b43fe5..3354ed45c39 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java @@ -7,9 +7,9 @@ import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; + import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -97,25 +97,25 @@ private void parseUrl() { throw new IllegalArgumentException("JDBC URL matches jdbc:tc: prefix but the database or tag name could not be identified"); } } - databaseType = urlMatcher.group(1); + databaseType = urlMatcher.group("databaseType"); - imageTag = Optional.ofNullable(urlMatcher.group(3)); + imageTag = Optional.ofNullable(urlMatcher.group("imageTag")); //String like hostname:port/database name, which may vary based on target database. //Clients can further parse it as needed. - dbHostString = urlMatcher.group(4); + dbHostString = urlMatcher.group("dbHostString"); //In case it matches to the default pattern Matcher dbInstanceMatcher = Patterns.DB_INSTANCE_MATCHING_PATTERN.matcher(dbHostString); if (dbInstanceMatcher.matches()) { - databaseHost = Optional.of(dbInstanceMatcher.group(1)); - databasePort = Optional.ofNullable(dbInstanceMatcher.group(3)).map(value -> Integer.valueOf(value)); - databaseName = Optional.of(dbInstanceMatcher.group(4)); + databaseHost = Optional.of(dbInstanceMatcher.group("databaseHost")); + databasePort = Optional.ofNullable(dbInstanceMatcher.group("databasePort")).map(Integer::valueOf); + databaseName = Optional.of(dbInstanceMatcher.group("databaseName")); } queryParameters = Collections.unmodifiableMap( parseQueryParameters( - Optional.ofNullable(urlMatcher.group(5)).orElse(""))); + Optional.ofNullable(urlMatcher.group("queryParameters")).orElse(""))); String query = queryParameters .entrySet() @@ -123,7 +123,7 @@ private void parseUrl() { .map(e -> e.getKey() + "=" + e.getValue()) .collect(Collectors.joining("&")); - if (query == null || query.trim().length() == 0) { + if (query.trim().length() == 0) { queryString = Optional.empty(); } else { queryString = Optional.of("?" + query); @@ -149,7 +149,7 @@ private void parseUrl() { } private Map parseTmpfsOptions(Map containerParameters) { - if(!containerParameters.containsKey("TC_TMPFS")){ + if (!containerParameters.containsKey("TC_TMPFS")) { return Collections.emptyMap(); } @@ -209,16 +209,49 @@ public Map getTmpfsOptions() { * @author manikmagar */ public interface Patterns { - Pattern URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z0-9]+)(:([^:]+))?://([^\\?]+)(\\?.*)?"); - - Pattern ORACLE_URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z]+)(:([^(thin:)]+))?:thin:@([^\\?]+)(\\?.*)?"); + Pattern URL_MATCHING_PATTERN = Pattern.compile( + "jdbc:tc:" + + "(?[a-z0-9]+)" + + "(:(?[^:]+))?" + + "://" + + "(?[^?]+)" + + "(?\\?.*)?" + ); + + Pattern ORACLE_URL_MATCHING_PATTERN = Pattern.compile( + "jdbc:tc:" + + "(?[a-z]+)" + + "(:(?(?!thin).+))?:thin:(//)?" + + "(" + + "(?[^:" + + "?^/]+)/(?[^?^/]+)" + + ")?" + + "@" + + "(?[^?]+)" + + "(?\\?.*)?" + ); //Matches to part of string - hostname:port/databasename - Pattern DB_INSTANCE_MATCHING_PATTERN = Pattern.compile("([^:]+)(:([0-9]+))?/([^\\\\?]+)"); - - Pattern DAEMON_MATCHING_PATTERN = Pattern.compile(".*([\\?&]?)TC_DAEMON=([^\\?&]+).*"); - Pattern INITSCRIPT_MATCHING_PATTERN = Pattern.compile(".*([\\?&]?)TC_INITSCRIPT=([^\\?&]+).*"); - Pattern INITFUNCTION_MATCHING_PATTERN = Pattern.compile(".*([\\?&]?)TC_INITFUNCTION=" + + Pattern DB_INSTANCE_MATCHING_PATTERN = Pattern.compile( + "(?[^:]+)" + + "(:(?[0-9]+))?" + + "(" + + "(?[:/])" + + "|" + + ";databaseName=" + + ")" + + "(?[^\\\\?]+)" + ); + + Pattern DAEMON_MATCHING_PATTERN = Pattern.compile(".*([?&]?)TC_DAEMON=([^?&]+).*"); + + /** + * @deprecated for removal + */ + @Deprecated + Pattern INITSCRIPT_MATCHING_PATTERN = Pattern.compile(".*([?&]?)TC_INITSCRIPT=([^?&]+).*"); + + Pattern INITFUNCTION_MATCHING_PATTERN = Pattern.compile(".*([?&]?)TC_INITFUNCTION=" + "((\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.)*\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)" + "::" + "(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)" + @@ -226,9 +259,9 @@ public interface Patterns { String TC_PARAM_NAME_PATTERN = "(TC_[A-Z_]+)"; - Pattern TC_PARAM_MATCHING_PATTERN = Pattern.compile(TC_PARAM_NAME_PATTERN + "=([^\\?&]+)"); + Pattern TC_PARAM_MATCHING_PATTERN = Pattern.compile(TC_PARAM_NAME_PATTERN + "=([^?&]+)"); - Pattern QUERY_PARAM_MATCHING_PATTERN = Pattern.compile("([^\\?&=]+)=([^\\?&]*)"); + Pattern QUERY_PARAM_MATCHING_PATTERN = Pattern.compile("([^?&=]+)=([^?&]*)"); } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java index 920fab04016..12ca5c28c3d 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java @@ -37,12 +37,17 @@ public static Iterable data() { {"jdbc:tc:mysql://hostname/test", "mysql", Optional.empty(), "hostname/test", "test"}, {"jdbc:tc:postgresql:1.2.3://hostname/test", "postgresql", Optional.of("1.2.3"), "hostname/test", "test"}, {"jdbc:tc:postgresql://hostname/test", "postgresql", Optional.empty(), "hostname/test", "test"}, - {"jdbc:tc:sqlserver:1.2.3://localhost;instance=SQLEXPRESS:1433;databaseName=test", "sqlserver", Optional.of("1.2.3"), "localhost;instance=SQLEXPRESS:1433;databaseName=test", ""}, - {"jdbc:tc:sqlserver://localhost;instance=SQLEXPRESS:1433;databaseName=test", "sqlserver", Optional.empty(), "localhost;instance=SQLEXPRESS:1433;databaseName=test", ""}, + {"jdbc:tc:sqlserver:1.2.3://localhost;instance=SQLEXPRESS:1433;databaseName=test", "sqlserver", Optional.of("1.2.3"), "localhost;instance=SQLEXPRESS:1433;databaseName=test", "test"}, + {"jdbc:tc:sqlserver://localhost;instance=SQLEXPRESS:1433;databaseName=test", "sqlserver", Optional.empty(), "localhost;instance=SQLEXPRESS:1433;databaseName=test", "test"}, {"jdbc:tc:mariadb:1.2.3://localhost:3306/test", "mariadb", Optional.of("1.2.3"), "localhost:3306/test", "test"}, {"jdbc:tc:mariadb://localhost:3306/test", "mariadb", Optional.empty(), "localhost:3306/test", "test"}, + {"jdbc:tc:oracle:1.2.3:thin://@localhost:1521/test", "oracle", Optional.of("1.2.3"), "localhost:1521/test", "test"}, {"jdbc:tc:oracle:1.2.3:thin:@localhost:1521/test", "oracle", Optional.of("1.2.3"), "localhost:1521/test", "test"}, - {"jdbc:tc:oracle:thin:@localhost:1521/test", "oracle", Optional.empty(), "localhost:1521/test", "test"} + {"jdbc:tc:oracle:thin:@localhost:1521/test", "oracle", Optional.empty(), "localhost:1521/test", "test"}, + {"jdbc:tc:oracle:1.2.3:thin:@localhost:1521:test", "oracle", Optional.of("1.2.3"), "localhost:1521:test", "test"}, + {"jdbc:tc:oracle:1.2.3:thin://@localhost:1521:test", "oracle", Optional.of("1.2.3"), "localhost:1521:test", "test"}, + {"jdbc:tc:oracle:1.2.3-anything:thin://@localhost:1521:test", "oracle", Optional.of("1.2.3-anything"), "localhost:1521:test", "test"}, + {"jdbc:tc:oracle:thin:@localhost:1521:test", "oracle", Optional.empty(), "localhost:1521:test", "test"} }); } From d512ca59802c7154dc2d117ff80e2583fe4c1c8f Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 23 Sep 2021 07:02:42 -0400 Subject: [PATCH 1451/4969] Tidy up core's build file (#4207) * Tidy up core's build file * post-merge fixes * Extract shading config * fix modules * fix tests * fix merge conflicts, simplify shading.gradle * cleanup * Workaround BOM dependency * Use `resolvedConfiguration` --- build.gradle | 33 +---------------------- core/build.gradle | 30 +++++---------------- gradle/publishing.gradle | 37 ++++++++++++++----------- gradle/shading.gradle | 58 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 71 deletions(-) create mode 100644 gradle/shading.gradle diff --git a/build.gradle b/build.gradle index 723c429271d..aac0648ec06 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ subprojects { apply plugin: 'java-library' apply plugin: 'idea' apply plugin: 'io.franzbecker.gradle-lombok' - apply plugin: 'com.github.johnrengelman.shadow' + apply from: "$rootDir/gradle/shading.gradle" group = "org.testcontainers" @@ -101,37 +101,6 @@ subprojects { source = delombok.outputs } - shadowJar { - configurations = [] - archiveClassifier.set(null) - - doFirst { - // See https://github.com/johnrengelman/shadow/blob/5.0.0/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ConfigureShadowRelocation.groovy - Set packages = [] - // Always read from core's configurations - for (configuration in tasks.getByPath(":testcontainers:shadowJar").configurations) { - for (jar in configuration.files) { - def jf = new java.util.jar.JarFile(jar) - for (entry in jf.entries()) { - def name = entry.name - if (name.endsWith(".class")) { - def index = name.lastIndexOf('/') - if (index != -1) { - packages.add(name.substring(0, index)) - } - } - } - jf.close() - } - } - for (pkg in packages) { - pkg = pkg.replaceAll('/', '.') - - tasks.shadowJar.relocate(pkg, "org.testcontainers.shaded.${pkg}") - } - } - } - dependencies { testImplementation 'ch.qos.logback:logback-classic:1.2.3' } diff --git a/core/build.gradle b/core/build.gradle index 35cecd76ce8..fca331e9d3f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -8,16 +8,7 @@ sourceSets { idea.module.testSourceDirs += sourceSets.jarFileTest.allSource.srcDirs -configurations { - shaded - [api, compileOnly, testCompile]*.extendsFrom shaded -} - shadowJar { - configurations = [project.configurations.shaded] - - mergeServiceFiles() - [ 'META-INF/NOTICE', 'META-INF/NOTICE.txt', @@ -77,23 +68,16 @@ dependencies { shaded 'org.awaitility:awaitility:4.1.0' + api platform('com.github.docker-java:docker-java-bom:3.2.12') shaded platform('com.github.docker-java:docker-java-bom:3.2.12') api "com.github.docker-java:docker-java-api" - shaded ('com.github.docker-java:docker-java-core') { - exclude(group: 'com.github.docker-java', module: 'docker-java-api') - exclude(group: 'com.github.docker-java', module: 'docker-java-transport') - exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-annotations') - exclude(group: 'com.google.code.findbug') - exclude(group: 'org.slf4j') - exclude(group: 'org.apache.commons', module: 'commons-compress') - } + shaded 'com.github.docker-java:docker-java-core' - shaded ('com.github.docker-java:docker-java-transport-okhttp') { - exclude(group: 'com.github.docker-java', module: 'docker-java-core') - exclude(group: 'net.java.dev.jna') - exclude(group: 'org.slf4j') + shaded 'com.github.docker-java:docker-java-transport-okhttp', { + // TODO remove unused `net.java.dev.jna:jna-platform` from `docker-java-transport-okhttp` + exclude(group: 'net.java.dev.jna', module: 'jna-platform') } api 'com.github.docker-java:docker-java-transport-zerodep' @@ -102,9 +86,7 @@ dependencies { shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' - shaded 'org.zeroturnaround:zt-exec:1.12', { - exclude(group: 'org.slf4j') - } + shaded 'org.zeroturnaround:zt-exec:1.12' testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:3.7.0' diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index e6bf5d2acbd..ffeb3cb38d4 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -57,27 +57,34 @@ publishing { def dependenciesNode = rootNode.appendNode('dependencies') - def addDependency = { dependency, scope -> - dependenciesNode.appendNode('dependency').with { - appendNode('groupId', dependency.group) - appendNode('artifactId', dependency.name) - appendNode('version', dependency.version) - appendNode('scope', scope) + def addDependencies = { Configuration configuration, scope -> + for (dependency in configuration.resolvedConfiguration.firstLevelModuleDependencies) { + if (dependency.configuration.startsWith("platform-")) { + continue + } + dependenciesNode.appendNode('dependency').with { + if (!dependency.moduleGroup || !dependency.moduleName || !dependency.moduleVersion) { + throw new IllegalStateException("Wrong dependency: $dependency") + } + appendNode('groupId', dependency.moduleGroup) + appendNode('artifactId', dependency.moduleName) + appendNode('version', dependency.moduleVersion) + appendNode('scope', scope) - if (dependency instanceof ModuleDependency && !dependency.excludeRules.empty) { - def excludesNode = appendNode('exclusions') - for (rule in dependency.excludeRules) { - excludesNode.appendNode('exclusion').with { - appendNode('groupId', rule.group) - appendNode('artifactId', rule.module) + if (dependency instanceof ModuleDependency && !dependency.excludeRules.empty) { + def excludesNode = appendNode('exclusions') + for (rule in dependency.excludeRules) { + excludesNode.appendNode('exclusion').with { + appendNode('groupId', rule.group) + appendNode('artifactId', rule.module) + } } } } } } - - project.configurations.api.dependencies.each { addDependency(it, 'compile') } - project.configurations.provided.dependencies.each { addDependency(it, 'provided') } + addDependencies(project.configurations.api, 'compile') + addDependencies(project.configurations.provided, 'provided') } } } diff --git a/gradle/shading.gradle b/gradle/shading.gradle new file mode 100644 index 00000000000..909989caf84 --- /dev/null +++ b/gradle/shading.gradle @@ -0,0 +1,58 @@ +import java.util.jar.JarFile + +apply plugin: 'com.github.johnrengelman.shadow' + +configurations { + shaded + [apiElements, implementation, compileOnly, testCompile]*.extendsFrom shaded +} +configurations.api.canBeResolved = true + +shadowJar { + configurations = [project.configurations.shaded] + archiveClassifier.set(null) + + mergeServiceFiles() +} + +project.afterEvaluate { + Set apiDependencies = project.configurations.api.resolvedConfiguration.resolvedArtifacts*.moduleVersion*.id*.module + + // Exclude `api` dependencies, to prevent them being included into the final JAR + shadowJar.dependencies { + for (id in apiDependencies) { + exclude(dependency("${id.group}:${id.name}")) + } + } + + // Inherit dependencies' relocators + shadowJar.relocators = configurations.api.dependencies.withType(ProjectDependency).collectMany { + return it.dependencyProject.tasks.findByName("shadowJar")?.relocators ?: [] + } + + // See https://github.com/johnrengelman/shadow/blob/5.0.0/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ConfigureShadowRelocation.groovy + Set packages = [] + + for (artifact in project.configurations.shaded.resolvedConfiguration.resolvedArtifacts) { + if (apiDependencies.contains(artifact.moduleVersion.id.module)) { + continue + } + + try (def jf = new JarFile(artifact.file)) { + for (entry in jf.entries()) { + def name = entry.name + if (name.endsWith(".class")) { + def index = name.lastIndexOf('/') + if (index != -1) { + packages.add(name.substring(0, index)) + } + } + } + } + } + for (pkg in packages) { + pkg = pkg.replaceAll('/', '.') + + tasks.shadowJar.relocate(pkg, "org.testcontainers.shaded.${pkg}") + } +} From f178e91623d3648ba3b61ee440f5bfc6fd92646f Mon Sep 17 00:00:00 2001 From: Simon Schneider <10846939+raynigon@users.noreply.github.com> Date: Thu, 23 Sep 2021 13:11:23 +0200 Subject: [PATCH 1452/4969] Make TimescaleDB available with JDBC syntax (#3891) --- docs/modules/databases/jdbc.md | 4 ++ .../jdbc/AbstractJDBCDriverTest.java | 4 +- .../TimescaleDBContainerProvider.java | 39 +++++++++++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../containers/TimescaleDBContainerTest.java | 58 +++++++++++++++++++ .../TimescaleDBJDBCDriverTest.java | 22 +++++++ .../resources/somepath/init_timescaledb.sql | 13 +++++ 7 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java create mode 100644 modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java create mode 100644 modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java create mode 100644 modules/postgresql/src/test/resources/somepath/init_timescaledb.sql diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 7adaf2f5e70..d402b5983b4 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -39,6 +39,10 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database `jdbc:tc:postgis:9.6-2.5:///databasename` +#### Using TimescaleDB + +`jdbc:tc:timescaldb:2.1.0-pg13:///databasename` + #### Using Trino `jdbc:tc:trino:352://localhost/memory/default` diff --git a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java index 38ca2237567..580aad513e3 100644 --- a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java @@ -117,7 +117,9 @@ private void performTestForJDBCParamUsage(HikariDataSource dataSource) throws SQ String databaseQuery = "SELECT DATABASE()"; // Postgres does not have Database() as a function String databaseType = ConnectionUrl.newInstance(jdbcUrl).getDatabaseType(); - if (databaseType.equalsIgnoreCase("postgresql") || databaseType.equalsIgnoreCase("postgis")) { + if (databaseType.equalsIgnoreCase("postgresql") || + databaseType.equalsIgnoreCase("postgis") || + databaseType.equalsIgnoreCase("timescaledb")) { databaseQuery = "SELECT CURRENT_DATABASE()"; } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java new file mode 100644 index 00000000000..c9b81fccfe4 --- /dev/null +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java @@ -0,0 +1,39 @@ +package org.testcontainers.containers; + +import org.testcontainers.jdbc.ConnectionUrl; +import org.testcontainers.utility.DockerImageName; + +/** + * Factory for TimescaleDB containers, which are a special flavour of PostgreSQL. + * + * @see https://docs.timescale.com/latest/introduction + */ +public class TimescaleDBContainerProvider extends JdbcDatabaseContainerProvider { + + private static final String NAME = "timescaledb"; + private static final String DEFAULT_TAG = "2.1.0-pg11"; + private static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("timescale/timescaledb").asCompatibleSubstituteFor("postgres"); + public static final String USER_PARAM = "user"; + public static final String PASSWORD_PARAM = "password"; + + + @Override + public boolean supports(String databaseType) { + return databaseType.equals(NAME); + } + + @Override + public JdbcDatabaseContainer newInstance() { + return newInstance(DEFAULT_TAG); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new PostgreSQLContainer(DEFAULT_IMAGE.withTag(tag)); + } + + @Override + public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { + return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); + } +} diff --git a/modules/postgresql/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/postgresql/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider index 79b2f29340a..05df9054522 100644 --- a/modules/postgresql/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider +++ b/modules/postgresql/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -1,2 +1,3 @@ org.testcontainers.containers.PostgreSQLContainerProvider org.testcontainers.containers.PostgisContainerProvider +org.testcontainers.containers.TimescaleDBContainerProvider diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java new file mode 100644 index 00000000000..f3c73a4111b --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java @@ -0,0 +1,58 @@ +package org.testcontainers.containers; + +import org.junit.Test; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; + +public class TimescaleDBContainerTest extends AbstractContainerDatabaseTest { + + @Test + public void testSimple() throws SQLException { + try (JdbcDatabaseContainer postgres = new TimescaleDBContainerProvider().newInstance()) { + postgres.start(); + + ResultSet resultSet = performQuery(postgres, "SELECT 1"); + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } + + @Test + public void testCommandOverride() throws SQLException { + try (GenericContainer postgres = new TimescaleDBContainerProvider().newInstance().withCommand("postgres -c max_connections=42")) { + postgres.start(); + + ResultSet resultSet = performQuery((JdbcDatabaseContainer) postgres, "SELECT current_setting('max_connections')"); + String result = resultSet.getString(1); + assertEquals("max_connections should be overriden", "42", result); + } + } + + @Test + public void testUnsetCommand() throws SQLException { + try (GenericContainer postgres = new TimescaleDBContainerProvider().newInstance().withCommand("postgres -c max_connections=42").withCommand()) { + postgres.start(); + + ResultSet resultSet = performQuery((JdbcDatabaseContainer) postgres, "SELECT current_setting('max_connections')"); + String result = resultSet.getString(1); + assertNotEquals("max_connections should not be overriden", "42", result); + } + } + + @Test + public void testExplicitInitScript() throws SQLException { + try (JdbcDatabaseContainer postgres = new TimescaleDBContainerProvider().newInstance().withInitScript("somepath/init_timescaledb.sql")) { + postgres.start(); + + ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); + + String firstColumnValue = resultSet.getString(1); + assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + } + } +} diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java new file mode 100644 index 00000000000..8a6eaa3d04b --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java @@ -0,0 +1,22 @@ +package org.testcontainers.jdbc.timescaledb; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.EnumSet; + +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class TimescaleDBJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return asList( + new Object[][]{ + {"jdbc:tc:timescaledb://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + {"jdbc:tc:timescaledb:2.1.0-pg13://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, + }); + } +} diff --git a/modules/postgresql/src/test/resources/somepath/init_timescaledb.sql b/modules/postgresql/src/test/resources/somepath/init_timescaledb.sql new file mode 100644 index 00000000000..da11604cf10 --- /dev/null +++ b/modules/postgresql/src/test/resources/somepath/init_timescaledb.sql @@ -0,0 +1,13 @@ +-- Extend the database with TimescaleDB +CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE; + +CREATE TABLE bar +( + foo VARCHAR(255), + time TIMESTAMPTZ NOT NULL +); + +SELECT create_hypertable('bar', 'time'); + +INSERT INTO bar (time, foo) +VALUES (CURRENT_TIMESTAMP, 'hello world'); From 4dd08729a9ee0472cd45bb307631e728571cf4f8 Mon Sep 17 00:00:00 2001 From: PROgrm_JARvis Date: Thu, 23 Sep 2021 14:15:12 +0300 Subject: [PATCH 1453/4969] Fix dangling constructor reference in deprecation note (#4443) --- .../java/org/testcontainers/containers/PostgreSQLContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 6c16bb8fe61..2b905bd3d37 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -35,7 +35,7 @@ public class PostgreSQLContainer> extends private static final String QUERY_PARAM_SEPARATOR = "&"; /** - * @deprecated use {@link PostgreSQLContainer(DockerImageName)} instead + * @deprecated use {@link #PostgreSQLContainer(DockerImageName)} or {@link #PostgreSQLContainer(String)} instead */ @Deprecated public PostgreSQLContainer() { From b88d136762b77cb4ac4b1db98ab4e1ddc711b274 Mon Sep 17 00:00:00 2001 From: John Athanaselis Date: Thu, 23 Sep 2021 16:57:41 +0300 Subject: [PATCH 1454/4969] Randomize naming for createVolumeDirectory method (#4195) Also marks createVolumeDirectory method as deprecated Co-authored-by: Richard North --- .../java/org/testcontainers/containers/GenericContainer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 50e4b927617..fb82832675b 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -88,6 +88,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -647,8 +648,9 @@ protected Logger logger() { * @param temporary is the volume directory temporary? If true, the directory will be deleted on JVM shutdown. * @return path to the volume directory */ + @Deprecated protected Path createVolumeDirectory(boolean temporary) { - Path directory = new File(".tmp-volume-" + System.currentTimeMillis()).toPath(); + Path directory = new File(".tmp-volume-" + UUID.randomUUID()).toPath(); PathUtils.mkdirp(directory); if (temporary) Runtime.getRuntime().addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { From 8f312b4fb3f29c8d37cc55f3640693afb912523f Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Thu, 23 Sep 2021 16:00:25 +0200 Subject: [PATCH 1455/4969] Avoid clobbering already configured path (#2957) --- .../java/org/testcontainers/containers/GenericContainer.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index fb82832675b..6d9551b8d6e 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1284,6 +1284,9 @@ public SELF withWorkingDirectory(String workDir) { */ @Override public SELF withCopyFileToContainer(MountableFile mountableFile, String containerPath) { + if (copyToFileContainerPathMap.containsKey(mountableFile)) { + throw new IllegalStateException("Path already configured for copy: " + mountableFile); + } copyToFileContainerPathMap.put(mountableFile, containerPath); return self(); } From 29a438d84e31dd193bd36614f98b76b6a0f89b90 Mon Sep 17 00:00:00 2001 From: Kyle Aure Date: Mon, 27 Sep 2021 03:55:59 -0500 Subject: [PATCH 1456/4969] Modernize Oracle Container Logic (#4402) --- modules/oracle-xe/build.gradle | 2 + .../containers/OracleContainer.java | 87 ++++++++++-- .../containers/jdbc/OracleJDBCDriverTest.java | 4 - .../junit/oracle/SimpleOracleTest.java | 133 ++++++++++++++++-- 4 files changed, 203 insertions(+), 23 deletions(-) diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index 5a6040ac81f..38146d4dd01 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -5,4 +5,6 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'com.oracle.ojdbc:ojdbc8:19.3.0.0' + + compileOnly 'org.jetbrains:annotations:21.0.1' } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index ccd705f5af9..c833689e692 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -2,19 +2,24 @@ import com.google.common.collect.Sets; import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.Future; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.util.Collections.singleton; + public class OracleContainer extends JdbcDatabaseContainer { public static final String NAME = "oracle"; private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe"); - static final String DEFAULT_TAG = "18.4.0-slim"; static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); @@ -23,10 +28,24 @@ public class OracleContainer extends JdbcDatabaseContainer { private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240; private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 120; - private static final List ORACLE_SYSTEM_USERS = Arrays.asList("system", "sys"); - private String username = "test"; - private String password = "test"; + // Container defaults + static final String DEFAULT_DATABASE_NAME = "xepdb1"; + static final String DEFAULT_SID = "xe"; + static final String DEFAULT_SYSTEM_USER = "system"; + static final String DEFAULT_SYS_USER = "sys"; + + // Test container defaults + static final String APP_USER = "test"; + static final String APP_USER_PASSWORD = "test"; + + // Restricted user and database names + private static final List ORACLE_SYSTEM_USERS = Arrays.asList(DEFAULT_SYSTEM_USER, DEFAULT_SYS_USER); + + private String databaseName = DEFAULT_DATABASE_NAME; + private String username = APP_USER; + private String password = APP_USER_PASSWORD; + private boolean usingSid = false; /** * @deprecated use {@link OracleContainer(DockerImageName)} instead @@ -42,6 +61,7 @@ public OracleContainer(String dockerImageName) { public OracleContainer(final DockerImageName dockerImageName) { super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); preconfigure(); } @@ -51,14 +71,24 @@ public OracleContainer(Future dockerImageName) { } private void preconfigure() { - withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); + this.waitStrategy = new LogMessageWaitStrategy() + .withRegEx(".*DATABASE IS READY TO USE!.*\\s") + .withTimes(1) + .withStartupTimeout(Duration.of(DEFAULT_STARTUP_TIMEOUT_SECONDS, SECONDS)); + withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT); } + @Override + protected void waitUntilContainerStarted() { + getWaitStrategy().waitUntilReady(this); + } + + @NotNull @Override public Set getLivenessCheckPortNumbers() { - return Sets.newHashSet(ORACLE_PORT); + return singleton(getMappedPort(ORACLE_PORT)); } @Override @@ -68,12 +98,15 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return "jdbc:oracle:thin:" + getUsername() + "/" + getPassword() + "@" + getHost() + ":" + getOraclePort() + "/xepdb1"; + return isUsingSid() ? + "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + ":" + getSid() : + "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + "/" + getDatabaseName(); } @Override public String getUsername() { - return username; + // An application user is tied to the database, and therefore not authenticated to connect to SID. + return isUsingSid() ? DEFAULT_SYSTEM_USER : username; } @Override @@ -81,6 +114,15 @@ public String getPassword() { return password; } + @Override + public String getDatabaseName() { + return databaseName; + } + + protected boolean isUsingSid() { + return usingSid; + } + @Override public OracleContainer withUsername(String username) { if (StringUtils.isEmpty(username)) { @@ -102,14 +144,33 @@ public OracleContainer withPassword(String password) { return self(); } + @Override + public OracleContainer withDatabaseName(String databaseName) { + if (StringUtils.isEmpty(databaseName)) { + throw new IllegalArgumentException("Database name cannot be null or empty"); + } + + if (DEFAULT_DATABASE_NAME.equals(databaseName.toLowerCase())) { + throw new IllegalArgumentException("Database name cannot be set to " + DEFAULT_DATABASE_NAME); + } + + this.databaseName = databaseName; + return self(); + } + + public OracleContainer usingSid() { + this.usingSid = true; + return self(); + } + @Override public OracleContainer withUrlParam(String paramName, String paramValue) { - throw new UnsupportedOperationException("The OracleDb does not support this"); + throw new UnsupportedOperationException("The Oracle Database driver does not support this"); } @SuppressWarnings("SameReturnValue") public String getSid() { - return "xe"; + return DEFAULT_SID; } public Integer getOraclePort() { @@ -129,6 +190,12 @@ public String getTestQueryString() { @Override protected void configure() { withEnv("ORACLE_PASSWORD", password); + + // Only set ORACLE_DATABASE if different than the default. + if(databaseName != DEFAULT_DATABASE_NAME) { + withEnv("ORACLE_DATABASE", databaseName); + } + withEnv("APP_USER", username); withEnv("APP_USER_PASSWORD", password); } diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java index fbe5ce95a05..79dc35deb64 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java @@ -12,10 +12,6 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -/** - * @author gusohal - */ -@Ignore public class OracleJDBCDriverTest { @Test diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java index 7d026924442..2dd82c437a4 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java @@ -1,5 +1,8 @@ package org.testcontainers.junit.oracle; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import org.junit.Test; import org.testcontainers.containers.OracleContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -8,26 +11,138 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - public class SimpleOracleTest extends AbstractContainerDatabaseTest { public static final DockerImageName ORACLE_DOCKER_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe:18.4.0-slim"); + private void runTest(OracleContainer container, String databaseName, String username, String password) throws SQLException { + //Test config was honored + assertEquals(databaseName, container.getDatabaseName()); + assertEquals(username, container.getUsername()); + assertEquals(password, container.getPassword()); + + //Test we can get a connection + container.start(); + ResultSet resultSet = performQuery(container, "SELECT 1 FROM dual"); + int resultSetInt = resultSet.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + + @Test + public void testDefaultSettings() throws SQLException { + try ( + OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME); + ) { + runTest(oracle, "xepdb1", "test", "test"); + + // Match against the last '/' + String urlSuffix = oracle.getJdbcUrl().split("(\\/)(?!.*\\/)", 2)[1]; + assertEquals("xepdb1", urlSuffix); + } + } + + @Test + public void testPluggableDatabase() throws SQLException { + try ( + OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) + .withDatabaseName("testDB") + ) { + runTest(oracle, "testDB", "test", "test"); + } + } + + @Test + public void testPluggableDatabaseAndCustomUser() throws SQLException { + try ( + OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) + .withDatabaseName("testDB") + .withUsername("testUser") + .withPassword("testPassword") + ) { + runTest(oracle, "testDB", "testUser", "testPassword"); + } + } + @Test - public void testSimple() throws SQLException { + public void testCustomUser() throws SQLException { + try ( + OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) + .withUsername("testUser") + .withPassword("testPassword") + ) { + runTest(oracle, "xepdb1", "testUser", "testPassword"); + } + } + @Test + public void testSID() throws SQLException { try ( OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) - .withUsername("baz") - .withPassword("bar") + .usingSid(); ) { - oracle.start(); - ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual"); + runTest(oracle, "xepdb1", "system", "test"); + + // Match against the last ':' + String urlSuffix = oracle.getJdbcUrl().split("(\\:)(?!.*\\:)", 2)[1]; + assertEquals("xe", urlSuffix); + } + } + + @Test + public void testSIDAndCustomPassword() throws SQLException { + try ( + OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) + .usingSid() + .withPassword("testPassword"); + ) { + runTest(oracle, "xepdb1", "system", "testPassword"); + } + } + + @Test + public void testErrorPaths() throws SQLException { + try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)) { + try { + oracle.withDatabaseName("XEPDB1"); + fail("Should not have been able to set database name to xepdb1."); + } catch (IllegalArgumentException e) { + //expected + } + + try { + oracle.withDatabaseName(""); + fail("Should not have been able to set database name to nothing."); + } catch (IllegalArgumentException e) { + //expected + } + + try { + oracle.withUsername("SYSTEM"); + fail("Should not have been able to set username to system."); + } catch (IllegalArgumentException e) { + //expected + } + + try { + oracle.withUsername("SYS"); + fail("Should not have been able to set username to sys."); + } catch (IllegalArgumentException e) { + //expected + } - int resultSetInt = resultSet.getInt(1); + try { + oracle.withUsername(""); + fail("Should not have been able to set username to nothing."); + } catch (IllegalArgumentException e) { + //expected + } - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + try { + oracle.withPassword(""); + fail("Should not have been able to set password to nothing."); + } catch (IllegalArgumentException e) { + //expected + } } } } From 532c0b711bef4443180ae3a41da9d1d6dfb825d1 Mon Sep 17 00:00:00 2001 From: Bennet Schulz Date: Tue, 28 Sep 2021 12:00:28 +0200 Subject: [PATCH 1457/4969] Add togglz as testcontainers user (#4484) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index af5bb4edcdb..65d417db2af 100644 --- a/docs/index.md +++ b/docs/index.md @@ -175,7 +175,7 @@ A huge thank you to our sponsors: ([query](https://github.com/search?l=Maven+POM&q=org%3Ajenkinsci+testcontainers&type=Code)). * [Elastic](https://www.elastic.co) - Integration testing of the Java APM agent * [Alkira](https://www.alkira.com/) - Testing of multiple micro-services using Kafka, PostgreSQL, Apache Zookeeper, Etcd and so on. - +* [Togglz](https://www.togglz.org/) - Feature Flags for the Java platform ## License From dd9372515faaea7b8e5ab914fa8010d7afa29024 Mon Sep 17 00:00:00 2001 From: pioorg Date: Mon, 4 Oct 2021 11:51:18 +0200 Subject: [PATCH 1458/4969] Switch from AdoptOpenJDK to Temurin and latest JDK 8. (#4537) * Switched from AdoptOpenJDK to Temurin and JDK version 8.0.302. --- .github/workflows/ci-examples.yml | 8 ++++---- .github/workflows/ci.yml | 8 ++++---- .github/workflows/release.yml | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 88587a6ab61..3fbdea447b9 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -17,8 +17,8 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.3.0 with: - java-version: '8.0.292+10' - distribution: adopt-hotspot + java-version: '8.0.302' + distribution: temurin - name: Cache Gradle Home files uses: actions/cache@v2.1.6 continue-on-error: true @@ -45,8 +45,8 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.3.0 with: - java-version: '8.0.292+10' - distribution: adopt-hotspot + java-version: '8.0.302' + distribution: temurin - name: Cache Gradle Home files uses: actions/cache@v2.1.6 continue-on-error: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6ae55e16b4..c3a85500ff1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,8 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.3.0 with: - java-version: '8.0.292+10' - distribution: adopt-hotspot + java-version: '8.0.302' + distribution: temurin - name: Cache Gradle Home files uses: actions/cache@v2.1.6 with: @@ -51,8 +51,8 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.3.0 with: - java-version: '8.0.292+10' - distribution: adopt-hotspot + java-version: '8.0.302' + distribution: temurin - name: Cache Gradle Home files uses: actions/cache@v2.1.6 continue-on-error: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 73b3b2152c9..7b9d480ec37 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,8 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2.3.0 with: - java-version: '1.8' + java-version: '8.0.302' + distribution: temurin - name: Clear existing docker image cache run: docker image prune -af From cad5cda62859c408962caa1ed4b3fdd756979922 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Oct 2021 09:52:47 +0000 Subject: [PATCH 1459/4969] Bump actions/setup-java from 2.3.0 to 2.3.1 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2.3.0 to 2.3.1. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2.3.0...v2.3.1) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 3fbdea447b9..a1f81f49bef 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -15,7 +15,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.0 + - uses: actions/setup-java@v2.3.1 with: java-version: '8.0.302' distribution: temurin @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.0 + - uses: actions/setup-java@v2.3.1 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3a85500ff1..2cbfc92b372 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.0 + - uses: actions/setup-java@v2.3.1 with: java-version: '8.0.302' distribution: temurin @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.0 + - uses: actions/setup-java@v2.3.1 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b9d480ec37..4e1e9d7c5a1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.0 + - uses: actions/setup-java@v2.3.1 with: java-version: '8.0.302' distribution: temurin From d44e61637b5c9834d9abbfa1c614ebff884fc470 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 4 Oct 2021 12:34:46 +0100 Subject: [PATCH 1460/4969] Prevent Compose image pre-fetching from pulling all tags when tag is absent (#4538) --- .../containers/DockerComposeFiles.java | 24 +++++++++---------- .../containers/DockerComposeFilesTest.java | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java b/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java index 15d035e3673..76754df5118 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java @@ -1,43 +1,43 @@ package org.testcontainers.containers; +import org.testcontainers.utility.DockerImageName; + import java.io.File; +import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; public class DockerComposeFiles { - private List parsedComposeFiles; + private final List parsedComposeFiles; public DockerComposeFiles(List composeFiles) { this.parsedComposeFiles = composeFiles.stream().map(ParsedDockerComposeFile::new).collect(Collectors.toList()); } public Set getDependencyImages() { - Map> mergedServiceNameToImageNames = mergeServiceDependencyImageNames(); return getImageNames(mergedServiceNameToImageNames); } private Map> mergeServiceDependencyImageNames() { - Map> mergedServiceNameToImageNames = new HashMap(); + Map> mergedServiceNameToImageNames = new HashMap<>(); for (ParsedDockerComposeFile parsedComposeFile : parsedComposeFiles) { - for (Entry> entry : parsedComposeFile.getServiceNameToImageNames().entrySet()) { - mergedServiceNameToImageNames.put(entry.getKey(), entry.getValue()); - } + mergedServiceNameToImageNames.putAll(parsedComposeFile.getServiceNameToImageNames()); } return mergedServiceNameToImageNames; } private Set getImageNames(Map> serviceToImageNames) { - Set imageNames = new HashSet<>(); - serviceToImageNames.values().stream().forEach(imageNames::addAll); - return imageNames; + return serviceToImageNames.values().stream() + .flatMap(Collection::stream) + // Pass through DockerImageName to convert image names to canonical form (e.g. making implicit latest tag explicit) + .map(DockerImageName::parse) + .map(DockerImageName::asCanonicalNameString) + .collect(Collectors.toSet()); } - } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java index 81586c8290b..c47db0c4b66 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java @@ -11,7 +11,7 @@ public class DockerComposeFilesTest { public void shouldGetDependencyImages() { DockerComposeFiles dockerComposeFiles = new DockerComposeFiles(Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"))); Assertions.assertThat(dockerComposeFiles.getDependencyImages()) - .containsExactlyInAnyOrder("postgres", "redis", "mysql"); + .containsExactlyInAnyOrder("postgres:latest", "redis:latest", "mysql:latest"); } @Test @@ -20,6 +20,6 @@ public void shouldGetDependencyImagesWhenOverriding() { Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-overriding-a.yml"), new File("src/test/resources/docker-compose-imagename-overriding-b.yml"))); Assertions.assertThat(dockerComposeFiles.getDependencyImages()) - .containsExactlyInAnyOrder("alpine:3.14", "redis:b", "mysql:b", "aservice"); + .containsExactlyInAnyOrder("alpine:3.14", "redis:b", "mysql:b", "aservice:latest"); } } From 3a5793d2543568ced9a6202fc2c8db06c73e1bdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:23:56 +0000 Subject: [PATCH 1461/4969] Bump okhttp from 4.9.1 to 4.9.2 in /examples Bumps [okhttp](https://github.com/square/okhttp) from 4.9.1 to 4.9.2. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.9.1...parent-4.9.2) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index ff1b2995e02..604f04594c0 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'com.squareup.okhttp3:okhttp:4.9.1' + implementation 'com.squareup.okhttp3:okhttp:4.9.2' implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.2.23' testImplementation 'ch.qos.logback:logback-classic:1.2.5' From 472e7c8b808779cf14362ce4c65425b7bb0cf467 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:23:58 +0000 Subject: [PATCH 1462/4969] Bump junit-jupiter-api from 5.7.2 to 5.8.1 in /modules/junit-jupiter Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.7.2 to 5.8.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.2...r5.8.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 03abb675f3b..798d295c1f0 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { api project(':testcontainers') - api 'org.junit.jupiter:junit-jupiter-api:5.7.2' + api 'org.junit.jupiter:junit-jupiter-api:5.8.1' testImplementation project(':mysql') testImplementation project(':postgresql') From bbe2b6e854db1698531e30511137e9faa9161d75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:04 +0000 Subject: [PATCH 1463/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.5.30 to 1.5.31. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 6096fcb37b4..fe0ed6553c3 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.5.4" id("org.jetbrains.kotlin.jvm") version "1.5.30" - id("org.jetbrains.kotlin.plugin.spring") version "1.5.30" + id("org.jetbrains.kotlin.plugin.spring") version "1.5.31" } apply plugin: 'io.spring.dependency-management' From d2e2ef25d9a6ebf3dba17d36d9f39d7f012a6ea1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:08 +0000 Subject: [PATCH 1464/4969] Bump postgresql from 42.2.23 to 42.2.24 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.23 to 42.2.24. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.23...REL42.2.24) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 03abb675f3b..f4f9bdd2570 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' - testRuntimeOnly 'org.postgresql:postgresql:42.2.23' + testRuntimeOnly 'org.postgresql:postgresql:42.2.24' testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } From f5bdb1bc4c5838e5448586051ff1aed4db02111d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:09 +0000 Subject: [PATCH 1465/4969] Bump org.springframework.boot from 2.5.4 to 2.5.5 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.5.4 to 2.5.5. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.5.4...v2.5.5) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 49893845273..48f9ed91b17 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.4' + id 'org.springframework.boot' version '2.5.5' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 6096fcb37b4..c48fcb9ad65 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.5.4" + id("org.springframework.boot") version "2.5.5" id("org.jetbrains.kotlin.jvm") version "1.5.30" id("org.jetbrains.kotlin.plugin.spring") version "1.5.30" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 3f93d3c153c..20ec4efd463 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.4' + id 'org.springframework.boot' version '2.5.5' } apply plugin: 'io.spring.dependency-management' From e44062ccaa4841deb511fd8b2f2217f7d7b481cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:10 +0000 Subject: [PATCH 1466/4969] Bump postgresql from 42.2.23 to 42.2.24 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.23 to 42.2.24. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.23...REL42.2.24) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index f510836c4b5..3fc86d7877b 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:5.0.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.2.23' + testRuntimeOnly 'org.postgresql:postgresql:42.2.24' testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' testCompileClasspath 'org.jetbrains:annotations:22.0.0' From cb0d8eca5cfa9330a7054a7951805b026128b7e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:16 +0000 Subject: [PATCH 1467/4969] Bump r2dbc-mariadb from 1.0.2 to 1.0.3 in /modules/mariadb Bumps [r2dbc-mariadb](https://github.com/mariadb-corporation/mariadb-connector-r2dbc) from 1.0.2 to 1.0.3. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/commits) --- updated-dependencies: - dependency-name: org.mariadb:r2dbc-mariadb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 037573f6143..e24fe293ff1 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -7,7 +7,7 @@ dependencies { api project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'org.mariadb:r2dbc-mariadb:1.0.2' + compileOnly 'org.mariadb:r2dbc-mariadb:1.0.3' testImplementation project(':jdbc-test') testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4' From a1269586b1bfc5c3a68344950bafd7e5bfa3521b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:18 +0000 Subject: [PATCH 1468/4969] Bump solr-solrj from 8.9.0 to 8.10.0 in /examples Bumps solr-solrj from 8.9.0 to 8.10.0. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index d416c4d8c45..373ece1df60 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.16" - implementation 'org.apache.solr:solr-solrj:8.9.0' + implementation 'org.apache.solr:solr-solrj:8.10.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From 6c45f2ef98720991e4decd6bec16c21c14b3c67e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:20 +0000 Subject: [PATCH 1469/4969] Bump transport from 7.14.1 to 7.15.0 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.14.1 to 7.15.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.14.1...v7.15.0) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 183b2428ba8..c70fd363f55 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.14.1" - testImplementation "org.elasticsearch.client:transport:7.14.1" + testImplementation "org.elasticsearch.client:transport:7.15.0" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 6ca83c0cb99784a7e636d093fd22ce2c91a4be63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:23 +0000 Subject: [PATCH 1470/4969] Bump postgresql from 42.2.23 to 42.2.24 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.23 to 42.2.24. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.23...REL42.2.24) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 1842a0e7dd7..5c25e6243ef 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.2.23' + testImplementation 'org.postgresql:postgresql:42.2.24' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' From 8bfe5a61705eae285e948f740f8ef33b5bd6190f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:24:27 +0000 Subject: [PATCH 1471/4969] Bump aws-java-sdk-s3 from 1.12.62 to 1.12.80 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.62 to 1.12.80. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.62...1.12.80) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 1ccc305595d..a4934425027 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.62' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.80' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.62' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' testImplementation 'software.amazon.awssdk:s3:2.17.34' From abf18468c2b3c8ec395f07fe91cd3afd449e28d2 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 5 Oct 2021 16:10:41 +0200 Subject: [PATCH 1472/4969] Give EnvironmentAndSystemPropertyClientProviderStrategy the highest priority (#4472) --- .../DockerClientProviderStrategy.java | 245 ++++++++++-------- 1 file changed, 133 insertions(+), 112 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 52700df22f3..b595ddba6ca 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -28,10 +28,12 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -113,120 +115,139 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List configurationFailures = new ArrayList<>(); + List allStrategies = new ArrayList<>(); + + // The environment has the highest priority + allStrategies.add(new EnvironmentAndSystemPropertyClientProviderStrategy()); + + // Next strategy to try out is the one configured using the Testcontainers configuration mechanism + loadConfiguredStrategy().ifPresent(allStrategies::add); + + // Finally, add all other strategies ordered by their internal priority + strategies + .stream() + .sorted(Comparator.comparing(DockerClientProviderStrategy::getPriority).reversed()) + .collect(Collectors.toCollection(() -> allStrategies)); + + + Predicate distinctStrategyClassPredicate = new Predicate() { + final Set> classes = new HashSet<>(); + + @Override + public boolean test(DockerClientProviderStrategy dockerClientProviderStrategy) { + return classes.add(dockerClientProviderStrategy.getClass()); + } + }; + + return allStrategies + .stream() + .filter(distinctStrategyClassPredicate) + .filter(DockerClientProviderStrategy::isApplicable) + .filter(strategy -> tryOutStrategy(configurationFailures, strategy)) + .findFirst() + .orElseThrow(() -> { + log.error("Could not find a valid Docker environment. Please check configuration. Attempted configurations were:"); + for (String failureMessage : configurationFailures) { + log.error(" " + failureMessage); + } + log.error("As no valid configuration was found, execution cannot continue"); - String dockerClientStrategyClassName = TestcontainersConfiguration.getInstance().getDockerClientStrategyClassName(); - return Stream - .concat( - Stream - .of(dockerClientStrategyClassName) - .filter(Objects::nonNull) - .flatMap(it -> { - try { - Class strategyClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(it); - return Stream.of(strategyClass.newInstance()); - } catch (ClassNotFoundException e) { - log.warn("Can't instantiate a strategy from {} (ClassNotFoundException). " + - "This probably means that cached configuration refers to a client provider " + - "class that is not available in this version of Testcontainers. Other " + - "strategies will be tried instead.", it); - return Stream.empty(); - } catch (InstantiationException | IllegalAccessException e) { - log.warn("Can't instantiate a strategy from {}", it, e); - return Stream.empty(); - } - }) - // Ignore persisted strategy if it's not persistable anymore - .filter(DockerClientProviderStrategy::isPersistable) - .peek(strategy -> log.info("Loaded {} from ~/.testcontainers.properties, will try it first", strategy.getClass().getName())), - strategies - .stream() - .sorted(Comparator.comparing(DockerClientProviderStrategy::getPriority).reversed()) - ) - .filter(new Predicate() { - - final Set> classes = new HashSet<>(); - - @Override - public boolean test(DockerClientProviderStrategy dockerClientProviderStrategy) { - return classes.add(dockerClientProviderStrategy.getClass()); - } - }) - .filter(DockerClientProviderStrategy::isApplicable) - .flatMap(strategy -> { - try { - DockerClient dockerClient = strategy.getDockerClient(); - - Info info; - try { - info = Unreliables.retryUntilSuccess(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS, () -> { - return strategy.PING_RATE_LIMITER.getWhenReady(() -> { - log.debug("Pinging docker daemon..."); - return dockerClient.infoCmd().exec(); - }); - }); - } catch (TimeoutException e) { - IOUtils.closeQuietly(dockerClient); - throw e; - } - log.info("Found Docker environment with {}", strategy.getDescription()); - log.debug( - "Transport type: '{}', Docker host: '{}'", - TestcontainersConfiguration.getInstance().getTransportType(), - strategy.getTransportConfig().getDockerHost() - ); - - log.debug("Checking Docker OS type for {}", strategy.getDescription()); - String osType = info.getOsType(); - if (StringUtils.isBlank(osType)) { - log.warn("Could not determine Docker OS type"); - } else if (!osType.equals("linux")) { - log.warn("{} is currently not supported", osType); - throw new InvalidConfigurationException(osType + " containers are currently not supported"); - } - - if (strategy.isPersistable()) { - TestcontainersConfiguration.getInstance().updateUserConfig("docker.client.strategy", strategy.getClass().getName()); - } - - return Stream.of(strategy); - } catch (Exception | ExceptionInInitializerError | NoClassDefFoundError e) { - @Nullable String throwableMessage = e.getMessage(); - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - Throwable rootCause = Throwables.getRootCause(e); - @Nullable String rootCauseMessage = rootCause.getMessage(); - - String failureDescription; - if (throwableMessage != null && throwableMessage.equals(rootCauseMessage)) { - failureDescription = String.format("%s: failed with exception %s (%s)", - strategy.getClass().getSimpleName(), - e.getClass().getSimpleName(), - throwableMessage); - } else { - failureDescription = String.format("%s: failed with exception %s (%s). Root cause %s (%s)", - strategy.getClass().getSimpleName(), - e.getClass().getSimpleName(), - throwableMessage, - rootCause.getClass().getSimpleName(), - rootCauseMessage - ); - } - configurationFailures.add(failureDescription); - - log.debug(failureDescription); - return Stream.empty(); - } - }) - .findAny() - .orElseThrow(() -> { - log.error("Could not find a valid Docker environment. Please check configuration. Attempted configurations were:"); - for (String failureMessage : configurationFailures) { - log.error(" " + failureMessage); - } - log.error("As no valid configuration was found, execution cannot continue"); - - FAIL_FAST_ALWAYS.set(true); - return new IllegalStateException("Could not find a valid Docker environment. Please see logs and check configuration"); + FAIL_FAST_ALWAYS.set(true); + return new IllegalStateException("Could not find a valid Docker environment. Please see logs and check configuration"); + }); + } + + private static boolean tryOutStrategy(List configurationFailures, DockerClientProviderStrategy strategy) { + try { + log.debug("Trying out strategy: {}", strategy.getClass().getSimpleName()); + DockerClient dockerClient = strategy.getDockerClient(); + + Info info; + try { + info = Unreliables.retryUntilSuccess(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS, () -> { + return strategy.PING_RATE_LIMITER.getWhenReady(() -> { + log.debug("Pinging docker daemon..."); + return dockerClient.infoCmd().exec(); + }); }); + } catch (TimeoutException e) { + IOUtils.closeQuietly(dockerClient); + throw e; + } + log.info("Found Docker environment with {}", strategy.getDescription()); + log.debug( + "Transport type: '{}', Docker host: '{}'", + TestcontainersConfiguration.getInstance().getTransportType(), + strategy.getTransportConfig().getDockerHost() + ); + + log.debug("Checking Docker OS type for {}", strategy.getDescription()); + String osType = info.getOsType(); + if (StringUtils.isBlank(osType)) { + log.warn("Could not determine Docker OS type"); + } else if (!osType.equals("linux")) { + log.warn("{} is currently not supported", osType); + throw new InvalidConfigurationException(osType + " containers are currently not supported"); + } + + if (strategy.isPersistable()) { + TestcontainersConfiguration.getInstance().updateUserConfig("docker.client.strategy", strategy.getClass().getName()); + } + + return true; + } catch (Exception | ExceptionInInitializerError | NoClassDefFoundError e) { + @Nullable String throwableMessage = e.getMessage(); + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") + Throwable rootCause = Throwables.getRootCause(e); + @Nullable String rootCauseMessage = rootCause.getMessage(); + + String failureDescription; + if (throwableMessage != null && throwableMessage.equals(rootCauseMessage)) { + failureDescription = String.format("%s: failed with exception %s (%s)", + strategy.getClass().getSimpleName(), + e.getClass().getSimpleName(), + throwableMessage); + } else { + failureDescription = String.format("%s: failed with exception %s (%s). Root cause %s (%s)", + strategy.getClass().getSimpleName(), + e.getClass().getSimpleName(), + throwableMessage, + rootCause.getClass().getSimpleName(), + rootCauseMessage + ); + } + configurationFailures.add(failureDescription); + + log.debug(failureDescription); + return false; + } + } + + private static Optional loadConfiguredStrategy() { + String configuredDockerClientStrategyClassName = TestcontainersConfiguration.getInstance().getDockerClientStrategyClassName(); + + return Stream + .of(configuredDockerClientStrategyClassName) + .filter(Objects::nonNull) + .flatMap(it -> { + try { + Class strategyClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(it); + return Stream.of(strategyClass.newInstance()); + } catch (ClassNotFoundException e) { + log.warn("Can't instantiate a strategy from {} (ClassNotFoundException). " + + "This probably means that cached configuration refers to a client provider " + + "class that is not available in this version of Testcontainers. Other " + + "strategies will be tried instead.", it); + return Stream.empty(); + } catch (InstantiationException | IllegalAccessException e) { + log.warn("Can't instantiate a strategy from {}", it, e); + return Stream.empty(); + } + }) + // Ignore persisted strategy if it's not persistable anymore + .filter(DockerClientProviderStrategy::isPersistable) + .peek(strategy -> log.info("Loaded {} from ~/.testcontainers.properties, will try it first", strategy.getClass().getName())) + .findFirst(); } public static DockerClient getClientForConfig(TransportConfig transportConfig) { From afc71788fa21828f0ec8fabdc81600696456dc7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 18:04:42 +0000 Subject: [PATCH 1473/4969] Bump junit-jupiter-engine from 5.7.2 to 5.8.1 in /modules/junit-jupiter Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.7.2 to 5.8.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.2...r5.8.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 03abb675f3b..20b2179f2d6 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntimeOnly 'org.postgresql:postgresql:42.2.23' testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' } test { From 56876dea783cf45db48f5e86c059ea8bf36386d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 18:09:41 +0000 Subject: [PATCH 1474/4969] Bump tomcat-jdbc from 10.0.10 to 10.0.12 in /modules/jdbc Bumps tomcat-jdbc from 10.0.10 to 10.0.12. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index b3f53e19333..ccf272554f7 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:22.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.10' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.12' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 3ffd00e635b5628bce953e81bc0b2933bf900404 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 18:15:10 +0000 Subject: [PATCH 1475/4969] Bump s3 from 2.17.34 to 2.17.52 in /modules/localstack Bumps s3 from 2.17.34 to 2.17.52. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 1ccc305595d..e633fbbe05d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.37' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.62' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' - testImplementation 'software.amazon.awssdk:s3:2.17.34' + testImplementation 'software.amazon.awssdk:s3:2.17.52' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 33ee416fb6d25ff2517f3c018ddafd24d6c5dbee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 18:20:05 +0000 Subject: [PATCH 1476/4969] Bump annotations from 21.0.1 to 22.0.0 in /modules/oracle-xe Bumps [annotations](https://github.com/JetBrains/java-annotations) from 21.0.1 to 22.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/21.0.1...22.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/oracle-xe/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index 38146d4dd01..5c18b63bb9d 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -6,5 +6,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'com.oracle.ojdbc:ojdbc8:19.3.0.0' - compileOnly 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:22.0.0' } From 5174d179f115c842acaa5323bd6a002ce534a494 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 18:51:26 +0000 Subject: [PATCH 1477/4969] Bump r2dbc-mssql in /modules/mssqlserver Bumps [r2dbc-mssql](https://github.com/r2dbc/r2dbc-mssql) from 0.8.6.RELEASE to 0.8.7.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-mssql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-mssql/blob/v0.8.7.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-mssql/compare/v0.8.6.RELEASE...v0.8.7.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-mssql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index cd797a9807f..51e5bba3315 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -7,13 +7,13 @@ dependencies { api project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-mssql:0.8.6.RELEASE' + compileOnly 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' testImplementation project(':jdbc-test') testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre8' testImplementation project(':r2dbc') - testImplementation 'io.r2dbc:r2dbc-mssql:0.8.5.RELEASE' + testImplementation 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' // MSSQL's wait strategy requires the JDBC driver testImplementation testFixtures(project(':r2dbc')) From dace7e4d750552bb3d57036b579318045e203931 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 7 Oct 2021 12:15:23 +0100 Subject: [PATCH 1478/4969] Fix flaky kafka cluster example (#4549) Co-authored-by: Kevin Wittek Co-authored-by: Sergei Egorov --- examples/kafka-cluster/build.gradle | 2 +- .../kafkacluster/KafkaContainerCluster.java | 8 +++++--- .../kafkacluster/KafkaContainerClusterTest.java | 2 +- .../src/test/resources/logback-test.xml | 14 ++++++++++++++ .../testcontainers/containers/KafkaContainer.java | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 examples/kafka-cluster/src/test/resources/logback-test.xml diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 2a4650930a4..8f23284a48e 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:2.8.0' testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'org.slf4j:slf4j-simple:1.7.32' + testImplementation 'ch.qos.logback:logback-classic:1.2.5' } diff --git a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java index fd5b1a0a0b6..398488fe3f9 100644 --- a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java +++ b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java @@ -10,6 +10,7 @@ import org.testcontainers.containers.KafkaContainer; import org.testcontainers.utility.DockerImageName; +import java.time.Duration; import java.util.Collection; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -56,7 +57,8 @@ public KafkaContainerCluster(String confluentPlatformVersion, int brokersNum, in .withEnv("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR", internalTopicsRf + "") .withEnv("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS", internalTopicsRf + "") .withEnv("KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR", internalTopicsRf + "") - .withEnv("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR", internalTopicsRf + ""); + .withEnv("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR", internalTopicsRf + "") + .withStartupTimeout(Duration.ofMinutes(1)); }) .collect(Collectors.toList()); } @@ -81,8 +83,8 @@ private Stream> allContainers() { @Override @SneakyThrows public void start() { - Stream startables = this.brokers.stream().map(Startable.class::cast); - Startables.deepStart(startables).get(60, SECONDS); + // sequential start to avoid resource contention on CI systems with weaker hardware + brokers.forEach(GenericContainer::start); Unreliables.retryUntilTrue(30, TimeUnit.SECONDS, () -> { Container.ExecResult result = this.zookeeper.execInContainer( diff --git a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java index 0756b24d58a..a431c14bba3 100644 --- a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java +++ b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java @@ -30,7 +30,7 @@ public class KafkaContainerClusterTest { @Test public void testKafkaContainerCluster() throws Exception { try ( - KafkaContainerCluster cluster = new KafkaContainerCluster("5.2.1", 3, 2) + KafkaContainerCluster cluster = new KafkaContainerCluster("6.2.1", 3, 2) ) { cluster.start(); String bootstrapServers = cluster.getBootstrapServers(); diff --git a/examples/kafka-cluster/src/test/resources/logback-test.xml b/examples/kafka-cluster/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..be4ebaed2c8 --- /dev/null +++ b/examples/kafka-cluster/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index f62ca23eb57..8b1128efef0 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -118,7 +118,7 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { "advertised.listeners=[" + String.join(",", getBootstrapServers(), brokerAdvertisedListener) + "]" ); if (result.getExitCode() != 0) { - throw new IllegalStateException(result.getStderr()); + throw new IllegalStateException(result.toString()); } } From ce15717313b38a584951017e04ca791ed63bc2c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:09 +0000 Subject: [PATCH 1479/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /modules/jdbc Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index b3f53e19333..977827488ce 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -11,5 +11,5 @@ dependencies { testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' } From 0900fcb7098293a4dfcc491c81b1ace6358e7ad5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:13 +0000 Subject: [PATCH 1480/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /core Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index fca331e9d3f..e5a36114afb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -100,7 +100,7 @@ dependencies { testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' testImplementation project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" From b77733d69a271a2a5d741a2f5cf9c19e5f6e748f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:25 +0000 Subject: [PATCH 1481/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /modules/neo4j Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 08eda371597..2c25d148418 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { api project(":testcontainers") testImplementation "org.neo4j.driver:neo4j-java-driver:1.7.5" - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' } From a4feea019dfc658680efa8ffd60d58e63608eebd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:30 +0000 Subject: [PATCH 1482/4969] Bump guava from 30.1.1-jre to 31.0.1-jre in /modules/jdbc-test Bumps [guava](https://github.com/google/guava) from 30.1.1-jre to 31.0.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 8145855684f..f24b9bd6df2 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -2,7 +2,7 @@ dependencies { api project(':jdbc') api project(':test-support') - api 'com.google.guava:guava:30.1.1-jre' + api 'com.google.guava:guava:31.0.1-jre' api 'org.apache.commons:commons-lang3:3.12.0' api 'com.zaxxer:HikariCP-java6:2.3.13' api 'commons-dbutils:commons-dbutils:1.7' From 06db7b6931ff0086808a80598344824c91624117 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:31 +0000 Subject: [PATCH 1483/4969] Bump kafka-clients from 2.8.0 to 3.0.0 in /modules/kafka Bumps kafka-clients from 2.8.0 to 3.0.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index f7e9acda9a0..63f751665b0 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -12,7 +12,7 @@ tasks.japicmp { dependencies { api project(':testcontainers') - testImplementation 'org.apache.kafka:kafka-clients:2.8.0' + testImplementation 'org.apache.kafka:kafka-clients:3.0.0' testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'com.google.guava:guava:23.0' } From 896f2200ebddaf0f625b6c7a3d8b0dcf771659fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:32 +0000 Subject: [PATCH 1484/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /modules/pulsar Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 478c47fff29..d886be91591 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' - testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.20.2' + testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.21.0' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' } From 3ac377d2bcd61cd375f4ead4bde4e0a487f3673b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:35 +0000 Subject: [PATCH 1485/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /modules/junit-jupiter Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 03abb675f3b..e99ccf32061 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testImplementation ('org.mockito:mockito-core:3.12.4') { exclude(module: 'hamcrest-core') } - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' testRuntimeOnly 'org.postgresql:postgresql:42.2.23' From 97bae71b6903b2c2ffd49d7a08c6f7e3ead72b9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:48 +0000 Subject: [PATCH 1486/4969] Bump kafka-clients from 2.8.0 to 3.0.0 in /examples Bumps kafka-clients from 2.8.0 to 3.0.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 8f23284a48e..956292df2f8 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompileOnly "org.projectlombok:lombok:1.18.20" testAnnotationProcessor "org.projectlombok:lombok:1.18.10" testImplementation 'org.testcontainers:kafka' - testImplementation 'org.apache.kafka:kafka-clients:2.8.0' + testImplementation 'org.apache.kafka:kafka-clients:3.0.0' testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.5' From 2fe8148fc3c6da51d91d1910a7d694c0b648115d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:16:54 +0000 Subject: [PATCH 1487/4969] Bump logback-classic from 1.2.5 to 1.2.6 in /examples Bumps logback-classic from 1.2.5 to 1.2.6. --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index c3b3e22fbc2..c44b4c7e7e1 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.5' + testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 8f23284a48e..c4f32682f0f 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:2.8.0' testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.5' + testImplementation 'ch.qos.logback:logback-classic:1.2.6' } diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index ff1b2995e02..f03ce765d24 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.2.23' - testImplementation 'ch.qos.logback:logback-classic:1.2.5' + testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.testcontainers:postgresql' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index fe269d58e77..9b1424451ec 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'ch.qos.logback:logback-classic:1.2.5' + testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.testng:testng:7.4.0' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 2d9f50b86bd..917f1b0c5a4 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -13,6 +13,6 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testImplementation 'ch.qos.logback:logback-classic:1.2.5' + testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index f3a18e685f3..661f6efc125 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' - testImplementation 'ch.qos.logback:logback-classic:1.2.5' + testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From a79418cdc1dbba3cf0ff6e74864be2a12d2b58b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:24:22 +0000 Subject: [PATCH 1488/4969] Bump gradle/wrapper-validation-action from 1.0.3 to 1.0.4 Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/e2c57acffb2c9aa5a8dc6eda2bbae0b6e495bd4c...e6e38bacfdf1a337459f332974bb2327a31aaf4b) Signed-off-by: dependabot[bot] --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index f9f1ec85662..08fbc91d00c 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -18,4 +18,4 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies - - uses: gradle/wrapper-validation-action@e2c57acffb2c9aa5a8dc6eda2bbae0b6e495bd4c # v1.0.3 + - uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b # v1.0.3 From 1202161b52b938a49e399c0df5b689d7cb52430c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:29:14 +0000 Subject: [PATCH 1489/4969] Bump influxdb-java from 2.21 to 2.22 in /modules/influxdb Bumps [influxdb-java](https://github.com/influxdata/influxdb-java) from 2.21 to 2.22. - [Release notes](https://github.com/influxdata/influxdb-java/releases) - [Changelog](https://github.com/influxdata/influxdb-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-java/compare/influxdb-java-2.21...influxdb-java-2.22) --- updated-dependencies: - dependency-name: org.influxdb:influxdb-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/influxdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index 704bf960724..7a028d4a19d 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { api project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.21' + compileOnly 'org.influxdb:influxdb-java:2.22' testImplementation 'org.influxdb:influxdb-java:2.21' } From 3304899856be39657b5433de3f5545504a24a8ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:34:15 +0000 Subject: [PATCH 1490/4969] Bump tomcat-jdbc from 10.0.10 to 10.0.12 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.10 to 10.0.12. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 8145855684f..42fb9e45dae 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.10' + api 'org.apache.tomcat:tomcat-jdbc:10.0.12' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.26' } From 600e751a73ae971c04cf654e3c5c968bad846b34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:26:45 +0000 Subject: [PATCH 1491/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /examples Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index f284af631e5..3679475d1bd 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -11,7 +11,7 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:1.18.10" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:3.0.0' - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.6' } From 740c0aa85d5da6a603171ec4a751516387ef20c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:26:45 +0000 Subject: [PATCH 1492/4969] Bump junit-jupiter-params from 5.7.2 to 5.8.1 in /modules/junit-jupiter Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.7.2 to 5.8.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.2...r5.8.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7df16da0100..1a7c9a477b6 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.21.0' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.1' testRuntimeOnly 'org.postgresql:postgresql:42.2.24' testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' From 6f546524d44c968b2ae227bbebbc299b0b830ffa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:26:54 +0000 Subject: [PATCH 1493/4969] Bump postgresql from 42.2.23 to 42.2.24 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.23 to 42.2.24. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.23...REL42.2.24) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 475f4032758..da10b960013 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'com.squareup.okhttp3:okhttp:4.9.2' implementation 'org.json:json:20210307' - testImplementation 'org.postgresql:postgresql:42.2.23' + testImplementation 'org.postgresql:postgresql:42.2.24' testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.testcontainers:postgresql' } From 4b8ea7ee3ccdd5c67f92957b49057793c84e916e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:26:56 +0000 Subject: [PATCH 1494/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /modules/vault Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 18897f66908..4fdb274f999 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testImplementation 'com.bettercloud:vault-java-driver:5.1.0' testImplementation 'io.rest-assured:rest-assured:4.4.0' - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' } From 878f441d52e65ba1932ab222155bdccd030648d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:26:59 +0000 Subject: [PATCH 1495/4969] Bump org.jetbrains.kotlin.jvm from 1.5.30 to 1.5.31 in /examples Bumps org.jetbrains.kotlin.jvm from 1.5.30 to 1.5.31. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 7e6989a1d93..e40e32a4397 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.5.5" - id("org.jetbrains.kotlin.jvm") version "1.5.30" + id("org.jetbrains.kotlin.jvm") version "1.5.31" id("org.jetbrains.kotlin.plugin.spring") version "1.5.31" } From 34c76ff0aca7bcada960246baefa025cc7b2ca03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:27:02 +0000 Subject: [PATCH 1496/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /modules/database-commons Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 35578b55d68..73735b0d03d 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { api project(':testcontainers') - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' } From 85368a9ee379c6b641305425fd4818024db3b968 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:27:02 +0000 Subject: [PATCH 1497/4969] Bump assertj-core from 3.20.2 to 3.21.0 in /modules/kafka Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.20.2 to 3.21.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 63f751665b0..b37105f7463 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -13,6 +13,6 @@ dependencies { api project(':testcontainers') testImplementation 'org.apache.kafka:kafka-clients:3.0.0' - testImplementation 'org.assertj:assertj-core:3.20.2' + testImplementation 'org.assertj:assertj-core:3.21.0' testImplementation 'com.google.guava:guava:23.0' } From f83a4857ca9c9491beb69e3068791ca38ed18a00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:27:19 +0000 Subject: [PATCH 1498/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.14.1 to 7.15.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.14.1...v7.15.0) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index c70fd363f55..2897ecb5628 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.14.1" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.15.0" testImplementation "org.elasticsearch.client:transport:7.15.0" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From fe35c5c6bc87df8dd63c433187cf1e760c7733ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:27:20 +0000 Subject: [PATCH 1499/4969] Bump aws-java-sdk-sqs from 1.12.62 to 1.12.82 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.62 to 1.12.82. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.62...1.12.82) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 04583b6ecdd..0d089bdf95f 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.80' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.62' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.82' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' testImplementation 'software.amazon.awssdk:s3:2.17.52' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From aa273b5c0136d8bf8d9eb308040b30006ad98144 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 8 Oct 2021 11:21:48 +0200 Subject: [PATCH 1500/4969] Document Dependabot merge process (#4556) Co-authored-by: Richard North --- docs/contributing.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/contributing.md b/docs/contributing.md index 7d87945c704..4094fab14ef 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -90,3 +90,17 @@ New modules should have the following warning at the top of their documentation This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. We will evaluate incubating modules periodically, and remove the label when appropriate. + + +## Combining Dependabot PRs + +Since we generally get a lot of Dependabot PRs, we regularly combine them into single commits. +For this, we are using the [gh-combine-prs](https://github.com/rnorth/gh-combine-prs) extension for [GitHub CLI](https://cli.github.com/). + +The whole process is as follow: + +1. Check that all open Dependabot PRs did succeed their build. If they did not succeed, trigger a rerun if the cause were external factors or else document the reason if obvious. +2. Run the extension from an up-to-date local `master` branch: `gh combine-prs --query "author:app/dependabot"` +3. Merge conflicts might appear. Just ignore them, we will get those PRs in a future run. +4. Once the build of the combined PR did succeed, temporarily enable merge commits and merge the PR using a merge commit through the GitHub UI. +5. After the merge, disable merge commits again. From 3740f65ae22bab3d59f5bcae0b40c9b42af5cdb6 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 8 Oct 2021 07:22:53 -0400 Subject: [PATCH 1501/4969] Fix `AuthenticatedImagePullTest` (#4560) Previous implementation was assuming that Docker can pull from the gateway, which may not always be the case. This change makes the temporary registry run with host network, so that Docker can always pull from it. --- .../utility/AuthenticatedImagePullTest.java | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index c99770c4fbf..3243d219cc0 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -1,21 +1,10 @@ package org.testcontainers.utility; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; -import static org.testcontainers.TestImages.TINY_IMAGE; - import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.PullImageResultCallback; +import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AuthConfig; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.concurrent.TimeUnit; import org.intellij.lang.annotations.Language; import org.junit.AfterClass; import org.junit.Before; @@ -27,9 +16,27 @@ import org.testcontainers.containers.ContainerState; import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.containers.output.FrameConsumerResultCallback; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.WaitingConsumer; import org.testcontainers.images.builder.ImageFromDockerfile; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; +import static org.testcontainers.TestImages.TINY_IMAGE; + /** * This test checks the integration between Testcontainers and an authenticated registry, but uses * a mock instance of {@link RegistryAuthLocator} - the purpose of the test is solely to ensure that @@ -52,8 +59,10 @@ public class AuthenticatedImagePullTest { .env("REGISTRY_AUTH_HTPASSWD_PATH", "/htpasswd") .env("REGISTRY_AUTH_HTPASSWD_REALM", "Test"); })) - .withExposedPorts(5000) - .waitingFor(new HttpWaitStrategy()); + .withEnv("REGISTRY_HTTP_ADDR", "127.0.0.1:0") + .withCreateContainerCmdModifier(cmd -> { + cmd.getHostConfig().withNetworkMode("host"); + }); private static RegistryAuthLocator originalAuthLocatorSingleton; private static DockerClient client; @@ -62,11 +71,34 @@ public class AuthenticatedImagePullTest { private static RegistryAuthLocator mockAuthLocator; @BeforeClass - public static void setUp() throws InterruptedException { + public static void setUp() throws Exception { originalAuthLocatorSingleton = RegistryAuthLocator.instance(); client = DockerClientFactory.instance().client(); - String testRegistryAddress = authenticatedRegistry.getHost() + ":" + authenticatedRegistry.getFirstMappedPort(); + AtomicInteger port = new AtomicInteger(-1); + try (FrameConsumerResultCallback resultCallback = new FrameConsumerResultCallback()) { + WaitingConsumer waitingConsumer = new WaitingConsumer(); + resultCallback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer); + + client.logContainerCmd(authenticatedRegistry.getContainerId()) + .withStdErr(true) + .withFollowStream(true) + .exec(resultCallback); + + Pattern pattern = Pattern.compile(".*listening on .*:(\\d+).*", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + waitingConsumer.waitUntil(it -> { + String s = it.getUtf8String(); + Matcher matcher = pattern.matcher(s); + if (matcher.matches()) { + port.set(Integer.parseInt(matcher.group(1))); + return true; + } else { + return false; + } + }, 10, TimeUnit.SECONDS); + } + + String testRegistryAddress = authenticatedRegistry.getHost() + ":" + port.get(); testImageName = testRegistryAddress + "/alpine"; final DockerImageName expectedName = DockerImageName.parse(testImageName); @@ -88,7 +120,11 @@ public static void setUp() throws InterruptedException { @Before public void removeImageFromLocalDocker() { // remove the image tag from local docker so that it must be pulled before use - client.removeImageCmd(testImageName).withForce(true).exec(); + try { + client.removeImageCmd(testImageName).withForce(true).exec(); + } catch (NotFoundException ignored) { + + } } @AfterClass From 33218e720158dfe2388bfdf9cad9fdfbfd40990f Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 11 Oct 2021 14:15:19 +0100 Subject: [PATCH 1502/4969] OrientDB: Use log wait strategy for more reliable readiness detection (#4471) --- .../containers/OrientDBContainer.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java index f6ce060b6ec..a68f55b60ef 100644 --- a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java +++ b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java @@ -9,20 +9,14 @@ import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.containers.wait.strategy.WaitAllStrategy; -import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.Optional; -import static java.net.HttpURLConnection.HTTP_OK; - /** * @author robfrank */ @@ -68,14 +62,7 @@ public OrientDBContainer(final DockerImageName dockerImageName) { serverPassword = DEFAULT_SERVER_PASSWORD; databaseName = DEFAULT_DATABASE_NAME; - WaitStrategy waitForHttp = new HttpWaitStrategy() - .forPort(DEFAULT_HTTP_PORT) - .forStatusCodeMatching(response -> response == HTTP_OK); - - waitStrategy = new WaitAllStrategy() - .withStrategy(Wait.forListeningPort()) - .withStrategy(waitForHttp) - .withStartupTimeout(Duration.ofMinutes(2)); + waitStrategy = new LogMessageWaitStrategy().withRegEx(".*Gremlin started correctly.*"); addExposedPorts(DEFAULT_BINARY_PORT, DEFAULT_HTTP_PORT); } From f31ee7984093efe303b8326934a9f76b70f65f35 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 11 Oct 2021 15:15:19 +0100 Subject: [PATCH 1503/4969] Skip japicmp for new modules (#4569) --- gradle/japicmp.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gradle/japicmp.gradle b/gradle/japicmp.gradle index 58fbec9c0b7..e74cdccd3af 100644 --- a/gradle/japicmp.gradle +++ b/gradle/japicmp.gradle @@ -11,6 +11,10 @@ dependencies { tasks.japicmp { dependsOn(tasks.shadowJar) + // Disable if baseline dependencies cannot be resolved - such as when developing a new module that doesn't + // have an existing published version. + enabled = ! configurations.baseline.copy().resolvedConfiguration.lenientConfiguration.getFiles().empty + oldClasspath = configurations.baseline newClasspath = shadowJar.outputs.files ignoreMissingClasses = true From 8d40cbd75c4bbb10797e8543d080ad6e046bc1ce Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 12 Oct 2021 09:27:34 +0200 Subject: [PATCH 1504/4969] Enable `JUnitPlatform` for Spock tests (#4568) Since Spock 2 is based on the JUnit platform, Gradle needs to be configured explicitly to discover and run the tests. Also, since HikariCP 5 requires JDK 11+, we have to switch back to 4.0.3. --- modules/spock/build.gradle | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 3fc86d7877b..1e280e88965 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -12,7 +12,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') - testImplementation 'com.zaxxer:HikariCP:5.0.0' + testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.2.24' @@ -26,3 +26,10 @@ sourceJar { allSource contains both .java and .groovy files */ from sourceSets.main.allSource } + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} From 1ad2a053d858b2080c359a1c85288dd5481a2b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20Ka=C4=9Fan=20=C3=96zcan?= Date: Tue, 12 Oct 2021 10:52:36 +0300 Subject: [PATCH 1505/4969] Add Azure Cosmos DB module: Introduce CosmosDBEmulatorContainer (#4303) Co-authored-by: Richard North --- docs/modules/azure.md | 64 +++++++++++ mkdocs.yml | 1 + modules/azure/build.gradle | 8 ++ .../containers/CosmosDBEmulatorContainer.java | 52 +++++++++ .../containers/KeyStoreBuilder.java | 105 ++++++++++++++++++ .../CosmosDBEmulatorContainerTest.java | 73 ++++++++++++ .../azure/src/test/resources/logback-test.xml | 16 +++ 7 files changed, 319 insertions(+) create mode 100644 docs/modules/azure.md create mode 100644 modules/azure/build.gradle create mode 100644 modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java create mode 100644 modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java create mode 100644 modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java create mode 100644 modules/azure/src/test/resources/logback-test.xml diff --git a/docs/modules/azure.md b/docs/modules/azure.md new file mode 100644 index 00000000000..529f058ea52 --- /dev/null +++ b/docs/modules/azure.md @@ -0,0 +1,64 @@ +# Azure Module + +!!! note +This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +Testcontainers module for the Microsoft Azure's [SDK](https://github.com/Azure/azure-sdk-for-java). + +Currently, the module supports `CosmosDB` emulator. In order to use it, you should use the following class: + +Class | Container Image +-|- +CosmosDBEmulatorContainer | [mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator](https://github.com/microsoft/containerregistry) + +## Usage example + +### CosmosDB + +Start Azure CosmosDB Emulator during a test: + + +[Starting a Azure CosmosDB Emulator container](../../modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java) inside_block:emulatorContainer + + +Prepare KeyStore to use for SSL. + + +[Building KeyStore from certificate within container](../../modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java) inside_block:buildAndSaveNewKeyStore + + +Set system trust-store parameters to use already built KeyStore: + + +[Set system trust-store parameters](../../modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java) inside_block:setSystemTrustStoreParameters + + +Build Azure CosmosDB client: + + +[Build Azure CosmosDB client](../../modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java) inside_block:buildClient + + +Test against the Emulator: + + +[Testing against Azure CosmosDB Emulator container](../../modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java) inside_block:testWithClientAgainstEmulatorContainer + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testImplementation "org.testcontainers:azure:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + azure + {{latest_version}} + test + +``` + diff --git a/mkdocs.yml b/mkdocs.yml index 9929f5292c2..5d182b79590 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -61,6 +61,7 @@ nav: - modules/databases/postgres.md - modules/databases/presto.md - modules/databases/trino.md + - modules/azure.md - modules/docker_compose.md - modules/elasticsearch.md - modules/gcloud.md diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle new file mode 100644 index 00000000000..19d9b3458fd --- /dev/null +++ b/modules/azure/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: Azure" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.15.0' + testImplementation 'com.azure:azure-cosmos:4.16.0' +} diff --git a/modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java new file mode 100644 index 00000000000..9328d881666 --- /dev/null +++ b/modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java @@ -0,0 +1,52 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +import java.security.KeyStore; + +/** + * An Azure CosmosDB container + */ +public class CosmosDBEmulatorContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = + DockerImageName.parse("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator"); + + private static final int PORT = 8081; + + /** + * @param dockerImageName specified docker image name to run + */ + public CosmosDBEmulatorContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(PORT); + waitingFor(Wait.forLogMessage("(?s).*Started\\r\\n$", 1)); + } + + /** + * @return new KeyStore built with PKCS12 + */ + public KeyStore buildNewKeyStore() { + return KeyStoreBuilder.buildByDownloadingCertificate(getEmulatorEndpoint(), getEmulatorKey()); + } + + /** + * Emulator key is a known constant and specified in Azure Cosmos DB Documents. + * This key is also used as password for emulator certificate file. + * + * @return predefined emulator key + * @see Azure Cosmos DB Documents + */ + public String getEmulatorKey() { + return "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="; + } + + /** + * @return secure https emulator endpoint to send requests + */ + public String getEmulatorEndpoint() { + return "https://" + getHost() + ":" + getMappedPort(PORT); + } +} diff --git a/modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java b/modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java new file mode 100644 index 00000000000..0179e8d832a --- /dev/null +++ b/modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java @@ -0,0 +1,105 @@ +package org.testcontainers.containers; + +import okhttp3.Cache; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Objects; + +final class KeyStoreBuilder { + + static KeyStore buildByDownloadingCertificate(String endpoint, String keyStorePassword) { + OkHttpClient client = null; + Response response = null; + try { + TrustManager[] trustAllManagers = buildTrustAllManagers(); + client = buildTrustAllClient(trustAllManagers); + Request request = buildRequest(endpoint); + response = client.newCall(request).execute(); + return buildKeyStore(response.body().byteStream(), keyStorePassword); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } finally { + closeResponseSilently(response); + closeClientSilently(client); + } + } + + private static TrustManager[] buildTrustAllManagers() { + return new TrustManager[] { + new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{}; + } + } + }; + } + + private static OkHttpClient buildTrustAllClient(TrustManager[] trustManagers) throws Exception { + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustManagers, new SecureRandom()); + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + return new OkHttpClient.Builder() + .sslSocketFactory(socketFactory, (X509TrustManager) trustManagers[0]) + .hostnameVerifier((s, sslSession) -> true) + .build(); + } + + private static Request buildRequest(String endpoint) { + return new Request.Builder() + .get() + .url(endpoint + "/_explorer/emulator.pem") + .build(); + } + + private static KeyStore buildKeyStore(InputStream certificateStream, String keyStorePassword) throws Exception { + Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(certificateStream); + KeyStore keystore = KeyStore.getInstance("PKCS12"); + keystore.load(null, keyStorePassword.toCharArray()); + keystore.setCertificateEntry("azure-cosmos-emulator", certificate); + return keystore; + } + + private static void closeResponseSilently(Response response) { + try { + if (Objects.nonNull(response)) { + response.close(); + } + } catch (Exception ignored) { + } + } + + private static void closeClientSilently(OkHttpClient client) { + try { + if (Objects.nonNull(client)) { + client.dispatcher().executorService().shutdown(); + client.connectionPool().evictAll(); + Cache cache = client.cache(); + if (Objects.nonNull(cache)) { + cache.close(); + } + } + } catch (Exception ignored) { + } + } +} diff --git a/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java b/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java new file mode 100644 index 00000000000..dd9dc6b718f --- /dev/null +++ b/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java @@ -0,0 +1,73 @@ +package org.testcontainers.containers; + +import com.azure.cosmos.CosmosAsyncClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.models.CosmosContainerResponse; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import org.assertj.core.api.Assertions; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.testcontainers.utility.DockerImageName; + +import java.io.FileOutputStream; +import java.nio.file.Path; +import java.security.KeyStore; +import java.util.Properties; + +public class CosmosDBEmulatorContainerTest { + + private static Properties originalSystemProperties; + + @BeforeClass + public static void captureOriginalSystemProperties() { + originalSystemProperties = (Properties) System.getProperties().clone(); + } + + @AfterClass + public static void restoreOriginalSystemProperties() { + System.setProperties(originalSystemProperties); + } + + @Rule + public TemporaryFolder tempFolder = TemporaryFolder.builder().assureDeletion().build(); + + @Rule + // emulatorContainer { + public CosmosDBEmulatorContainer emulator = new CosmosDBEmulatorContainer( + DockerImageName.parse("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest") + ); + // } + + @Test + public void testWithCosmosClient() throws Exception { + // buildAndSaveNewKeyStore { + Path keyStoreFile = tempFolder.newFile("azure-cosmos-emulator.keystore").toPath(); + KeyStore keyStore = emulator.buildNewKeyStore(); + keyStore.store(new FileOutputStream(keyStoreFile.toFile()), emulator.getEmulatorKey().toCharArray()); + // } + // setSystemTrustStoreParameters { + System.setProperty("javax.net.ssl.trustStore", keyStoreFile.toString()); + System.setProperty("javax.net.ssl.trustStorePassword", emulator.getEmulatorKey()); + System.setProperty("javax.net.ssl.trustStoreType", "PKCS12"); + // } + // buildClient { + CosmosAsyncClient client = new CosmosClientBuilder() + .gatewayMode() + .endpointDiscoveryEnabled(false) + .endpoint(emulator.getEmulatorEndpoint()) + .key(emulator.getEmulatorKey()) + .buildAsyncClient(); + // } + // testWithClientAgainstEmulatorContainer { + CosmosDatabaseResponse databaseResponse = + client.createDatabaseIfNotExists("Azure").block(); + Assertions.assertThat(databaseResponse.getStatusCode()).isEqualTo(201); + CosmosContainerResponse containerResponse = + client.getDatabase("Azure").createContainerIfNotExists("ServiceContainer", "/name").block(); + Assertions.assertThat(containerResponse.getStatusCode()).isEqualTo(201); + // } + } +} diff --git a/modules/azure/src/test/resources/logback-test.xml b/modules/azure/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/azure/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 92155d949f58080e7aa12538574e3b8252198f53 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 12 Oct 2021 10:27:22 +0100 Subject: [PATCH 1506/4969] Temporarily disable Thundra on master branch (#4570) --- .github/workflows/ci.yml | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2cbfc92b372..d27955d33e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,14 +9,6 @@ env: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} jobs: - thundra_test_initializer: - runs-on: ubuntu-latest - outputs: - thundra_agent_testrun_id: ${{ steps.thundra_test_initializer.outputs.thundra_agent_testrun_id }} - steps: - - uses: actions/checkout@v2 - - id: thundra_test_initializer - uses: thundra-io/thundra-test-init-action@v1 find_gradle_jobs: runs-on: ubuntu-18.04 outputs: @@ -42,7 +34,7 @@ jobs: echo $TASKS echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" check: - needs: [find_gradle_jobs, thundra_test_initializer] + needs: [find_gradle_jobs] strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} @@ -61,19 +53,9 @@ jobs: key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} - name: Clear existing docker image cache run: docker image prune -af - - name: Thundra Gradle Test Instrumentation - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - uses: thundra-io/thundra-gradle-test-action@v1 - with: - apikey: ${{ secrets.THUNDRA_API_KEY }} - project_id: ${{ secrets.THUNDRA_PROJECT_ID }} - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | - ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} \ - $($THUNDRA_GRADLE_INIT_SCRIPT_PATH || echo "--init-script $THUNDRA_GRADLE_INIT_SCRIPT_PATH") - env: - THUNDRA_AGENT_TEST_RUN_ID: ${{ needs.thundra_test_initializer.outputs.thundra_agent_testrun_id }} - THUNDRA_AGENT_REPORT_REST_BASEURL: https://collector.thundra.us/v1 + ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} httpclient5_test: runs-on: ubuntu-18.04 steps: From b7e9bb6a69264a43bac37edf596a928c96ce5443 Mon Sep 17 00:00:00 2001 From: Ulrich Winter Date: Tue, 12 Oct 2021 17:54:26 +0200 Subject: [PATCH 1507/4969] Update GitLab CI docs: Add --tls=false to docker-in-docker to avoid startup delays (#4573) --- .../continuous_integration/gitlab_ci.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md index e6daf84401f..5e701007ab0 100644 --- a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md +++ b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md @@ -1,14 +1,18 @@ # GitLab CI In order to use Testcontainers in a Gitlab CI pipeline, you need to run the job as a Docker container (see [Patterns for running inside Docker](dind_patterns.md)). -So edit your `.gitlab-ci.yml` to include the [Docker-In-Docker service](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-workflow-with-docker-executor) (`docker:dind`) and set the `DOCKER_HOST` variable to `tcp://docker:2375` and `DOCKER_TLS_CERTDIR` to empty string. +So edit your `.gitlab-ci.yml` to include the [Docker-In-Docker service](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-workflow-with-docker-executor) (`docker:dind`) and set the `DOCKER_HOST` variable to `tcp://docker:2375` and `DOCKER_TLS_CERTDIR` to empty string. + +Caveat: Current docker releases (verified for 20.10.9) intentionally delay the startup, if the docker api is bound to a network address but not TLS protected. To avoid this delay, the docker process needs to be started with the argument `--tls=false`. Otherwise jobs which access the docker api at the very beginning might fail. Here is a sample `.gitlab-ci.yml` that executes test with gradle: ```yml # DinD service is required for Testcontainers services: - - docker:dind + - name: docker:dind + # explicitly disable tls to avoid docker startup interruption + command: ["--tls=false"] variables: # Instruct Testcontainers to use the daemon of DinD. From b29716dbfafe24dd66e8a9c2405aa1330ea96f60 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 13 Oct 2021 06:25:24 -0400 Subject: [PATCH 1508/4969] Remove `httpclient5_test` (#4562) Co-authored-by: Richard North --- .github/workflows/ci.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d27955d33e3..7421b601c8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,12 +56,3 @@ jobs: - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} - httpclient5_test: - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - name: Build with Gradle - run: | - echo "transport.type=httpclient5" > $HOME/.testcontainers.properties - cat $HOME/.testcontainers.properties - ./gradlew --no-daemon --scan testcontainers:test --tests '*EventStreamTest' From 69cf13c307a3e898297bce08f7537b4ebabae7e2 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 13 Oct 2021 07:12:46 -0400 Subject: [PATCH 1509/4969] Perform port checks in parallel (#4463) The checks will now also incorporate Awaitility. --- .../wait/strategy/AbstractWaitStrategy.java | 16 ++++++ .../wait/strategy/HostPortWaitStrategy.java | 52 ++++++++++++++++--- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/AbstractWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/AbstractWaitStrategy.java index dd9421cccf3..5656c21ae1d 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/AbstractWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/AbstractWaitStrategy.java @@ -6,10 +6,26 @@ import java.time.Duration; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; public abstract class AbstractWaitStrategy implements WaitStrategy { + static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() { + + private final AtomicLong COUNTER = new AtomicLong(0); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "testcontainers-wait-" + COUNTER.getAndIncrement()); + thread.setDaemon(true); + return thread; + } + }); + private static final RateLimiter DOCKER_CLIENT_RATE_LIMITER = RateLimiterBuilder .newBuilder() .withRate(1, TimeUnit.SECONDS) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java index a0ba1e9950c..ed6365566f1 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java @@ -1,16 +1,23 @@ package org.testcontainers.containers.wait.strategy; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.rnorth.ducttape.TimeoutException; -import org.rnorth.ducttape.unreliables.Unreliables; +import org.awaitility.Awaitility; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.wait.internal.ExternalPortListeningCheck; import org.testcontainers.containers.wait.internal.InternalCommandPortListeningCheck; +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; /** @@ -22,6 +29,7 @@ public class HostPortWaitStrategy extends AbstractWaitStrategy { @Override + @SneakyThrows(InterruptedException.class) protected void waitUntilReady() { final Set externalLivenessCheckPorts = getLivenessCheckPorts(); if (externalLivenessCheckPorts.isEmpty()) { @@ -31,7 +39,6 @@ protected void waitUntilReady() { return; } - @SuppressWarnings("unchecked") List exposedPorts = waitStrategyTarget.getExposedPorts(); final Set internalPorts = getInternalPorts(externalLivenessCheckPorts, exposedPorts); @@ -41,10 +48,43 @@ protected void waitUntilReady() { Callable externalCheck = new ExternalPortListeningCheck(waitStrategyTarget, externalLivenessCheckPorts); try { - Unreliables.retryUntilTrue((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, - () -> getRateLimiter().getWhenReady(() -> internalCheck.call() && externalCheck.call())); + List> futures = EXECUTOR.invokeAll(Arrays.asList( + // Blocking + () -> { + Instant now = Instant.now(); + Boolean result = internalCheck.call(); + log.debug( + "Internal port check {} for {} in {}", + Boolean.TRUE.equals(result) ? "passed" : "failed", + internalPorts, + Duration.between(now, Instant.now()) + ); + return result; + }, + // Polling + () -> { + Instant now = Instant.now(); + Awaitility.await() + .pollInSameThread() + .pollInterval(Duration.ofMillis(100)) + .pollDelay(Duration.ZERO) + .forever() + .until(externalCheck); - } catch (TimeoutException e) { + log.debug( + "External port check passed for {} mapped as {} in {}", + internalPorts, + externalLivenessCheckPorts, + Duration.between(now, Instant.now()) + ); + return true; + } + ), startupTimeout.getSeconds(), TimeUnit.SECONDS); + + for (Future future : futures) { + future.get(0, TimeUnit.SECONDS); + } + } catch (CancellationException | ExecutionException | TimeoutException e) { throw new ContainerLaunchException("Timed out waiting for container port to open (" + waitStrategyTarget.getHost() + " ports: " + From 737865fb964f6fd5dd84ff6dbe8ca42ab9efdc53 Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 14 Oct 2021 11:39:27 +0100 Subject: [PATCH 1510/4969] Upgrade ryuk image to 0.3.3 (#4581) --- .../main/java/org/testcontainers/utility/ResourceReaper.java | 2 +- docs/features/configuration.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index ca657675da4..8c1f28378ef 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -95,7 +95,7 @@ public static String start(String hostIpAddress, DockerClient client) { @SneakyThrows(InterruptedException.class) public static String start(DockerClient client) { String ryukImage = ImageNameSubstitutor.instance() - .apply(DockerImageName.parse("testcontainers/ryuk:0.3.2")) + .apply(DockerImageName.parse("testcontainers/ryuk:0.3.3")) .asCanonicalNameString(); DockerClientFactory.instance().checkAndPullImage(client, ryukImage); diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 8024dbb15ef..1761d1a2a71 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -47,7 +47,7 @@ It takes a couple of seconds, but if you want to speed up your tests, you can di Testcontainers uses public Docker images to perform different actions like startup checks, VNC recording and others. Some companies disallow the usage of Docker Hub, but you can override `*.image` properties with your own images from your private registry to workaround that. -> **ryuk.container.image = testcontainers/ryuk:0.3.2** +> **ryuk.container.image = testcontainers/ryuk:0.3.3** > Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) > **tinyimage.container.image = alpine:3.14** @@ -74,7 +74,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` ## Customizing Ryuk resource reaper -> **ryuk.container.image = testcontainers/ryuk:0.3.2** +> **ryuk.container.image = testcontainers/ryuk:0.3.3** > The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown > **ryuk.container.privileged = false** From 2174928a5d2ac6e117643c12300171a03f8de7f8 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 14 Oct 2021 13:44:14 +0200 Subject: [PATCH 1511/4969] Remove unused `@ClassRule` container in `KafkaContainerTest` and use `cp-kafka:6.2.1` as default (#4564) --- docs/modules/kafka.md | 4 +-- .../containers/KafkaContainerTest.java | 34 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index b0cd1742f6b..58f447d412e 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -10,9 +10,9 @@ More precisely Testcontainers uses the official Docker images for [Confluent OSS ## Example -The following field in your JUnit test class will prepare a container running Kafka: +Create a `KafkaContainer` to use it in your tests: -[JUnit Rule](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:junitRule +[Creating a KafkaContainer](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:constructorWithVersion The correspondence between Confluent Platform versions and Kafka versions can be seen [in Confluent documentation](https://docs.confluent.io/current/installation/versions-interoperability.html#cp-and-apache-kafka-compatibility) diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index e16081d16d9..f0ef0db2067 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -1,14 +1,6 @@ package org.testcontainers.containers; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - import com.google.common.collect.ImmutableMap; -import java.time.Duration; -import java.util.Collection; -import java.util.UUID; -import java.util.concurrent.TimeUnit; import org.apache.kafka.clients.admin.AdminClient; import org.apache.kafka.clients.admin.AdminClientConfig; import org.apache.kafka.clients.admin.NewTopic; @@ -21,22 +13,25 @@ import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringSerializer; -import org.junit.ClassRule; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.Testcontainers; import org.testcontainers.utility.DockerImageName; +import java.time.Duration; +import java.util.Collection; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + public class KafkaContainerTest { - private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:5.4.3"); + private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:6.2.1"); private static final DockerImageName ZOOKEEPER_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-zookeeper:4.0.0"); - // junitRule { - @ClassRule - public static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3")); - // } - @Test public void testUsage() throws Exception { try (KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE)) { @@ -50,7 +45,7 @@ public void testUsage() throws Exception { public void testUsageWithSpecificImage() throws Exception { try ( // constructorWithVersion { - KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3")) + KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1")) // } ) { kafka.start(); @@ -62,11 +57,10 @@ public void testUsageWithSpecificImage() throws Exception { } } - @Test public void testUsageWithVersion() throws Exception { try ( - KafkaContainer kafka = new KafkaContainer("5.5.1") + KafkaContainer kafka = new KafkaContainer("6.2.1") ) { kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); @@ -105,9 +99,9 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { } @Test - public void testConfluentPlatformVersion6() throws Exception { + public void testConfluentPlatformVersion5() throws Exception { try ( - KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.0.0")) + KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3")) ) { kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); From 81317a66024cb82f99d349c5b3247f8e3616c7ae Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 18 Oct 2021 07:15:46 -0400 Subject: [PATCH 1512/4969] Provide an API to force access to the host (#4584) --- .../containers/GenericContainer.java | 16 +++++++ .../containers/PortForwardingContainer.java | 16 +++++++ .../containers/ExposedHostTest.java | 47 ++++++++++++------- docs/features/networking.md | 3 +- 4 files changed, 63 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 6d9551b8d6e..c2387cf5977 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -231,6 +231,7 @@ public class GenericContainer> @Setter(AccessLevel.NONE) private boolean shouldBeReused = false; + private boolean hostAccessible = false; public GenericContainer(@NonNull final DockerImageName dockerImageName) { this.image = new RemoteDockerImage(dockerImageName); @@ -834,6 +835,9 @@ private void applyConfiguration(CreateContainerCmd createCommand) { createCommand.withNetworkMode(networkForLinks.get()); } + if (hostAccessible) { + PortForwardingContainer.INSTANCE.start(); + } PortForwardingContainer.INSTANCE.getNetwork().ifPresent(it -> { withExtraHost(INTERNAL_HOST_HOSTNAME, it.getIpAddress()); }); @@ -1424,6 +1428,18 @@ public SELF withReuse(boolean reusable) { return self(); } + /** + * Forces access to the tests host machine. + * Use this method if you need to call {@link org.testcontainers.Testcontainers#exposeHostPorts(int...)} + * after you start this container. + * + * @return this + */ + public SELF withAccessToHost(boolean value) { + this.hostAccessible = value; + return self(); + } + @Override public boolean equals(Object o) { return this == o; diff --git a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java index b3f020500a1..a854b1e55c3 100644 --- a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java @@ -15,6 +15,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; public enum PortForwardingContainer { INSTANCE; @@ -68,9 +69,24 @@ public void exposeHostPort(int hostPort, int containerPort) { } } + void start() { + getSshConnection(); + } + Optional getNetwork() { return Optional.ofNullable(container) .map(GenericContainer::getContainerInfo) .flatMap(it -> it.getNetworkSettings().getNetworks().values().stream().findFirst()); } + + void reset() { + if (container != null) { + container.stop(); + } + container = null; + + ((AtomicReference) (Object) sshConnection).set(null); + + exposedPorts.clear(); + } } diff --git a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java index d17b0709dfa..38005014662 100644 --- a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java +++ b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableMap; import com.sun.net.httpserver.HttpServer; import lombok.SneakyThrows; +import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -31,42 +32,52 @@ public static void setUpClass() throws Exception { }); server.start(); - Testcontainers.exposeHostPorts(server.getAddress().getPort()); - - Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 80)); - Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 81)); } @AfterClass - public static void tearDownClass() throws Exception { + public static void tearDownClass() { server.stop(0); } + @After + public void tearDown() { + PortForwardingContainer.INSTANCE.reset(); + } + + @Test + public void testExposedHostAfterContainerIsStarted() { + try ( + GenericContainer container = new GenericContainer<>(TINY_IMAGE) + .withCommand("top") + .withAccessToHost(true) + ) { + container.start(); + Testcontainers.exposeHostPorts(server.getAddress().getPort()); + assertResponse(container, server.getAddress().getPort()); + } + } + @Test public void testExposedHost() throws Exception { - assertResponse(new GenericContainer<>(TINY_IMAGE) - .withCommand("top"), - server.getAddress().getPort()); + Testcontainers.exposeHostPorts(server.getAddress().getPort()); + assertResponse(new GenericContainer<>(TINY_IMAGE).withCommand("top"), server.getAddress().getPort()); } @Test public void testExposedHostWithNetwork() throws Exception { + Testcontainers.exposeHostPorts(server.getAddress().getPort()); try (Network network = Network.newNetwork()) { - assertResponse(new GenericContainer<>(TINY_IMAGE) - .withNetwork(network) - .withCommand("top"), - server.getAddress().getPort()); + assertResponse(new GenericContainer<>(TINY_IMAGE).withNetwork(network).withCommand("top"), server.getAddress().getPort()); } } @Test public void testExposedHostPortOnFixedInternalPorts() throws Exception { - assertResponse(new GenericContainer<>(TINY_IMAGE) - .withCommand("top"), - 80); - assertResponse(new GenericContainer<>(TINY_IMAGE) - .withCommand("top"), - 81); + Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 80)); + Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 81)); + + assertResponse(new GenericContainer<>(TINY_IMAGE).withCommand("top"), 80); + assertResponse(new GenericContainer<>(TINY_IMAGE).withCommand("top"), 81); } @SneakyThrows diff --git a/docs/features/networking.md b/docs/features/networking.md index e7d8493483e..7ecf929da16 100644 --- a/docs/features/networking.md +++ b/docs/features/networking.md @@ -69,7 +69,8 @@ We need to tell Testcontainers to prepare to expose this port to containers: !!! warning - Note that the above command should be invoked _before_ containers are started, but _after_ the server on the host was started. + Note that the above command should be invoked _before_ containers are started, but _after_ the server on the host was started. + Alternatively, use `container.withAccessToHost(true)` to force the host access mechanism (you still need to call `exposeHostPorts` to make the port available). Having done so, we can now access this port from any containers that are launched. From a container's perspective, the hostname will be `host.testcontainers.internal` and the port will be the same value as `localServerPort`. From 31e55619a36f89afe27234b94e0250417dc5ff8f Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 20 Oct 2021 17:19:42 +0100 Subject: [PATCH 1513/4969] Remove Linux Azure pipelines build for Linux (#4452) This retains Windows build --- azure-pipelines.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 247948901d8..91e33f202a9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,21 +3,6 @@ jobs: - job: azure_pipeline_tests steps: - # Run a minimal set of tests in normal Linux pipeline builds - - task: Gradle@2 - condition: eq(variables['Agent.OS'], 'Linux') - displayName: Build & test (Linux - minimal core) - env: - AWS_ACCESS_KEY_ID: $(aws.accessKeyId) - AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) - inputs: - gradleWrapperFile: 'gradlew' - jdkVersionOption: '1.11' - options: "--no-daemon --continue" - tasks: "clean testcontainers:test --tests GenericContainerRuleTest" - publishJUnitResults: true - testResultsFiles: '**/TEST-*.xml' - # Run all core tests when running the Windows CI tests - task: Gradle@2 condition: eq(variables['Agent.OS'], 'Windows_NT') From e122628ab3493967636e5f78498d594b12d7d3ff Mon Sep 17 00:00:00 2001 From: Oguzhan Ozdemir Date: Thu, 21 Oct 2021 14:33:09 +0300 Subject: [PATCH 1514/4969] Revert "Temporarily disable Thundra on master branch" (#4571) Co-authored-by: Kevin Wittek --- .github/workflows/ci.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7421b601c8d..7336e0767e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,14 @@ env: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} jobs: + thundra_test_initializer: + runs-on: ubuntu-latest + outputs: + thundra_agent_testrun_id: ${{ steps.thundra_test_initializer.outputs.thundra_agent_testrun_id }} + steps: + - uses: actions/checkout@v2 + - id: thundra_test_initializer + uses: thundra-io/thundra-test-init-action@v1 find_gradle_jobs: runs-on: ubuntu-18.04 outputs: @@ -34,7 +42,7 @@ jobs: echo $TASKS echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" check: - needs: [find_gradle_jobs] + needs: [find_gradle_jobs, thundra_test_initializer] strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} @@ -53,6 +61,16 @@ jobs: key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} - name: Clear existing docker image cache run: docker image prune -af + - name: Thundra Gradle Test Instrumentation + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + uses: thundra-io/thundra-gradle-test-action@v1 + with: + apikey: ${{ secrets.THUNDRA_API_KEY }} + project_id: ${{ secrets.THUNDRA_PROJECT_ID }} - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | - ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} + ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} \ + $([[ -f $THUNDRA_GRADLE_INIT_SCRIPT_PATH ]] && echo "--init-script $THUNDRA_GRADLE_INIT_SCRIPT_PATH") + env: + THUNDRA_AGENT_TEST_RUN_ID: ${{ needs.thundra_test_initializer.outputs.thundra_agent_testrun_id }} + THUNDRA_AGENT_REPORT_REST_BASEURL: https://collector.thundra.us/v1 \ No newline at end of file From a5418861a0eb605e049ae4ae6a7d6fa08c0e2327 Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Thu, 21 Oct 2021 16:15:33 +0200 Subject: [PATCH 1515/4969] [couchbase] Add support for Couchbase Analytics. (#4592) Co-authored-by: Richard North --- .../couchbase/CouchbaseContainer.java | 48 ++++++++++++++++++- .../couchbase/CouchbaseService.java | 7 ++- .../couchbase/CouchbaseContainerTest.java | 16 +++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index e9247b8c84a..db8d8ec9666 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -68,6 +68,10 @@ public class CouchbaseContainer extends GenericContainer { private static final int SEARCH_SSL_PORT = 18094; + private static final int ANALYTICS_PORT = 8095; + + private static final int ANALYTICS_SSL_PORT = 18095; + private static final int KV_PORT = 11210; private static final int KV_SSL_PORT = 11207; @@ -84,7 +88,17 @@ public class CouchbaseContainer extends GenericContainer { private String password = "password"; - private Set enabledServices = EnumSet.allOf(CouchbaseService.class); + /** + * Enabled services does not include Analytics since most users likely do not need to test + * with it and is also a little heavy on memory and runtime requirements. Also, it is only + * available with the enterprise edition (EE). + */ + private Set enabledServices = EnumSet.of( + CouchbaseService.KV, + CouchbaseService.QUERY, + CouchbaseService.SEARCH, + CouchbaseService.INDEX + ); private final List buckets = new ArrayList<>(); @@ -144,6 +158,17 @@ public CouchbaseContainer withEnabledServices(final CouchbaseService... enabled) return this; } + /** + * Enables the analytics service which is not enabled by default. + * + * @return this {@link CouchbaseContainer} for chaining purposes. + */ + public CouchbaseContainer withAnalyticsService() { + checkNotRunning(); + this.enabledServices.add(CouchbaseService.ANALYTICS); + return this; + } + public final String getUsername() { return username; } @@ -177,6 +202,8 @@ protected void configure() { QUERY_SSL_PORT, SEARCH_PORT, SEARCH_SSL_PORT, + ANALYTICS_PORT, + ANALYTICS_SSL_PORT, KV_PORT, KV_SSL_PORT ); @@ -214,6 +241,16 @@ protected void configure() { ); } + if (enabledServices.contains(CouchbaseService.ANALYTICS)) { + waitStrategy = waitStrategy.withStrategy( + new HttpWaitStrategy() + .forPath("/admin/ping") + .forPort(ANALYTICS_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + ); + } + waitingFor(waitStrategy); } @@ -262,6 +299,10 @@ private void initializeIsEnterprise() { } catch (IOException e) { throw new IllegalStateException("Couchbase /pools did not return valid JSON"); } + + if (!isEnterprise && enabledServices.contains(CouchbaseService.ANALYTICS)) { + throw new IllegalStateException("The Analytics Service is only supported with the Enterprise version"); + } } /** @@ -349,6 +390,11 @@ private void configureExternalPorts() { builder.add("ftsSSL", Integer.toString(getMappedPort(SEARCH_SSL_PORT))); } + if (enabledServices.contains(CouchbaseService.ANALYTICS)) { + builder.add("cbas", Integer.toString(getMappedPort(ANALYTICS_PORT))); + builder.add("cbasSSL", Integer.toString(getMappedPort(ANALYTICS_SSL_PORT))); + } + @Cleanup Response response = doHttpRequest( MGMT_PORT, "/node/controller/setupAlternateAddresses/external", diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java index c60fc6b71d0..57d3e37fcf2 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java @@ -39,7 +39,12 @@ public enum CouchbaseService { /** * Indexing service (needed if QUERY is also used!). */ - INDEX("index"); + INDEX("index"), + + /** + * Analytics service. + */ + ANALYTICS("cbas"); private final String identifier; diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index fcebbe2bb62..5d2d7d9402a 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -21,6 +21,7 @@ import com.couchbase.client.java.Collection; import com.couchbase.client.java.json.JsonObject; import org.junit.Test; +import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.utility.DockerImageName; import java.time.Duration; @@ -29,6 +30,7 @@ import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; public class CouchbaseContainerTest { @@ -111,6 +113,20 @@ public void testBucketIsFlushableIfEnabled() { } } + /** + * Make sure that the code fails fast if the Analytics service is enabled on the community + * edition which is not supported. + */ + @Test + public void testFailureIfCommunityUsedWithAnalytics() { + try ( + CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) + .withEnabledServices(CouchbaseService.KV, CouchbaseService.ANALYTICS) + ) { + assertThrows(ContainerLaunchException.class, () -> setUpClient(container, cluster -> {})); + } + } + private void setUpClient(CouchbaseContainer container, Consumer consumer) { container.start(); From e257baca07068fdc34894060a1997383c32dc040 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 22 Oct 2021 13:04:22 +0200 Subject: [PATCH 1516/4969] Fix race condition in external port check (#4597) Makes Awaitility ignore exception (which are expected to occur) during checking external ports. --- .../containers/wait/strategy/HostPortWaitStrategy.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java index ed6365566f1..38ddcb44db6 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HostPortWaitStrategy.java @@ -68,6 +68,7 @@ protected void waitUntilReady() { .pollInSameThread() .pollInterval(Duration.ofMillis(100)) .pollDelay(Duration.ZERO) + .ignoreExceptions() .forever() .until(externalCheck); From 820161f7be7e43f36b48e2347e3e612bb905bc60 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Fri, 22 Oct 2021 14:17:56 +0200 Subject: [PATCH 1517/4969] Added started log message used in Selenium 4.0.0 (#4580) --- .../containers/BrowserWebDriverContainer.java | 4 ++-- .../junit/{Selenium3xTest.java => SeleniumStartTest.java} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename modules/selenium/src/test/java/org/testcontainers/junit/{Selenium3xTest.java => SeleniumStartTest.java} (86%) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 1209b7af019..17544308691 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -78,7 +78,7 @@ public class BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>(imageName) .withCapabilities(new ChromeOptions())) { From ce57df66eff75e77c545ef840376816a19e54cb7 Mon Sep 17 00:00:00 2001 From: Alexander Lehmann Date: Fri, 22 Oct 2021 14:25:46 +0200 Subject: [PATCH 1518/4969] Fix double nested lambda in `getWithTimeout` (#4470) This fixes #4469, `getWithTimeou`t did only apply to the outer lambda, which returned immediately (the inner lambda). Instead, wrap getWithTimeout itself inside a lambda. --- .../testcontainers/containers/BrowserWebDriverContainer.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 17544308691..7bc37e4701c 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -281,9 +281,8 @@ public int getPort() { @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { driver = Unreliables.retryUntilSuccess(30, TimeUnit.SECONDS, - Timeouts.getWithTimeout(10, TimeUnit.SECONDS, - () -> - () -> new RemoteWebDriver(getSeleniumAddress(), capabilities))); + () -> Timeouts.getWithTimeout(10, TimeUnit.SECONDS, + () -> new RemoteWebDriver(getSeleniumAddress(), capabilities))); if (vncRecordingContainer != null) { LOGGER.debug("Starting VNC recording"); From 1469b22dc2d0cc4694d080f958e403f598632a55 Mon Sep 17 00:00:00 2001 From: Florent Biville <445792+fbiville@users.noreply.github.com> Date: Fri, 22 Oct 2021 14:27:14 +0200 Subject: [PATCH 1519/4969] Make Bolt log wait strategy more lenient (#4455) Fixes #4454 --- .../main/java/org/testcontainers/containers/Neo4jContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index e93a840302a..7890bf5dcad 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -91,7 +91,7 @@ public Neo4jContainer(final DockerImageName dockerImageName) { dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); WaitStrategy waitForBolt = new LogMessageWaitStrategy() - .withRegEx(String.format(".*Bolt enabled on 0\\.0\\.0\\.0:%d\\.\n", DEFAULT_BOLT_PORT)); + .withRegEx(String.format(".*Bolt enabled on .*:%d\\.\n", DEFAULT_BOLT_PORT)); WaitStrategy waitForHttp = new HttpWaitStrategy() .forPort(DEFAULT_HTTP_PORT) .forStatusCodeMatching(response -> response == HTTP_OK); From 902e45a5aca8416ede36b37ea5a84596b5b696ef Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 22 Oct 2021 14:28:39 +0200 Subject: [PATCH 1520/4969] Update RELEASING.md (#4590) Co-authored-by: Sergei Egorov Co-authored-by: Richard North --- RELEASING.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 34a6b55ae26..4ad91b56477 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -6,18 +6,21 @@ Testcontainers' release process is semi-automated through GitHub Actions. This d 1. Ensure that the master branch is building and that tests are passing. 1. Create a new release on GitHub. **The tag name is used as the version**, so please keep the tag name plain (e.g. 1.2.3). -1. The release triggers a GitHub Action workflow, but it gets mostly build using results from the Gradle remote-cache. Therefore, this should be fairly fast. -1. Login to Sonatype to check the staging repository. -1. Get the staging url after GitHub Action workflow finished. -1. Manually test the release with the staging url as maven repository url (e.g. critical issues and features). -1. Run [TinSalver](https://github.com/bsideup/tinsalver) from GitHub using `npx` to sign artifact (see [TinsSalver README](https://github.com/bsideup/tinsalver/blob/main/README.md)). -1. Close the release in Sonatype. This will evaluate the release based on given Sontaype rules and afterwards automatically sync to Maven Central. -1. Handcraft and polish some of the release notes (e.g. substitute combinded dependency PRs and highlight certain features). -1. When available through Maven Central, poke [Richard North](https://github.com/rnorth) to announce the release on Twitter! +1. The release triggers a GitHub Action workflow. +1. Log in to [Sonatype](https://oss.sonatype.org/) to check the staging repository. + * Getting access to Sonatype requires a Sonatype JIRA account and [raising an issue](https://issues.sonatype.org/browse/OSSRH-74229), requesting access. +3. Get the staging URL from Sonatype after GitHub Action workflow finished. The general URL format should be `https://oss.sonatype.org/service/local/repositories/$staging-repo-id/content/` +4. Manually test the release with the staging URL as maven repository URL (e.g. critical issues and features). +5. Run [TinSalver](https://github.com/bsideup/tinsalver) from GitHub using `npx` to sign artifact (see [TinSalver README](https://github.com/bsideup/tinsalver/blob/main/README.md)). + * For TinSalver to correctly work with keybase on WSL on Windows, you might need to disable pinentry: `keybase config set -b pinentry.disabled true`. +7. Close the release in Sonatype. This will evaluate the release based on given Sonatype rules. +8. After successful closing, the release button needs to be clicked and afterwards it is automatically synced to Maven Central. +9. Handcraft and polish some of the release notes (e.g. substitute combinded dependency PRs and highlight certain features). +10. When available through Maven Central, poke [Richard North](https://github.com/rnorth) to announce the release on Twitter! ## Internal details * The process is done with GitHub Actions, TinSalver and Sonatype. * Sonatype will automatically promote the staging release to Maven Central. * Keybase needs to be installed on the developer machine. -* GPG key of signing developer needs to be uplodaed to the Ubuntu keyserver (or other server supported by Sonatype). +* GPG key of signing developer needs to be uplodaed to the [Ubuntu keyserver](https://keyserver.ubuntu.com/) (or other server supported by Sonatype). From 76f11b344ce42ad920828b0628a7ec929a9d0eca Mon Sep 17 00:00:00 2001 From: Robert Munteanu Date: Fri, 22 Oct 2021 14:54:53 +0200 Subject: [PATCH 1521/4969] Upgrade to Docker Compose 1.29.2 (#4164) (#4461) --- .../org/testcontainers/containers/DockerComposeContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 89d6d692db7..961d066cb91 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -608,7 +608,7 @@ interface DockerCompose { class ContainerisedDockerCompose extends GenericContainer implements DockerCompose { public static final char UNIX_PATH_SEPERATOR = ':'; - public static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker/compose:1.24.1"); + public static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker/compose:1.29.2"); public ContainerisedDockerCompose(List composeFiles, String identifier) { From 436fde8cbe1a24b95b6e872bb2247d8018758e2d Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 22 Oct 2021 17:28:37 +0200 Subject: [PATCH 1522/4969] Don't run tests as part of the release build (#4600) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4e1e9d7c5a1..3779af890ae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: run: docker image prune -af - name: Run Gradle Build - run: ./gradlew build --scan --no-daemon -i + run: ./gradlew build --scan --no-daemon -i -x test - name: Run Gradle Publish run: | From 94a1a111d6369edead0ff6e051af26d7dc4799ef Mon Sep 17 00:00:00 2001 From: Oguzhan Ozdemir Date: Mon, 25 Oct 2021 13:19:01 +0300 Subject: [PATCH 1523/4969] Suggestion to add Thundra test summary badge (#4604) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 752c501e91f..9bcf6f002f8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Testcontainers [![Thundra Foresight](https://thundra-assets-prod.s3.us-west-2.amazonaws.com/images/badges/thundra-foresight-badge-enabled.svg)](https://foresight.thundra.live/testRuns/5a49cc30-f063-11eb-9a03-0242ac130003) +[![Thundra Foresight Test Results](https://foresight.service.thundra.us/public/api/v1/badge/test/5a49cc30-f063-11eb-9a03-0242ac130003)](https://foresight.thundra.live/testRuns/5a49cc30-f063-11eb-9a03-0242ac130003) > Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. From 5cbf52a95b81d9a614bff473b617861673119f0b Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 27 Oct 2021 11:19:21 +0100 Subject: [PATCH 1524/4969] Update docs version --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 5d182b79590..be30f26a964 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -97,4 +97,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.16.0 + latest_version: 1.16.2 From 0654ef6a9186eab85df3accd9ea52a37c68853b0 Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 27 Oct 2021 12:16:08 +0100 Subject: [PATCH 1525/4969] Use automated PR to update docs version (#4606) --- .github/workflows/update-docs-version.yml | 45 +++++++++++------------ 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index ee11b83026a..3311847da5d 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -1,28 +1,27 @@ name: Update docs version on: - release: - types: [published] + release: + types: [ published ] jobs: - build: - if: github.repository == 'testcontainers/testcontainers-java' - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - with: - ref: master - - name: Update latest_version property in mkdocs.yml - run: | - sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml - git diff - - name: Commit changes - run: | - git config user.email "nobody@testcontainers.org" - git config user.name "GitHub Action - Update docs version" - git add mkdocs.yml - git commit -m "Update documentation version to ${GITHUB_REF##*/}" -m "skip-checks: true" || echo "not changed" - - name: Push changes - uses: ad-m/github-push-action@40bf560936a8022e68a3c00e7d2abefaf01305a6 # v0.6.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} + build: + if: github.repository == 'testcontainers/testcontainers-java' + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + ref: master + - name: Update latest_version property in mkdocs.yml + run: | + sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml + git diff + - name: Create Pull Request + uses: peter-evans/create-pull-request@3c3d696d5b8aa2eb0e70f76c251e4b149122acf1 # v3.10.1 + with: + title: Update docs version to ${GITHUB_REF##*/} + body: | + Update docs version to ${GITHUB_REF##*/} + skip-checks: true + branch: update-docs-version + delete-branch: true From 70cc4e3b3df6062251d6aa8191a91b7f88b44f6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:34 +0000 Subject: [PATCH 1526/4969] Bump mysql-connector-java from 8.0.26 to 8.0.27 in /modules/mysql Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.26 to 8.0.27. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.26...8.0.27) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index e465acaaee3..d84def3e7ba 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.26' + testImplementation 'mysql:mysql-connector-java:8.0.27' testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' From 659b7a5274b5db8c5d35c7c8952e35b27686d599 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:34 +0000 Subject: [PATCH 1527/4969] Bump neo4j from 3.5.9 to 3.5.29 in /modules/neo4j Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.9 to 3.5.29. - [Release notes](https://github.com/neo4j/neo4j/releases) - [Commits](https://github.com/neo4j/neo4j/commits) --- updated-dependencies: - dependency-name: org.neo4j:neo4j dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 2c25d148418..51cc625dc9d 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -29,7 +29,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.9" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.29" api project(":testcontainers") From bf7f4e3ef7658e33ce02c84f139f41b658c5fb72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:35 +0000 Subject: [PATCH 1528/4969] Bump testcontainers from 1.16.0 to 1.16.2 in /core Bumps [testcontainers](https://github.com/testcontainers/testcontainers-java) from 1.16.0 to 1.16.2. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.16.0...1.16.2) --- updated-dependencies: - dependency-name: org.testcontainers:testcontainers dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index e5a36114afb..ad0e189acec 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -53,7 +53,7 @@ configurations.all { } dependencies { - baseline 'org.testcontainers:testcontainers:1.16.0', { + baseline 'org.testcontainers:testcontainers:1.16.2', { exclude group: "*", module: "*" } From eb95474dc571679d049379861025e6250fac57d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:35 +0000 Subject: [PATCH 1529/4969] Bump mysql-connector-java from 8.0.26 to 8.0.27 in /modules/spock Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.26 to 8.0.27. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.26...8.0.27) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 1e280e88965..478f3bdd31c 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.2.24' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' testCompileClasspath 'org.jetbrains:annotations:22.0.0' } From 3d3c63189af29f64e4f28d9380bc0127a1b44268 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:35 +0000 Subject: [PATCH 1530/4969] Bump aws-java-sdk-dynamodb from 1.12.60 to 1.12.100 in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.60 to 1.12.100. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.60...1.12.100) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 4cf9b02f160..7dbadb27133 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.60' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.37' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.100' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.100' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 652f433b06624c4967f730b90b64514af2457ac2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:35 +0000 Subject: [PATCH 1531/4969] Bump aws-java-sdk-s3 from 1.12.80 to 1.12.100 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.80 to 1.12.100. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.80...1.12.100) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 0d089bdf95f..c1f29a861bc 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.80' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.100' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.82' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' From 0a27e65fd32e27093bb6f1a1777555a20d9266dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:36 +0000 Subject: [PATCH 1532/4969] Bump mysql-connector-java from 8.0.26 to 8.0.27 in /modules/jdbc-test Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.26 to 8.0.27. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.26...8.0.27) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 6e03f3e1969..3cfed4d80c0 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -16,5 +16,5 @@ dependencies { api 'org.apache.tomcat:tomcat-jdbc:10.0.12' api 'org.vibur:vibur-dbcp:25.0' - api 'mysql:mysql-connector-java:8.0.26' + api 'mysql:mysql-connector-java:8.0.27' } From e22501afad14bfe77e673e2f7d14f8c81a8fb89e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:36 +0000 Subject: [PATCH 1533/4969] Bump pulsar-client from 2.7.2 to 2.7.3 in /modules/pulsar Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.7.2 to 2.7.3. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.7.2...v2.7.3) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index d886be91591..ef3a4298128 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { api project(':testcontainers') - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.3' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.21.0' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' } From 49f558b79bd93028030fe0aa5813e0cf82a673d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:39 +0000 Subject: [PATCH 1534/4969] Bump aws-java-sdk-sqs from 1.12.82 to 1.12.100 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.82 to 1.12.100. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.82...1.12.100) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 0d089bdf95f..254f4093667 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.80' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.82' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.100' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' testImplementation 'software.amazon.awssdk:s3:2.17.52' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 4fc1d8a14cf749d66d473752a84e0be7381a2846 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:39 +0000 Subject: [PATCH 1535/4969] Bump mockito-core from 3.12.4 to 4.0.0 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 3.12.4 to 4.0.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.12.4...v4.0.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index e5a36114afb..995da71ffd4 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -93,7 +93,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.13.1' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' - testImplementation ('org.mockito:mockito-core:3.12.4') { + testImplementation ('org.mockito:mockito-core:4.0.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 63c3d68ba6f2501a2398c81fb90000cdc8d9b385 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:40 +0000 Subject: [PATCH 1536/4969] Bump java-client from 3.2.1 to 3.2.2 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.2.1 to 3.2.2. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.2.1...java-client-3.2.2) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 99cf927173e..02917b46045 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') - testImplementation 'com.couchbase.client:java-client:3.2.1' + testImplementation 'com.couchbase.client:java-client:3.2.2' testImplementation 'org.awaitility:awaitility:4.1.0' } From 82fd5d6de922147eba6c6d1502462d60d655caa6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:40 +0000 Subject: [PATCH 1537/4969] Bump transport from 7.15.0 to 7.15.1 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.15.0 to 7.15.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.15.0...v7.15.1) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 2897ecb5628..1c3e66edf0d 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.15.0" - testImplementation "org.elasticsearch.client:transport:7.15.0" + testImplementation "org.elasticsearch.client:transport:7.15.1" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From fc48919f1691d063cd5cfd247ad63a533bd5cea3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:41 +0000 Subject: [PATCH 1538/4969] Bump pulsar-client-admin from 2.7.2 to 2.7.3 in /modules/pulsar Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.7.2 to 2.7.3. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.7.2...v2.7.3) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client-admin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index d886be91591..0a85bd4dc07 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.2' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.21.0' - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.2' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.3' } From a615b1e1fc8e3dbca584d5238a6c26e45e154cd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:43 +0000 Subject: [PATCH 1539/4969] Bump postgresql from 42.2.24 to 42.3.1 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.24 to 42.3.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.24...REL42.3.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 669a2e6b85d..7f127be30c1 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.21.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.1' - testRuntimeOnly 'org.postgresql:postgresql:42.2.24' + testRuntimeOnly 'org.postgresql:postgresql:42.3.1' testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' } From 84161818095d53ec3d20447ab415ef5c5530a35e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:45 +0000 Subject: [PATCH 1540/4969] Bump solr-solrj from 8.10.0 to 8.10.1 in /examples Bumps solr-solrj from 8.10.0 to 8.10.1. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 373ece1df60..5f76ada58cf 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.16" - implementation 'org.apache.solr:solr-solrj:8.10.0' + implementation 'org.apache.solr:solr-solrj:8.10.1' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From f086d69041b6f14db9f83f62c894e8c6c7d76ab2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:47 +0000 Subject: [PATCH 1541/4969] Bump s3 from 2.17.52 to 2.17.72 in /modules/localstack Bumps s3 from 2.17.52 to 2.17.72. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 0d089bdf95f..34b35ab8a1f 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.82' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' - testImplementation 'software.amazon.awssdk:s3:2.17.52' + testImplementation 'software.amazon.awssdk:s3:2.17.72' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 16368fc9a99eb901a78fced62e2c675d94356646 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:00:59 +0000 Subject: [PATCH 1542/4969] Bump cucumber-junit from 6.11.0 to 7.0.0 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 6.11.0 to 7.0.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.11.0...v7.0.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 6febeeec483..ae66a351335 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:6.11.0' - testImplementation 'io.cucumber:cucumber-junit:6.11.0' + testImplementation 'io.cucumber:cucumber-junit:7.0.0' testImplementation 'org.testcontainers:selenium' } From 489c753d435383f145ca5d666b1463e90460d9c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:01:02 +0000 Subject: [PATCH 1543/4969] Bump gson from 2.8.8 to 2.8.9 in /examples Bumps [gson](https://github.com/google/gson) from 2.8.8 to 2.8.9. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.8.8...gson-parent-2.8.9) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index c44b4c7e7e1..5d2876fd3b1 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.20" annotationProcessor "org.projectlombok:lombok:1.18.20" implementation 'biz.paluch.redis:spinach:0.3' - implementation 'com.google.code.gson:gson:2.8.8' + implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.mockito:mockito-all:1.10.19' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 9b1424451ec..0771fbeec7f 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:3.7.0' - implementation 'com.google.code.gson:gson:2.8.8' + implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.6' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 917f1b0c5a4..3651bbe6927 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:3.7.0' - implementation 'com.google.code.gson:gson:2.8.8' + implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 661f6efc125..44ce783694b 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation 'redis.clients:jedis:3.7.0' - implementation 'com.google.code.gson:gson:2.8.8' + implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From 7ffce94eb5047b0ad6288ba62f77078baf5c2b9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:01:11 +0000 Subject: [PATCH 1544/4969] Bump org.springframework.boot from 2.5.5 to 2.5.6 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.5.5 to 2.5.6. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.5.5...v2.5.6) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 48f9ed91b17..f1618268508 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.5' + id 'org.springframework.boot' version '2.5.6' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index e40e32a4397..c512e594a65 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.5.5" + id("org.springframework.boot") version "2.5.6" id("org.jetbrains.kotlin.jvm") version "1.5.31" id("org.jetbrains.kotlin.plugin.spring") version "1.5.31" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 20ec4efd463..85cb38f3781 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.5' + id 'org.springframework.boot' version '2.5.6' } apply plugin: 'io.spring.dependency-management' From 59b0c3802d4c5721e4b0bd4529ddaf54e5d24f8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 22:01:20 +0000 Subject: [PATCH 1545/4969] Bump toxiproxy-java from 2.1.4 to 2.1.5 in /modules/toxiproxy Bumps [toxiproxy-java](https://github.com/trekawek/toxiproxy-java) from 2.1.4 to 2.1.5. - [Release notes](https://github.com/trekawek/toxiproxy-java/releases) - [Changelog](https://github.com/trekawek/toxiproxy-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/trekawek/toxiproxy-java/compare/toxiproxy-java-2.1.4...toxiproxy-java-2.1.5) --- updated-dependencies: - dependency-name: eu.rekawek.toxiproxy:toxiproxy-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/toxiproxy/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index 3d7d110609b..cad4b6b71f3 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Toxiproxy" dependencies { api project(':testcontainers') - api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.4' + api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.5' testImplementation 'redis.clients:jedis:3.0.1' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From d69602467983709d8bdc5665c83f3a0502a189c3 Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Tue, 2 Nov 2021 16:13:00 +0100 Subject: [PATCH 1546/4969] Fix Documentation not displaying properly for 'Docker wormhole pattern' (#4658) Fixes #4656 --- .../continuous_integration/dind_patterns.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/supported_docker_environment/continuous_integration/dind_patterns.md b/docs/supported_docker_environment/continuous_integration/dind_patterns.md index e742c047afa..b6fc4e489ea 100644 --- a/docs/supported_docker_environment/continuous_integration/dind_patterns.md +++ b/docs/supported_docker_environment/continuous_integration/dind_patterns.md @@ -27,6 +27,7 @@ $ docker run -it --rm -v $PWD:$PWD -w $PWD -v /var/run/docker.sock:/var/run/dock ``` Where: + * `-v $PWD:$PWD` will add your current directory as a volume inside the container * `-w $PWD` will set the current directory to this volume * `-v /var/run/docker.sock:/var/run/docker.sock` will map the Docker socket From 12b08b9e7ba77fed5d0c5a5665588d1c27338d16 Mon Sep 17 00:00:00 2001 From: Richard North Date: Mon, 8 Nov 2021 13:44:11 +0000 Subject: [PATCH 1547/4969] Fix formatting error --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 65d417db2af..c8fb46f26d6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -65,6 +65,7 @@ Using Maven you can add the following to `dependencyManagement` section in your ``` + and then use dependencies without specifying a version: ```xml tab='Maven' From 3ad90d78d0b3cffe8b225ea389c16e300d9949e4 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 9 Nov 2021 11:57:57 +0100 Subject: [PATCH 1548/4969] Add Gradle Enterprise (#4057) Co-authored-by: Richard North --- .github/workflows/ci-examples.yml | 1 + .github/workflows/ci.yml | 1 + settings.gradle | 12 +++++++++--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index a1f81f49bef..286eb41606f 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -7,6 +7,7 @@ on: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + GRADLE_ENTERPRISE_ACCESS_KEY: ge.testcontainers.org=${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: find_gradle_jobs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7336e0767e1..91666644dfa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,7 @@ on: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + GRADLE_ENTERPRISE_ACCESS_KEY: ge.testcontainers.org=${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: thundra_test_initializer: diff --git a/settings.gradle b/settings.gradle index 849a1ade06b..5a3966e3d25 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,12 +6,14 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.2.1" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.6.1" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.2.1" } } apply plugin: 'ch.myniva.s3-build-cache' apply plugin: 'com.gradle.enterprise' +apply plugin: "com.gradle.common-custom-user-data-gradle-plugin" rootProject.name = 'testcontainers-java' @@ -56,7 +58,11 @@ buildCache { gradleEnterprise { buildScan { - termsOfServiceUrl = 'https://gradle.com/terms-of-service' - termsOfServiceAgree = 'yes' + server = "https://ge.testcontainers.org/" + publishAlways() + publishIfAuthenticated() + uploadInBackground = System.getenv("CI") == null + captureTaskInputFiles = true } + } From 484985b137d64533b5a564a2dd705d15293cd845 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 10 Nov 2021 10:15:45 +0100 Subject: [PATCH 1549/4969] Use key=value format for GRADLE_ENTERPRISE_ACCESS_KEY value (#4671) --- .github/workflows/ci-examples.yml | 2 +- .github/workflows/ci.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 286eb41606f..e98c494a2c1 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -7,7 +7,7 @@ on: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - GRADLE_ENTERPRISE_ACCESS_KEY: ge.testcontainers.org=${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: find_gradle_jobs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91666644dfa..93f8307178f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - GRADLE_ENTERPRISE_ACCESS_KEY: ge.testcontainers.org=${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: thundra_test_initializer: @@ -74,4 +74,4 @@ jobs: $([[ -f $THUNDRA_GRADLE_INIT_SCRIPT_PATH ]] && echo "--init-script $THUNDRA_GRADLE_INIT_SCRIPT_PATH") env: THUNDRA_AGENT_TEST_RUN_ID: ${{ needs.thundra_test_initializer.outputs.thundra_agent_testrun_id }} - THUNDRA_AGENT_REPORT_REST_BASEURL: https://collector.thundra.us/v1 \ No newline at end of file + THUNDRA_AGENT_REPORT_REST_BASEURL: https://collector.thundra.us/v1 From 440179d3fe372ff076426b8d1ac9ad614f6eefce Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 10 Nov 2021 14:21:31 +0100 Subject: [PATCH 1550/4969] Update GE plugin in examples to 3.6.1 (#4672) This aligns the version between the examples and the project. --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index ea988b4ada8..4a979449b07 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.2.1" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.6.1" } } From cd04914aa9bd4cdef921e77813d74987c2e1cb97 Mon Sep 17 00:00:00 2001 From: Per Lundberg Date: Tue, 16 Nov 2021 15:22:18 +0200 Subject: [PATCH 1551/4969] Fix typo in Timescale JDBC docs (#4678) --- docs/modules/databases/jdbc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index d402b5983b4..b2a1588ae22 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -41,7 +41,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database #### Using TimescaleDB -`jdbc:tc:timescaldb:2.1.0-pg13:///databasename` +`jdbc:tc:timescaledb:2.1.0-pg13:///databasename` #### Using Trino From ce7693e20bbc21a5e2baca58a8ee0de9223393d9 Mon Sep 17 00:00:00 2001 From: kmcgovern-apixio <66644089+kmcgovern-apixio@users.noreply.github.com> Date: Wed, 17 Nov 2021 03:16:33 -0800 Subject: [PATCH 1552/4969] Change external port check so it can timeout and retry (#4680) Co-authored-by: Sergei Egorov --- .../wait/internal/ExternalPortListeningCheck.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java index b9b63eeee5c..d543d952bbd 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java @@ -4,6 +4,7 @@ import org.testcontainers.containers.ContainerState; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.Socket; import java.util.Set; import java.util.concurrent.Callable; @@ -21,8 +22,9 @@ public Boolean call() { String address = containerState.getHost(); externalLivenessCheckPorts.parallelStream().forEach(externalPort -> { - try { - new Socket(address, externalPort).close(); + try (Socket socket = new Socket()) { + InetSocketAddress inetSocketAddress = new InetSocketAddress(address, externalPort); + socket.connect(inetSocketAddress, 1000); } catch (IOException e) { throw new IllegalStateException("Socket not listening yet: " + externalPort); } From ca244d855109962c72f96bee31804d5b2f39896a Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Thu, 25 Nov 2021 11:42:31 -0800 Subject: [PATCH 1553/4969] Add link to webdrivers module (#4699) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index c8fb46f26d6..83e1a682540 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,7 @@ Testcontainers make the following kinds of tests easier: * **Data access layer integration tests**: use a containerized instance of a MySQL, PostgreSQL or Oracle database to test your data access layer code for complete compatibility, but without requiring complex setup on developers' machines and safe in the knowledge that your tests will always start with a known DB state. Any other database type that can be containerized can also be used. * **Application integration tests**: for running your application in a short-lived test mode with dependencies, such as databases, message queues or web servers. -* **UI/Acceptance tests**: use containerized web browsers, compatible with Selenium, for conducting automated UI tests. Each test can get a fresh instance of the browser, with no browser state, plugin variations or automated browser upgrades to worry about. And you get a video recording of each test session, or just each session where tests failed. +* **UI/Acceptance tests**: use [containerized web browsers](https://www.testcontainers.org/modules/webdriver_containers/), compatible with Selenium, for conducting automated UI tests. Each test can get a fresh instance of the browser, with no browser state, plugin variations or automated browser upgrades to worry about. And you get a video recording of each test session, or just each session where tests failed. * **Much more!** Check out the various contributed modules or create your own custom container classes using [`GenericContainer`](features/creating_container.md) as a base. ## Prerequisites From c86be400c7ef2eda4e36c91b0432d0ba7c74d472 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 25 Nov 2021 14:46:54 -0500 Subject: [PATCH 1554/4969] Use a relative path to the Selenium module (#4700) Follow-up to #4699 --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 83e1a682540..4bfbc723a5a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,7 @@ Testcontainers make the following kinds of tests easier: * **Data access layer integration tests**: use a containerized instance of a MySQL, PostgreSQL or Oracle database to test your data access layer code for complete compatibility, but without requiring complex setup on developers' machines and safe in the knowledge that your tests will always start with a known DB state. Any other database type that can be containerized can also be used. * **Application integration tests**: for running your application in a short-lived test mode with dependencies, such as databases, message queues or web servers. -* **UI/Acceptance tests**: use [containerized web browsers](https://www.testcontainers.org/modules/webdriver_containers/), compatible with Selenium, for conducting automated UI tests. Each test can get a fresh instance of the browser, with no browser state, plugin variations or automated browser upgrades to worry about. And you get a video recording of each test session, or just each session where tests failed. +* **UI/Acceptance tests**: use [containerized web browsers](modules/webdriver_containers.md), compatible with Selenium, for conducting automated UI tests. Each test can get a fresh instance of the browser, with no browser state, plugin variations or automated browser upgrades to worry about. And you get a video recording of each test session, or just each session where tests failed. * **Much more!** Check out the various contributed modules or create your own custom container classes using [`GenericContainer`](features/creating_container.md) as a base. ## Prerequisites From 368c182e9a133a9985483375c0e5718977faacb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:09 +0000 Subject: [PATCH 1555/4969] Bump postgresql from 42.2.24 to 42.3.1 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.24 to 42.3.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.24...REL42.3.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 5c25e6243ef..57c7ed64b14 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.2.24' + testImplementation 'org.postgresql:postgresql:42.3.1' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' From eb1f0a2f17c19f7a9a98a4035a81d81388799111 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:10 +0000 Subject: [PATCH 1556/4969] Bump awaitility from 4.1.0 to 4.1.1 in /modules/couchbase Bumps [awaitility](https://github.com/awaitility/awaitility) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.1.0...awaitility-4.1.1) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 02917b46045..8539d19d2d6 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':testcontainers') testImplementation 'com.couchbase.client:java-client:3.2.2' - testImplementation 'org.awaitility:awaitility:4.1.0' + testImplementation 'org.awaitility:awaitility:4.1.1' } From 15db1ce408e442e6a7bf25ff638abcf3deac8f44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:18 +0000 Subject: [PATCH 1557/4969] Bump mockito-core from 3.12.4 to 4.1.0 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 3.12.4 to 4.1.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.12.4...v4.1.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7f127be30c1..cddedb59408 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:3.7.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:3.12.4') { + testImplementation ('org.mockito:mockito-core:4.1.0') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.21.0' From 01d59303b78fa190927c2d8918240798c124882a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:18 +0000 Subject: [PATCH 1558/4969] Bump postgresql from 42.2.24 to 42.3.1 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.24 to 42.3.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.24...REL42.3.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 478f3bdd31c..0f2843ea007 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.2.24' + testRuntimeOnly 'org.postgresql:postgresql:42.3.1' testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' testCompileClasspath 'org.jetbrains:annotations:22.0.0' From ef9fa8a9ba511cd726dab1284c017fe832469af3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:20 +0000 Subject: [PATCH 1559/4969] Bump mysql-connector-java in /modules/junit-jupiter Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.26 to 8.0.27. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.26...8.0.27) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7f127be30c1..f215680c524 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.1' testRuntimeOnly 'org.postgresql:postgresql:42.3.1' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.26' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' } From 6c86a5ef5070c7ad76eafa61e0923a7e18502856 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:23 +0000 Subject: [PATCH 1560/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.15.0 to 7.15.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.15.0...v7.15.2) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 1c3e66edf0d..da2508085c0 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.15.0" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.15.2" testImplementation "org.elasticsearch.client:transport:7.15.1" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 8bcc7872fa8372069d43e8e6692bf53510a8958b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:25 +0000 Subject: [PATCH 1561/4969] Bump cucumber-java from 6.11.0 to 7.1.0 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 6.11.0 to 7.1.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v6.11.0...v7.1.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index ae66a351335..49b18404862 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:6.11.0' + testImplementation 'io.cucumber:cucumber-java:7.1.0' testImplementation 'io.cucumber:cucumber-junit:7.0.0' testImplementation 'org.testcontainers:selenium' } From 1982b714c5ce44e7de61437be546dc8b1b45810a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:26 +0000 Subject: [PATCH 1562/4969] Bump awaitility from 4.1.0 to 4.1.1 in /core Bumps [awaitility](https://github.com/awaitility/awaitility) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.1.0...awaitility-4.1.1) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9ef9fab67e6..8a63834d03c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -66,7 +66,7 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } - shaded 'org.awaitility:awaitility:4.1.0' + shaded 'org.awaitility:awaitility:4.1.1' api platform('com.github.docker-java:docker-java-bom:3.2.12') shaded platform('com.github.docker-java:docker-java-bom:3.2.12') From d1c958858065b3038cde4343572003f8ba24ef58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:29 +0000 Subject: [PATCH 1563/4969] Bump lombok from 1.18.20 to 1.18.22 in /examples Bumps [lombok](https://github.com/projectlombok/lombok) from 1.18.20 to 1.18.22. - [Release notes](https://github.com/projectlombok/lombok/releases) - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.20...v1.18.22) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 4 ++-- examples/solr-container/build.gradle | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 5d2876fd3b1..c8362c42447 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.20" + compileOnly "org.projectlombok:lombok:1.18.22" annotationProcessor "org.projectlombok:lombok:1.18.20" implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.9' diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 3679475d1bd..cef94112f25 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -7,8 +7,8 @@ repositories { } dependencies { - testCompileOnly "org.projectlombok:lombok:1.18.20" - testAnnotationProcessor "org.projectlombok:lombok:1.18.10" + testCompileOnly "org.projectlombok:lombok:1.18.22" + testAnnotationProcessor "org.projectlombok:lombok:1.18.22" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:3.0.0' testImplementation 'org.assertj:assertj-core:3.21.0' diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 5f76ada58cf..965a40b35a8 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -7,8 +7,8 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.20" - annotationProcessor "org.projectlombok:lombok:1.18.16" + compileOnly "org.projectlombok:lombok:1.18.22" + annotationProcessor "org.projectlombok:lombok:1.18.22" implementation 'org.apache.solr:solr-solrj:8.10.1' From fc974928ccd7f6ad4e07e557b86f1c32315e3421 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:29 +0000 Subject: [PATCH 1564/4969] Bump postgresql from 42.2.24 to 42.3.1 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.24 to 42.3.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.24...REL42.3.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index da10b960013..b5670402803 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'com.squareup.okhttp3:okhttp:4.9.2' implementation 'org.json:json:20210307' - testImplementation 'org.postgresql:postgresql:42.2.24' + testImplementation 'org.postgresql:postgresql:42.3.1' testImplementation 'ch.qos.logback:logback-classic:1.2.6' testImplementation 'org.testcontainers:postgresql' } From 8261f3712b91c833657cb7ce5c08130bf87c7a48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 09:42:35 +0000 Subject: [PATCH 1565/4969] Bump aws-java-sdk-logs from 1.12.60 to 1.12.119 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.60 to 1.12.119. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.60...1.12.119) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 1d2297951e8..7d27bf40721 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.100' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.100' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.60' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.119' testImplementation 'software.amazon.awssdk:s3:2.17.72' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From d1493484d657606a5250a5886d988686d489c0a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1566/4969] Bump transport from 7.15.1 to 7.15.2 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.15.1 to 7.15.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.15.1...v7.15.2) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index da2508085c0..ad1446a0f0f 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.15.2" - testImplementation "org.elasticsearch.client:transport:7.15.1" + testImplementation "org.elasticsearch.client:transport:7.15.2" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From c1bd5954e829ffb90bf9659de32dcfa470a65443 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1567/4969] Bump annotations from 22.0.0 to 23.0.0 in /modules/spock Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 0f2843ea007..cec493cf77d 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -18,7 +18,7 @@ dependencies { testRuntimeOnly 'org.postgresql:postgresql:42.3.1' testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' - testCompileClasspath 'org.jetbrains:annotations:22.0.0' + testCompileClasspath 'org.jetbrains:annotations:23.0.0' } sourceJar { From 2f07fdcca7716d7766ab69a28fb67575a7c50a39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1568/4969] Bump auto-service from 1.0 to 1.0.1 in /modules/mariadb Bumps [auto-service](https://github.com/google/auto) from 1.0 to 1.0.1. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/compare/auto-value-1.0...auto-common-1.0.1) --- updated-dependencies: - dependency-name: com.google.auto.service:auto-service dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index e24fe293ff1..af67719f8ad 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: JDBC :: MariaDB" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0' + annotationProcessor 'com.google.auto.service:auto-service:1.0.1' compileOnly 'com.google.auto.service:auto-service:1.0' api project(':jdbc') From 68c27642b4c91a6959899977892bc54d03a04425 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1569/4969] Bump tomcat-jdbc from 10.0.12 to 10.0.13 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.12 to 10.0.13. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 3cfed4d80c0..7dd1023b95a 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.12' + api 'org.apache.tomcat:tomcat-jdbc:10.0.13' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.27' } From b975b886795e17d7b2905de9af9757ce560f0600 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1570/4969] Bump annotations from 22.0.0 to 23.0.0 in /modules/postgresql Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 57c7ed64b14..530b0c26eae 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -16,5 +16,5 @@ dependencies { testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' - compileOnly 'org.jetbrains:annotations:22.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' } From d85235ae27884c26dddc9210638d7f9921edd65a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1571/4969] Bump junit-jupiter-api from 5.8.1 to 5.8.2 in /modules/junit-jupiter Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.8.1 to 5.8.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 294bcfb48f0..1100219ed96 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { api project(':testcontainers') - api 'org.junit.jupiter:junit-jupiter-api:5.8.1' + api 'org.junit.jupiter:junit-jupiter-api:5.8.2' testImplementation project(':mysql') testImplementation project(':postgresql') From f309c241761863e56355a9a67a02380a649c7e98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1572/4969] Bump annotations from 22.0.0 to 23.0.0 in /modules/jdbc Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index e24690963f2..f5056daedf4 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':database-commons') testImplementation project(':test-support') - compileOnly 'org.jetbrains:annotations:22.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.12' From 5532ac65d38f4be3b1a041405915718388a7de03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1573/4969] Bump annotations from 22.0.0 to 23.0.0 in /modules/oracle-xe Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/oracle-xe/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index 5c18b63bb9d..107f8e66bdf 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -6,5 +6,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'com.oracle.ojdbc:ojdbc8:19.3.0.0' - compileOnly 'org.jetbrains:annotations:22.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' } From bb608169669b52acf05eee7f42ab96a3e144caf8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1574/4969] Bump java-client from 3.2.2 to 3.2.3 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.2.2 to 3.2.3. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.2.2...java-client-3.2.3) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 8539d19d2d6..772876b7bf1 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') - testImplementation 'com.couchbase.client:java-client:3.2.2' + testImplementation 'com.couchbase.client:java-client:3.2.3' testImplementation 'org.awaitility:awaitility:4.1.1' } From caf16e136239d7cd6c0884056b796be29552fb36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:35 +0000 Subject: [PATCH 1575/4969] Bump annotations from 22.0.0 to 23.0.0 in /modules/selenium Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/selenium/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index 5cff4c544b3..5f0824f8b12 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -12,6 +12,6 @@ dependencies { testImplementation project(':nginx') testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - compileOnly 'org.jetbrains:annotations:22.0.0' - testCompileClasspath 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:23.0.0' + testCompileClasspath 'org.jetbrains:annotations:23.0.0' } From 1d14ec53359dd3dfc89ee9aa5662e786eb86c3f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:36 +0000 Subject: [PATCH 1576/4969] Bump auto-service from 1.0 to 1.0.1 in /modules/mssqlserver Bumps [auto-service](https://github.com/google/auto) from 1.0 to 1.0.1. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/compare/auto-value-1.0...auto-common-1.0.1) --- updated-dependencies: - dependency-name: com.google.auto.service:auto-service dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 51e5bba3315..de691b47277 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: MS SQL Server" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0' + annotationProcessor 'com.google.auto.service:auto-service:1.0.1' compileOnly 'com.google.auto.service:auto-service:1.0' api project(':jdbc') From 15452779f0865e8a010141d12ff81598816f720c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:36 +0000 Subject: [PATCH 1577/4969] Bump mockito-core from 4.0.0 to 4.1.0 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.0.0...v4.1.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 8a63834d03c..0d4c9d565ce 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -93,7 +93,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.13.1' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' - testImplementation ('org.mockito:mockito-core:4.0.0') { + testImplementation ('org.mockito:mockito-core:4.1.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 395129e29ff7cdbdb0b1e2bb9d8ca0d6688c373f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:37 +0000 Subject: [PATCH 1578/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.100 to 1.12.122. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.100...1.12.122) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 7dbadb27133..fb4edcf1576 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.100' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.100' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From fda92ef5cb1517c1e8183de34d04635450e4cb87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:37 +0000 Subject: [PATCH 1579/4969] Bump annotations from 22.0.0 to 23.0.0 in /modules/nginx Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/nginx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index b8f45d394c1..288b45b027a 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -2,6 +2,6 @@ description = "Testcontainers :: Nginx" dependencies { api project(':testcontainers') - compileOnly 'org.jetbrains:annotations:22.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From a88fc5a2d4b5a6a0bcfb7e4daa6cd7b335d14a3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:38 +0000 Subject: [PATCH 1580/4969] Bump junit-jupiter-params from 5.8.1 to 5.8.2 in /modules/junit-jupiter Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.8.1 to 5.8.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 294bcfb48f0..06f4ea7a846 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.21.0' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.1' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' testRuntimeOnly 'org.postgresql:postgresql:42.3.1' testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' From 9055bc67eef4205d8c7586ae23a868e10502e6c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:38 +0000 Subject: [PATCH 1581/4969] Bump auto-service from 1.0 to 1.0.1 in /modules/postgresql Bumps [auto-service](https://github.com/google/auto) from 1.0 to 1.0.1. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/compare/auto-value-1.0...auto-common-1.0.1) --- updated-dependencies: - dependency-name: com.google.auto.service:auto-service dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 57c7ed64b14..bf18e22d8f6 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: JDBC :: PostgreSQL" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0' + annotationProcessor 'com.google.auto.service:auto-service:1.0.1' compileOnly 'com.google.auto.service:auto-service:1.0' api project(':jdbc') From ba506700077bea6aad891f519e584bd0d8ac93b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:41 +0000 Subject: [PATCH 1582/4969] Bump amqp-client from 5.13.1 to 5.14.0 in /core Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.13.1 to 5.14.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.13.1...v5.14.0) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 8a63834d03c..d238b908762 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -90,7 +90,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:3.7.0' - testImplementation 'com.rabbitmq:amqp-client:5.13.1' + testImplementation 'com.rabbitmq:amqp-client:5.14.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' testImplementation ('org.mockito:mockito-core:4.0.0') { From 23130b842cd687fe495282ed37a94e9dec414916 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:41 +0000 Subject: [PATCH 1583/4969] Bump junit-jupiter-engine from 5.8.1 to 5.8.2 in /modules/junit-jupiter Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.8.1 to 5.8.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 294bcfb48f0..b6c193e98bb 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntimeOnly 'org.postgresql:postgresql:42.3.1' testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' } test { From 7d1bef98c819ec80a8bd58278f0a1d8d5a9165fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:42 +0000 Subject: [PATCH 1584/4969] Bump aws-java-sdk-s3 from 1.12.100 to 1.12.122 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.100 to 1.12.122. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.100...1.12.122) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 7d27bf40721..39c5c342891 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.100' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.122' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.100' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.119' testImplementation 'software.amazon.awssdk:s3:2.17.72' From da8d136a388918fb7c529e999b55a0f6b10a525c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:43 +0000 Subject: [PATCH 1585/4969] Bump annotations from 22.0.0 to 23.0.0 in /core Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 8a63834d03c..f94c4115c5e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -59,8 +59,8 @@ dependencies { api 'junit:junit:4.13.2' api 'org.slf4j:slf4j-api:1.7.32' - compileOnly 'org.jetbrains:annotations:22.0.0' - testCompileClasspath 'org.jetbrains:annotations:21.0.1' + compileOnly 'org.jetbrains:annotations:23.0.0' + testCompileClasspath 'org.jetbrains:annotations:23.0.0' api 'org.apache.commons:commons-compress:1.21' api ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') From ae0dee7902629a578172971ff9b51c341ac34597 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:43 +0000 Subject: [PATCH 1586/4969] Bump cucumber-junit from 7.0.0 to 7.1.0 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.0.0 to 7.1.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.0.0...v7.1.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 49b18404862..edb62670134 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.1.0' - testImplementation 'io.cucumber:cucumber-junit:7.0.0' + testImplementation 'io.cucumber:cucumber-junit:7.1.0' testImplementation 'org.testcontainers:selenium' } From 99cba6b46ef2a3ca5a4d47c764c6fb0cba13b381 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:45 +0000 Subject: [PATCH 1587/4969] Bump okhttp from 4.9.2 to 4.9.3 in /examples Bumps [okhttp](https://github.com/square/okhttp) from 4.9.2 to 4.9.3. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.9.2...parent-4.9.3) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index b5670402803..f916f6abf81 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'com.squareup.okhttp3:okhttp:4.9.2' + implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.3.1' testImplementation 'ch.qos.logback:logback-classic:1.2.6' From c669300c3654743d07a9cf4cb88519c6b6f5c82e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:46 +0000 Subject: [PATCH 1588/4969] Bump aws-java-sdk-logs from 1.12.119 to 1.12.122 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.119 to 1.12.122. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.119...1.12.122) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 7d27bf40721..11a01bb66f6 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.100' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.80' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.100' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.119' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.122' testImplementation 'software.amazon.awssdk:s3:2.17.72' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 721a7334a265cf4aff93aad7595782ff2954bae5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:53 +0000 Subject: [PATCH 1589/4969] Bump annotations from 22.0.0 to 23.0.0 in /examples Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/mongodb-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 86b3e978019..23f193115ba 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -9,5 +9,5 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testCompileClasspath 'org.jetbrains:annotations:22.0.0' + testCompileClasspath 'org.jetbrains:annotations:23.0.0' } From aff143a43a107dc668509718f03ea32e19dd5a1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:00:54 +0000 Subject: [PATCH 1590/4969] Bump logback-classic from 1.2.6 to 1.2.7 in /examples Bumps logback-classic from 1.2.6 to 1.2.7. --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index c8362c42447..051e82f67d7 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.6' + testImplementation 'ch.qos.logback:logback-classic:1.2.7' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index cef94112f25..290a4295368 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:3.0.0' testImplementation 'org.assertj:assertj-core:3.21.0' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.6' + testImplementation 'ch.qos.logback:logback-classic:1.2.7' } diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index b5670402803..c404e2e7363 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.2' implementation 'org.json:json:20210307' testImplementation 'org.postgresql:postgresql:42.3.1' - testImplementation 'ch.qos.logback:logback-classic:1.2.6' + testImplementation 'ch.qos.logback:logback-classic:1.2.7' testImplementation 'org.testcontainers:postgresql' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 0771fbeec7f..8f30256e2da 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'ch.qos.logback:logback-classic:1.2.6' + testImplementation 'ch.qos.logback:logback-classic:1.2.7' testImplementation 'org.testng:testng:7.4.0' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 3651bbe6927..b6ac1f4ddd6 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -13,6 +13,6 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testImplementation 'ch.qos.logback:logback-classic:1.2.6' + testImplementation 'ch.qos.logback:logback-classic:1.2.7' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 44ce783694b..a8b10171d99 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' - testImplementation 'ch.qos.logback:logback-classic:1.2.6' + testImplementation 'ch.qos.logback:logback-classic:1.2.7' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 0d6f00cf7173547de86fd8bd64c7024ae9d849c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:01:14 +0000 Subject: [PATCH 1591/4969] Bump peter-evans/create-pull-request Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 3c3d696d5b8aa2eb0e70f76c251e4b149122acf1 to 3.11.0. This release includes the previously tagged commit. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/3c3d696d5b8aa2eb0e70f76c251e4b149122acf1...67df31e08a133c6a77008b89689677067fef169e) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 3311847da5d..790dad57188 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -17,7 +17,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@3c3d696d5b8aa2eb0e70f76c251e4b149122acf1 # v3.10.1 + uses: peter-evans/create-pull-request@67df31e08a133c6a77008b89689677067fef169e # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From fedf1d379e2c47a283c387c9c9907f3d2cf14360 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:01:16 +0000 Subject: [PATCH 1592/4969] Bump actions/setup-java from 2.3.1 to 2.4.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2.3.1 to 2.4.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2.3.1...v2.4.0) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index e98c494a2c1..c850d1acaaf 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -16,7 +16,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.1 + - uses: actions/setup-java@v2.4.0 with: java-version: '8.0.302' distribution: temurin @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.1 + - uses: actions/setup-java@v2.4.0 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93f8307178f..a6837c31f43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.1 + - uses: actions/setup-java@v2.4.0 with: java-version: '8.0.302' distribution: temurin @@ -50,7 +50,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.1 + - uses: actions/setup-java@v2.4.0 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3779af890ae..7b727567ecb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.1 + - uses: actions/setup-java@v2.4.0 with: java-version: '8.0.302' distribution: temurin From b85859cb6f51b164d584b3cbe71f3e2c86518e36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:01:20 +0000 Subject: [PATCH 1593/4969] Bump actions/cache from 2.1.6 to 2.1.7 Bumps [actions/cache](https://github.com/actions/cache) from 2.1.6 to 2.1.7. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.6...v2.1.7) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index e98c494a2c1..e3cda845dde 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -21,7 +21,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.6 + uses: actions/cache@v2.1.7 continue-on-error: true with: path: ~/.gradle/caches @@ -49,7 +49,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.6 + uses: actions/cache@v2.1.7 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93f8307178f..d7ffc854dcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.6 + uses: actions/cache@v2.1.7 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -55,7 +55,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.6 + uses: actions/cache@v2.1.7 continue-on-error: true with: path: ~/.gradle/caches From ab4e058aafc1f9b625feec85a07ef9261c1de1ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:02:41 +0000 Subject: [PATCH 1594/4969] Bump org.jetbrains.kotlin.jvm from 1.5.31 to 1.6.0 in /examples Bumps org.jetbrains.kotlin.jvm from 1.5.31 to 1.6.0. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index c512e594a65..4c8d6d551fb 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.5.6" - id("org.jetbrains.kotlin.jvm") version "1.5.31" + id("org.jetbrains.kotlin.jvm") version "1.6.0" id("org.jetbrains.kotlin.plugin.spring") version "1.5.31" } From 4aef1dc6d79aea30db9b30a3f776df31d8f39d4f Mon Sep 17 00:00:00 2001 From: mruemeli <88658860+mruemeli@users.noreply.github.com> Date: Fri, 3 Dec 2021 16:36:27 +0100 Subject: [PATCH 1595/4969] Execute Docker credential programm through shell on Windows (#4763) --- .../java/org/testcontainers/utility/RegistryAuthLocator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index 846b62f1f25..b373eedaa03 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -5,6 +5,7 @@ import com.github.dockerjava.api.model.AuthConfig; import com.google.common.annotations.VisibleForTesting; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.SystemUtils; import org.slf4j.Logger; import org.zeroturnaround.exec.InvalidResultException; import org.zeroturnaround.exec.ProcessExecutor; @@ -337,8 +338,9 @@ private String extractCredentialProviderErrorMessage(InvalidResultException inva private String runCredentialProgram(String hostName, String credentialHelperName) throws InvalidResultException, InterruptedException, TimeoutException, IOException { + String[] command = SystemUtils.IS_OS_WINDOWS ? new String[] {"cmd", "/c", credentialHelperName, "get"} : new String[]{credentialHelperName, "get"}; return new ProcessExecutor() - .command(credentialHelperName, "get") + .command(command) .redirectInput(new ByteArrayInputStream(hostName.getBytes())) .readOutput(true) .exitValueNormal() From 4adabdc5c281c05a202ed2139eadf51006c37e49 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Dec 2021 16:05:25 +0000 Subject: [PATCH 1596/4969] Update Gradle Wrapper to 7.3.1 (#4761) Co-authored-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index a2e01c0dffe..93a3251ccfc 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionSha256Sum=9afb3ca688fc12c761a0e9e4321e4d24e977a4a8916c8a768b1fe05ddb4d6b66 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a37233c5e2e..cf2b23094e4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=a8da5b02437a60819cad23e10fc7e9cf32bcb57029d9cb277e26eeff76ce014b -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip +distributionSha256Sum=b75392c5625a88bccd58a574552a5a323edca82dab5942d2d41097f809c6bcce +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From b4fcec8189af2b6c203725d47c2277076fe81867 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 9 Dec 2021 14:31:36 +0300 Subject: [PATCH 1597/4969] Adapt Gradle config according to Gradle Enterprise Trial experiments (#4705) We are now utilizing the Gradle Enterprise remote cache. --- .github/workflows/ci-examples.yml | 1 + .github/workflows/ci.yml | 1 + .gitignore | 3 +++ build.gradle | 7 ++++++- examples/settings.gradle | 2 +- gradle.properties | 2 +- settings.gradle | 31 ++++++++++++++----------------- 7 files changed, 27 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index b751f1e61a1..7403b53fd8e 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -8,6 +8,7 @@ env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} jobs: find_gradle_jobs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6243237a41..990ffa666b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} jobs: thundra_test_initializer: diff --git a/.gitignore b/.gitignore index aa9fdf33f1f..d6a9a697796 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ src/mkdocs-codeinclude-plugin src/pip-delete-this-directory.txt .DS_Store + +# Codespaces / VSCode +/.vscode/ \ No newline at end of file diff --git a/build.gradle b/build.gradle index aac0648ec06..8fb15a6566f 100644 --- a/build.gradle +++ b/build.gradle @@ -46,9 +46,14 @@ subprojects { task delombok(type: io.franzbecker.gradle.lombok.task.DelombokTask) { def outputDir = file("$buildDir/delombok") outputs.dir(outputDir) + outputs.cacheIf { + true + } for (srcDir in project.sourceSets.main.java.srcDirs) { + // TODO: named input and relative path for `srcDir` to make task more cacheable inputs.dir(srcDir) - args(srcDir, "-d", outputDir) + // TODO: `outputDir` as relative path to make task more cacheable + args(srcDir, "-d", outputDir, "-f", "generateDelombokComment:skip") } } delombok.onlyIf { diff --git a/examples/settings.gradle b/examples/settings.gradle index 4a979449b07..13645d5f5ff 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.6.1" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.7.2" } } diff --git a/gradle.properties b/gradle.properties index 397b832391e..a063988958c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.parallel=false org.gradle.caching=true - +org.gradle.configureondemand=true diff --git a/settings.gradle b/settings.gradle index 5a3966e3d25..db8f11f14c0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,13 +5,11 @@ buildscript { } } dependencies { - classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.6.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.2.1" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.7.2" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.1" } } -apply plugin: 'ch.myniva.s3-build-cache' apply plugin: 'com.gradle.enterprise' apply plugin: "com.gradle.common-custom-user-data-gradle-plugin" @@ -38,21 +36,20 @@ ext.isMasterBuild = false || (System.getenv("GITHUB_REF") == "refs/heads/master") || (System.getenv("BUILD_SOURCEBRANCHNAME") == "master") +ext.isCI = System.getenv("CI") != null + buildCache { local { - enabled = !isMasterBuild + enabled = !isCI } - - remote(ch.myniva.gradle.caching.s3.AwsS3BuildCache) { - endpoint = 'fra1.digitaloceanspaces.com' - region = 'fra1' - bucket = 'testcontainers' - path = 'cache' - reducedRedundancy = false - push = isMasterBuild && !System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") - headers = [ - 'x-amz-acl': 'public-read' - ] + remote(HttpBuildCache) { + push = isCI + enabled = true + url = 'https://ge.testcontainers.org/cache/' + credentials { + username = 'ci' + password = System.getenv("GRADLE_ENTERPRISE_CACHE_PASSWORD") + } } } @@ -61,7 +58,7 @@ gradleEnterprise { server = "https://ge.testcontainers.org/" publishAlways() publishIfAuthenticated() - uploadInBackground = System.getenv("CI") == null + uploadInBackground = !isCI captureTaskInputFiles = true } From 02a8eed88ef22e5894acadb883dd967c2a88080e Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 9 Dec 2021 15:17:19 +0000 Subject: [PATCH 1598/4969] Combined dependencies PR (#4768) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 4 ++-- examples/spring-boot/build.gradle | 2 +- modules/jdbc/build.gradle | 2 +- modules/localstack/build.gradle | 2 +- modules/mssqlserver/build.gradle | 4 ++-- modules/mysql/build.gradle | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index f1618268508..242cfcd3810 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.6' + id 'org.springframework.boot' version '2.6.1' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 4c8d6d551fb..a37b63e6557 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { - id("org.springframework.boot") version "2.5.6" + id("org.springframework.boot") version "2.6.1" id("org.jetbrains.kotlin.jvm") version "1.6.0" - id("org.jetbrains.kotlin.plugin.spring") version "1.5.31" + id("org.jetbrains.kotlin.plugin.spring") version "1.6.0" } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 85cb38f3781..b5ddd11cc84 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.5.6' + id 'org.springframework.boot' version '2.6.1' } apply plugin: 'io.spring.dependency-management' diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index f5056daedf4..5a4ff7872d4 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.12' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.13' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index b96bd49ed59..4b62d30742f 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.100' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.124' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.122' testImplementation 'software.amazon.awssdk:s3:2.17.72' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index de691b47277..1e554440939 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,12 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre8' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.5.0.jre8-preview' testImplementation project(':r2dbc') testImplementation 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' // MSSQL's wait strategy requires the JDBC driver testImplementation testFixtures(project(':r2dbc')) - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre8' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.5.0.jre8-preview' } diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index d84def3e7ba..88a4473f56c 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -1,7 +1,7 @@ description = "Testcontainers :: JDBC :: MySQL" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0' + annotationProcessor 'com.google.auto.service:auto-service:1.0.1' compileOnly 'com.google.auto.service:auto-service:1.0' api project(':jdbc') @@ -15,5 +15,5 @@ dependencies { testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' - compileOnly 'org.jetbrains:annotations:22.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' } From 8a6833d2454e918dd7111351e7580446b74ecdf8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Dec 2021 15:18:11 +0000 Subject: [PATCH 1599/4969] Bump tomcat-jdbc from 10.0.12 to 10.0.14 in /modules/jdbc Bumps tomcat-jdbc from 10.0.12 to 10.0.14. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 5a4ff7872d4..973bc9b01df 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.13' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.14' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From a71554855b4fe06549eb23398e69837617e41974 Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Fri, 10 Dec 2021 08:36:36 +0100 Subject: [PATCH 1600/4969] [couchbase] Ignore transient primary index creation error. (#4681) This changeset makes sure that when a primary index is created, a transient error is ignored since the indexing engine will automatically retry the statement later. Transient errors can happen because we just created the bucket and the indexer might not have caught up to that bucket just yet, but it will eventually. In addition, a check has been added afterwards to make sure that the primary index is online (so, ready for the user to query) before returning to the caller, improving the overall stability of queries. --- .../couchbase/CouchbaseContainer.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index db8d8ec9666..9ef8e99e19d 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -473,7 +473,30 @@ private void createBuckets() { .add("statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`") .build(), true); - checkSuccessfulResponse(queryResponse, "Could not create primary index for bucket " + bucket.getName()); + try { + checkSuccessfulResponse(queryResponse, "Could not create primary index for bucket " + bucket.getName()); + } catch (IllegalStateException ex) { + // potentially ignore the error, the index will be eventually built. + if (!ex.getMessage().contains("Index creation will be retried in background")) { + throw ex; + } + } + + timePhase( + "createBucket:" + bucket.getName() + ":primaryIndexOnline", + () -> Unreliables.retryUntilTrue(1, TimeUnit.MINUTES, () -> { + @Cleanup Response stateResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() + .add("statement", "SELECT count(*) > 0 AS online FROM system:indexes where keyspace_id = \"" + bucket.getName() + "\" and is_primary = true and state = \"online\"") + .build(), true); + + String body = stateResponse.body() != null ? stateResponse.body().string() : null; + checkSuccessfulResponse(stateResponse, "Could not poll primary index state for bucket: " + bucket.getName()); + + return Optional.of(MAPPER.readTree(body)) + .map(n -> n.at("/results/0/online")) + .map(JsonNode::asBoolean) + .orElse(false); + })); } else { logger().info("Primary index creation for bucket {} ignored, since QUERY service is not present.", bucket.getName()); } @@ -508,7 +531,7 @@ private void checkSuccessfulResponse(final Response response, final String messa } } - throw new IllegalStateException(message + ": " + response.toString() + ", body=" + (body == null ? "" : body)); + throw new IllegalStateException(message + ": " + response + ", body=" + (body == null ? "" : body)); } } From 42e4905b15b0fa42ef3343939edd8ce7dc531465 Mon Sep 17 00:00:00 2001 From: Szymon Przebierowski Date: Wed, 22 Dec 2021 17:01:22 +0100 Subject: [PATCH 1601/4969] Remove hardcoded log level setting on mockserver (#4798) --- .../java/org/testcontainers/containers/MockServerContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index 0502469208e..6ab1c541325 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -38,7 +38,7 @@ public MockServerContainer(DockerImageName dockerImageName) { waitingFor(Wait.forHttp("/mockserver/status").withMethod("PUT").forStatusCode(200)); - withCommand("-logLevel INFO -serverPort " + PORT); + withCommand("-serverPort " + PORT); addExposedPorts(PORT); } From 7b098bc6bbdf18cf1c212337ba3e39afef6212a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Dec 2021 10:10:58 +0100 Subject: [PATCH 1602/4969] Update Gradle Wrapper to 7.3.3 (#4800) * Update Gradle Wrapper from 7.3.1 to 7.3.3. Signed-off-by: gradle-update-robot Co-authored-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 93a3251ccfc..59250647c40 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=9afb3ca688fc12c761a0e9e4321e4d24e977a4a8916c8a768b1fe05ddb4d6b66 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip +distributionSha256Sum=b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cf2b23094e4..ee6ba9a3ac4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=b75392c5625a88bccd58a574552a5a323edca82dab5942d2d41097f809c6bcce -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip +distributionSha256Sum=c9490e938b221daf0094982288e4038deed954a3f12fb54cbf270ddf4e37d879 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From a9883cfcc0e4dce5ddd6b584be3d39351b62ce23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Dec 2021 09:05:39 +0000 Subject: [PATCH 1603/4969] Bump mkdocs from 1.0.4 to 1.2.3 (#4771) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Pipfile.lock | 382 +++++++++++++++++++++++++++++---------------------- 1 file changed, 217 insertions(+), 165 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 6ac609b04a9..7dad511e377 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -18,104 +18,133 @@ "default": { "click": { "hashes": [ - "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", - "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" + "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", + "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" ], - "version": "==7.1.2" + "markers": "python_version >= '3.6'", + "version": "==8.0.3" }, - "importlib-metadata": { + "ghp-import": { "hashes": [ - "sha256:742add720a20d0467df2f444ae41704000f50e1234f46174b51f9c6031a1bd71", - "sha256:b74159469b464a99cb8cc3e21973e4d96e05d3024d337313fedb618a6e86e6f4" + "sha256:5f8962b30b20652cdffa9c5a9812f7de6bcb56ec475acac579807719bf242c46", + "sha256:947b3771f11be850c852c64b561c600fdddf794bab363060854c1ee7ad05e071" ], - "markers": "python_version < '3.8'", - "version": "==3.7.3" + "version": "==2.0.2" }, - "jinja2": { + "importlib-metadata": { "hashes": [ - "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", - "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" + "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100", + "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb" ], - "index": "pypi", - "version": "==2.11.3" + "markers": "python_version >= '3.6'", + "version": "==4.8.2" }, - "livereload": { + "jinja2": { "hashes": [ - "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869" + "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", + "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" ], - "version": "==2.6.3" + "markers": "python_version >= '3.6'", + "version": "==3.0.3" }, "markdown": { "hashes": [ - "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49", - "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c" + "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006", + "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3" ], - "version": "==3.3.4" + "markers": "python_version >= '3.6'", + "version": "==3.3.6" }, "markupsafe": { "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", - "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f", - "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014", - "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85", - "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850", - "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1", - "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", - "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5", - "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c", - "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", - "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", - "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" + "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", + "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", + "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", + "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", + "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", + "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", + "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", + "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", + "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", + "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", + "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", + "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", + "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", + "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", + "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", + "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", + "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", + "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", + "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", + "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", + "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", + "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", + "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", + "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", + "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", + "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", + "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", + "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", + "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", + "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", + "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", + "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", + "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", + "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", + "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", + "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", + "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", + "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", + "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", + "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", + "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", + "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", + "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", + "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", + "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", + "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", + "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", + "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", + "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", + "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", + "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", + "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", + "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", + "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", + "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", + "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", + "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", + "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", + "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", + "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", + "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", + "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", + "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", + "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", + "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", + "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", + "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", + "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", + "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" ], - "version": "==1.1.1" + "markers": "python_version >= '3.6'", + "version": "==2.0.1" + }, + "mergedeep": { + "hashes": [ + "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", + "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307" + ], + "markers": "python_version >= '3.6'", + "version": "==1.3.4" }, "mkdocs": { "hashes": [ - "sha256:17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939", - "sha256:8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a" + "sha256:89f5a094764381cda656af4298727c9f53dc3e602983087e1fe96ea1df24f4c1", + "sha256:a1fa8c2d0c1305d7fc2b9d9f607c71778572a8b110fb26642aa00296c9e6d072" ], "index": "pypi", - "version": "==1.0.4" + "version": "==1.2.3" }, "mkdocs-codeinclude-plugin": { "hashes": [ @@ -140,122 +169,145 @@ "index": "pypi", "version": "==3.2.0" }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "markers": "python_version >= '3.6'", + "version": "==21.3" + }, "pygments": { "hashes": [ - "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94", - "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8" + "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380", + "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" ], - "version": "==2.8.1" + "markers": "python_version >= '3.5'", + "version": "==2.10.0" }, "pymdown-extensions": { "hashes": [ - "sha256:478b2c04513fbb2db61688d5f6e9030a92fb9be14f1f383535c43f7be9dff95b", - "sha256:632371fa3bf1b21a0e3f4063010da59b41db049f261f4c0b0872069a9b6d1735" + "sha256:74247f2c80f1d9e3c7242abe1c16317da36c6f26c7ad4b8a7f457f0ec20f0365", + "sha256:b03e66f91f33af4a6e7a0e20c740313522995f69a03d86316b1449766c473d0e" ], - "version": "==8.1.1" + "markers": "python_version >= '3.6'", + "version": "==9.1" + }, + "pyparsing": { + "hashes": [ + "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", + "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" + ], + "markers": "python_version >= '3.6'", + "version": "==3.0.6" + }, + "python-dateutil": { + "hashes": [ + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.8.2" }, "pyyaml": { "hashes": [ - "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", - "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", - "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", - "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", - "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", - "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", - "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", - "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", - "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", - "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", - "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", - "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", - "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347", - "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", - "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541", - "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", - "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", - "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc", - "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", - "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa", - "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", - "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122", - "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", - "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", - "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", - "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc", - "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247", - "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", - "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0" + "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", + "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", + "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", + "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", + "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", + "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", + "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", + "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", + "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", + "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", + "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", + "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", + "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", + "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", + "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", + "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", + "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", + "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", + "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", + "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", + "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", + "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", + "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", + "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", + "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", + "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", + "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" ], - "version": "==5.4.1" + "markers": "python_version >= '3.6'", + "version": "==6.0" }, - "six": { + "pyyaml-env-tag": { "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", + "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069" ], - "version": "==1.15.0" + "markers": "python_version >= '3.6'", + "version": "==0.1" }, - "tornado": { + "six": { "hashes": [ - "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb", - "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c", - "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288", - "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95", - "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558", - "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe", - "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791", - "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d", - "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326", - "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b", - "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4", - "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c", - "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910", - "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5", - "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c", - "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0", - "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675", - "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd", - "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f", - "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c", - "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea", - "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6", - "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05", - "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd", - "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575", - "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a", - "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37", - "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795", - "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f", - "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32", - "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c", - "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01", - "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4", - "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2", - "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921", - "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085", - "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df", - "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102", - "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5", - "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", - "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "version": "==6.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" }, "typing-extensions": { "hashes": [ - "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", - "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", - "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" + "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", + "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" ], "markers": "python_version < '3.8'", - "version": "==3.7.4.3" + "version": "==4.0.1" + }, + "watchdog": { + "hashes": [ + "sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685", + "sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04", + "sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb", + "sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542", + "sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6", + "sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b", + "sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660", + "sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3", + "sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923", + "sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7", + "sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b", + "sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669", + "sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2", + "sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3", + "sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604", + "sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8", + "sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5", + "sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0", + "sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6", + "sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65", + "sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d", + "sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15", + "sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9" + ], + "markers": "python_version >= '3.6'", + "version": "==2.1.6" }, "zipp": { "hashes": [ - "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76", - "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098" + "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", + "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc" ], - "version": "==3.4.1" + "markers": "python_version >= '3.6'", + "version": "==3.6.0" } }, "develop": {} From cbaedff97aebc2465ec111d525e97c2ec7a6a56e Mon Sep 17 00:00:00 2001 From: Richard North Date: Wed, 29 Dec 2021 15:44:01 +0000 Subject: [PATCH 1604/4969] Update sponsors as of Dec 2021 (#4806) --- docs/index.md | 20 +++++++++++++++++++- docs/sponsor_logos/elastic.png | Bin 0 -> 23741 bytes docs/sponsor_logos/red_hat.png | Bin 0 -> 20118 bytes 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 docs/sponsor_logos/elastic.png create mode 100644 docs/sponsor_logos/red_hat.png diff --git a/docs/index.md b/docs/index.md index 4bfbc723a5a..136ae53d2ca 100644 --- a/docs/index.md +++ b/docs/index.md @@ -127,16 +127,34 @@ A huge thank you to our sponsors: +

+ +### Donors + + + ### Backers * [Philip Riecks (@rieckpil)](https://github.com/rieckpil) * [Karl Heinz Marbaise (@khmarbaise)](https://github.com/khmarbaise) * [Sascha Frinken (@sascha-frinken)](https://github.com/sascha-frinken) * [Christoph Dreis (@dreis2211)](https://github.com/dreis2211) -* [Pascal Zwick (@pas2al)](https://github.com/pas2al) * [Nikita Zhevnitskiy (@zhenik)](https://github.com/zhenik) * [Bas Stoker (@bastoker)](https://github.com/bastoker) * [Oleg Nenashev (@oleg-nenashev)](https://github.com/oleg-nenashev) +* [Rik Glover (@rikglover)](https://github.com/rikglover) +* [Amitosh Swain Mahapatra (@recrsn)](https://github.com/recrsn) +* [Paris Apostolopoulos](https://opencollective.com/paris-apostolopoulos) ## Who is using Testcontainers? diff --git a/docs/sponsor_logos/elastic.png b/docs/sponsor_logos/elastic.png new file mode 100644 index 0000000000000000000000000000000000000000..393e6711c45f58934ffc04bd8278b9872c44bf44 GIT binary patch literal 23741 zcmaI7bzIb4w>L}(3KB|4cS(1bO2d#MCEYM|cL>rULpRbjlyo-?T@Kx;G$RK*ZiXb5qds{XmQ+s1GHV<0|fR2D5BJSZ}WCAvGp)@wLu(A`SK5prtrnE8@rPkzC zQ-%=%u7?;srJlG^G|7Ll^N70vOnuxfoG;*xJ}R3welA|HD@Z`2Xo= zc52Fhnz(>PskIbUC?)Kj%qV%;c-c6p#n355oJ`Gy)Fh?<-5K~MN^R-l;vmG%?(Xi+ z=FZJ#?_|NwDJUq&&cVgb#l;G=V0HGib20K@wR5IQiqGXK9cf1>=4<_?zjF80or z_74B4z<(R!Kgs{2BVfM&y^DvD!~fP;QStxX+}8HLsp0G*xc`4t?f)B9!rsQ- z=_3$UW}?)b|8#n?osgWZk%gJ2m8py6e{uUS0?5qH;(t({q_c5-a_=WQD?lHv|Kg_g zUo=r_elGU^V<7GSmGqy!5c)?xMSD{~ynpHRUnDsR2^A-Mb1NHw=By_3fl^LNf{#;> zkB^m$?O!7RjuQgw%-pTWypZ*o#AI%*9_3d9@ZLI!@Y)Z<1{3~Q+@?;uOY6mBK zQ&$r+(|^VV*!_#@Y;W%3ZscV4-U4u~DD``Db1T4zo|Gz2F-ytG#>v6P^WS^8Tbcpf z{#T9I|1A{zQ=0vUR3hyELvE3O8vGx53H1BdZ$Q2S69@Z$&K$s(|D1cw?0^Z!37A;~{As7-l| zBII)mvhH0r?ex5?Xtp?TnRv%O7M5FP!p)6Xx-dZYhI^%PROjdTJy>y=Qx8$0?W8!@ zT5w%%z0+EW*Yk6uqMUTnSLLs_JWV+#&=Q&9J7cHZ5d(Vg_cZ~n&%t`(2Bi0W@@fh% zhlhX37o81_`;H{fnWQ#phi7ga?mau*?CHb9joLK(_Byq#@pOWnxpWIV;j9QIUqSst z9x)mphZZ);V69&|K-(`B3zJplxP5G>^zs?}SYdbh{xIIC)m38o4IV${=J^Cigp8qg za3qLM+#8|iIM-gIw!+t;yl37_D)OlF8dZQ|ChQHP9G@dt1gnx^f;0pUw$x?0Jg~^# z^nL+_Y3g+yk^dR=9GK#FrL#EDW9ys*)(A8QS#4(ogqOHaA4G(-3_=71N(4E{_v#)Q z2g~jmx}UDEPRCPg+Dw1Y&C}+)LsULc(gv@Ty`X-Zn?wDj*g)#l>y9tEeo}s4a(I48 zB{0c`KEs)kVEWa@&@w-IA;i6VIk5b$Gr{?IN!Zz9$FoEKTwdSdsBPTN{4#YqEAQ2Z zMkO#b;GvVykY@sU4;9b7?c%}v^{Y8&#t9@IzxAI8HmDj1%q?4)uS6_m8G$1ExFRRd*t65MAk$xnok&%mQhCNclBwwW0!V%ZB)_m4<4WB(+ zYg;3VA+0>8M?OzftKJHs&-WxlwjMK2g5ckt5!r2=LBV`(%Y^F+X!U{S~_<9+3UEz>QY;)w)5u z&o25pJ=FE}33$zmGNJ0Z49Ry}&RVvRi@&dyF(1s@Ad!a8M<4vijG&Ft7?GZZ$N~5#z$`xr3tGQ7sdEs=nP%PQ#X zqpxX~kA{$ky*~#PKVr{xppxykc}6kfhqPAfg>Op^iW95XYbr+~ULx=_76`R@g~_r) zK#~iSI@tldV+OyDq8GnA)+CA$uLQ`}l{L73%0Xz>L!e8R=%N+5QO!p7`NUY)6`3A6 z0|Z8XbcGQ#8@U7VOT}`d74eJ+2By74IjnAx9t5YFI8@tva2+JyxLDo~U`|x4Z1gpW z(*dkon^Sj$C4!Q1IEI<0@`$7Uh@!L8;-p|OD2_Vh|Dumz?JV}uARt@r`gVj47()d5 z*JCaF-D;!#8}OI30i#(1sN7$dL~bM|yI?zlKqn|JKS84wV`BfRK(#oaiTt#V!OJDg z;LT>${Dt3NXGDxy=ST78gT8MRsW_$bhEsIdcBaag(Ah14^0DOTsm-jQ_K1EYtBSdB zpTU?#%7ry0!;-gU;(u^_Y4}j zgvLaMmx{yv+83hfbMN_|mMmi4K!O+Qgfg5aljTWNrve2Fa51{#9@^9mQ2AWJfvRvhA0 zN8XCsqAwHY8pVx)0{(h;DvYj`3aV%n5L3u{EgVIQ;bj&Y#@3H5Bb_}t6S^d#PP{c_ z!|?Q7LrbVcCvN8~>2i)Mr%fY<5MLv{+76=#{*4&YcdjD$iO$&swecpx#FN)@^hCvF zc0W-%ldG&XoAi3E2u`Rpj6J0o>*%u5t)R!q70xcFM;1oI*if8fYO!_wiDSpX?7cr& zWSvd&CGN{F<*&Zd#$$Z1JHpfrNqiTBf`sPf^2`IR@iQau^iiMA{xK5vykF^20F+;6 z*zc>i`YW#$JH;{K>1P?`32FPr>fO(2Q}YF(uAC0s@Y7mBIV=l4jkW``){>Ji8Iwa@oD}GAviKZWvY#r;Rg( zm^UYl>!U9rV#qoPJm*Hficzz^UU^gnXFm6NMryQg2a(08Ji*(0ET0Z)(*Go{x8^2G zEr`Qw$AXrB%QFA%k2UQ0V44*!jV;4yPjoAZjog9~(k_Ta9Bp`C=zlF3mLei`^Xz@@gM!FW|d zlN{~hP-(1B2EuD4>%(uIhPpq7a_ITp_;sbBJ0Tx#x9@?z=NC2WQUWTpV_7b_*Lr33 z`d#a$Eq43)hlyWnAHCz;MPDPY(_m2@dk^65shU1+j2%{4BT1U#(VA_=HY8z`O>`~# znKL>B%fZOjDF6ot!*8$!bRQP4Pw91z(m~~86p7BC+`=*x2I8C_j9zj0y!@@C6>1V0XwOwOU*PY{{=&~N~AmOpD__nPS>2zwwu27zp8+)O`D{pLRhn#2> zD`;fvOGyv*8eF#}^UG3uFw`56&LNu?*S`gi5WM?EOA$Akzx|!*wo>c|CuN5KBd%Xd zM)zDeCD0usOFhfo2+}pw*xc7_@unLe^>*Xt(&}aoU#Iz9zN!9AADinG%QQx(Vl6O2 z*9Q5MlUKDZ69A?AHERjIcO#FTdoD-+;L7SYGzhl59yZP0FKvq)l%gWq7y_}L=j^Bo zYi=PwZmRNhOF=+B#rws}1`ADvhX&_+Db?`2uq6wTUKF=b>EKn{M}x2hrdK{~@aA;Q z^%w54T&G3p)s8cE15tIg56%^#>y7LJRZFeae?U_TwOFOcKb)mrJ4DM&zDNd|5CJLf7cNph&`SfKg+AJ*B!Rn>TnhZN57 zI^=z5i6rzBKjzA-|Hw~$tR=T5uX662sIZ>zE}~7niakYqKgrr+}L})@oJs(SJI5_kANvZfb|eEjHmeO+p-2D$jD{3;#30GsOZdX z7n8JF3Z=ZteEXI5xy@u+#eqR%xjA+FesX%Z4Se@tm}|iM5@Ih5cnH{ZXn8A-1P8{8 zMoA0M!g|HWxNPTAyJ5X>AGt_SyT!9*ELZlqrVo(tC(*IZNjI`OLny{Jdk!(Jh{4A<^P!+eD?aFQy+ta{xpb zg*l8?Dj69$2d~R-d32$kwIM`Ya>vqVKneUS^D2rKmts!`_Q`UJuek)iY1xW<@F{8t zEuA-ss$yjNPhcjT%YK6!0=nxe)K$0IbQc|9x?*0wMPCQ@ z9{wCR!T5`r3ou%qL5GwwU(DV+|CqLu0NVHjKuroAMdCi|kM8ZXD*6FTgM46?bGpcwg9@k#}x!UY8HDSmLfI>7_c7xw7J>Fh0S z*m6+wN=7qN{;R9l_XHhO(m(uGdlULQ7R9##Lui0gZQxq;t9|6v($h&mI8(d&F`I=1 zVY!xMaC|os#d#gc{N-NZJy8Ymw`-j0P)}Pvxqsw0SmCouaGs0{9{9^&>6$3%wA121 zYrVt`yX3+!VoNwc=-q7%brqUGjQ6=3Y!8k-cuAa_4hHh=z3Dt3^|1S^GQI~Y&?hA_?fN$6E}Mp!>z_Lf zF6pP_@mlepy!2lnn0d5v4{DS(8V$U&Le!2A`NnG%=K8qfM$KH_ zi=$niIk@nx{TL2^{a97@$3!6MfcD4Re#n)vo7*2QFwt z>a+h+2<1t_)m{JUmy<_b6xaGz*}K0W+L0mJ!0~=bI9_%O*5wZZb{~|`I;4tcc1R)g zbYTwPp7sYcOqb83Tuh*eTFoH?#=J*9bMY|ubuASy`Vwh~+!sq|C_*gK0G)8sxN3yq zqZ(jpm>3ujp}Mrc4KnPO``JyHIIu=DUcrmrn0<;{P7neTDXhaXRxDpd&6mWyekVnx zjsMj&)6g}`#U!2gdxuY@XR_r%&Lvt})^&w&j;)jkRiq1zGd&}4jts4ZhZ_Htj!|-B zIaT>87#w?~e6{z0uov@U^3$hmy5vOR323H4CYHsRq2UkPglxwNRBY7^ z2Z4pGyoP1^Z6`6bxXD()#60Uz!e7(Q*lkiqVi{>2!#ch`7eVT^gSy;U=ZzGx*2(n+ zd3aFFf(N0wt6!fh)rY`)nA~{5sZ6c(=f6Z?19oWLOyOK_D{c{v?ZDf|%p@tTZGWem zj%75ooulv3KahUR>Z#tIkE$FrvWz=LtqfL`;)~fy0uCHWwmvwOr`PS>-Vl&(ZXNl{ zRz!7yHW@vcC<{2>>D+HrIKR}zqMgad;Alm~J8&ECrB)i**4~*-f3k(MjTDxNe9epJ zYTL5?TC*WiRLv=uAk(m68QRoFVE;>ef@A10alI>5yJJ60(s&*(q(gl%y9Te7@pM*r zX>VtRNXeg1_&II#>Wnl7I%uw|&39dx{u~!-%iF61A^UoQ`ztk{R*v3rO2?nf1H*v_ z&SS4BES~zYXG-YO?R$eX55=L)W?m+|RZ69+7*bxb1?jmuvl(*s;X0;{Ki-I}iM~9S zAMXXk>3t8r7w^;yIOHt2i6LxYUmC>)6N^^L;{U8Ft`Cx`BNJ(?K@14|x~?4B2WZA! z#UXdjW}8jB+ti)SLi2`dV5dwidHhD?&R@y6#!gd_qaTe0< zPj5MaJh7I4=%vk6dcWq=Umt6ev_`uOMr8kRv~IWJ%A}#@IXapifgEpY90V64xk4bc z-)+{jRb{)ain!)I%<4_VKqpkgGxzygx4NBjMtXxUkohIDE28JSFEpJBy(-FD5oV1~YuoKlPi){6@LiyHuqohTy~YWfqDX(Q6v9_ON(N>IC_JLD`-D3UIr zP&2Y>$Q#?8wBLrId?nXKyZ5O4;*IxxzVzB|=e<0mpzo*z1cU*c=n;-;okzc8xeGE1{_#eN5)Ae>)zxb`e_CF#oUu{Hi7>tJ zJqjFJbmXGMnNCv*;&#EJCIGvv(?DI#TKRFa8DLv$?O&tOE{j8sL6zpIk-`ff=S7EY z4j5j((Ls~SPktx%=aC@6Z(wp8nyJd>X^t-O_=oxuWFYS>vveN28AznFzeSpvS!g=8 zg-{D$uKN8*NKW*E-(PoFg89B9mNxFeS6(@0-$+YJK+SA4(~^Yl;H&>vCc`y_Z{ERq z!)57kWANRP1@+P7Y_Dv+(dWnC-WBrT!-2b^yJKvGC=&< zmwSm~Tg?(=5r`LruU8bN1s_k{=izI`-I6an)WP>J83FLNs-_Niz zqO!o4;@-Y&;@9Ig#tWX<9Tm_Z`;L>>1Y*}>bDkJV_QcRvTYpr*$n5$gkt>HFg1>A?zwf)TTAQQTrk`VA*MCS6{Ve;sr4Ne zR-#tDLgWXNXnL?!R+b3(*#bt z__eA=FCh1-ozr@ej=_j>^x5v5D&|uTnx7M9)&AH(Os)5#POs8@k4ff=HqH++(AaS3 z9<>O$P-2v{0)N*Vt_+v4T9Wk)BTyGcncvAD_u4o65~1Ed|3VkT_BehvnsIURS)G@zV(7hzH^Z*z0~>{H zm0se_8>p+U%sX>*IeNWXcwWFJXhE7+q>GcLLTB*R!TuNtX9u|a zyw7@OrbWK{@+iCROJsHyNWo%b{L(5`vgyw}qfLo@z4xy+o&DfsK_y-YNX)sys;8m8 zwyKWq9=qjis%@CqCZT8?a`s1#AYjG)edX$=%dg|{)r^5y{Y?DXsa20pymgMJ)A5H# zCPe76msgausXjX%(;>04m9%zX5@F9}4bPi0QtYxY0Tie2kK#Ea9(Y&I3pA>1kGr9F z9ahUg~TSY2pjL+{AKG) z>4VS37^rP%ef?yYmL57iE2{ttuj_9UM*w%BgDmk5r5Z_Fyb5EK7M7^LS!O&{YrHr)s&aLNoe+mV7;|9x zQHZ(B_U@Kmi>L5l3I11PSkx=8BU@U;5J(qw!{TK_HP!3rW=O zOB{2~xG%h4aJ^!Ky(?#yYG!$I+rE6Mn-RMMHb(!5{hWQdDgC)QwALB+U8|@vg8iGR zajNN5aVhK2Lcda_2~1$T;zu>e13MA3K(qS<1>Qt-jk|=+f}3c7eV^^r`sZ?8khy8E zLnsz?}F7&ShM(lQ?e)ui@#o&5UPe!JbL5XC0_FUt5Nbwh^LIiqlMwshqw0?b@`u2btwsM#4*ig1)E!Gh&R(8 z(}pO-bvK+0!_Ti;e~zqLm-!|CaGkOOOlDO1tct&$9cyn<0^QTpSa2Q@`}dw1_7^et zo-q80O#*mt+gyVRBZd!I1iOQar{3r1yCN4@iH8ip!VbR;kAN9qoD(%^Zqt~4dT>BHaamK6z`whPTx-x zTo2^Gn(#xEGDxd&6E1TjsuUYWt~lYyNT7i|i<(V2vTmpgR`GeS(zQI0a5k-aIua-F zYOpS(Erh)`r0dMIF}*bpdUiS=1WY&%pILz@p-9sF*+ilVx%VAo5*{@pIMk<2CAN!1GT`a42I+L)k zX`6gh@IUmjejr|;>8E)WY7LE!=rKoZG0ggrC>m11= z$pRl!3AX-DGZ7ga*{pW^?rWSKqWnl{^G+U)bA^!`+xn39~==X3u2E~*M(17#_G@yc8WdhT0t8SoL~y&Sqy7Q3kIRlu0(55E1s=B zPRjB%2ma$})UVrl{psxwmYP@j(sk0WSMeiL1^(I|>HNq@!@`cRFQs&8Aq)WlckS;d ziSl)2#J~s`sWzFjN1gB+b0wb>#lrICBPYWLiyu?f7_L;XXPuUd;7glpjnqaPLquhA z10}n`2lf>`vO`@VcVceqvgn25ql2|}S7u-sGQVmYs{PNTGgn-y9B8Pm&w6$~T-s|f zh~Ma~sKQHmL%(tm*jJiu+*kf^*|keXR=}L**O<3rV{ZOtie$+1gBjR2`uSLLUPiOi zY#EA~m?&@)jAji@N#D{9FPf-6RGT3e`TQZ*WX~9F75Z$(IkFuUAVD7RdN^l;;nkmC zsC&82<;c(v{kM+dyURZp1%7?!pNAW6(vI-_sB2GEbnT~5iutMYye*0Wf6!jGCri%C zt-nL_LIJUZVlneGwsSp>wVVVQ!D#AGA$+HCW1_R=)8h3|hLtXl1(W^Z($1*o=DK|G z9cGlS8T8wbQ188kz$Z6M3=b@%u_Pn$(^G3Uj}1}c#cAhXm1NWWgqKR_fjy!abab*@ zoFMx7_flCw-_u=^@l`}bsx!($iJ(5$?9<@VCYK|bigE9e%Cha-$Q_5FKbM~7=UxjY z`XD%g7Tsc~KawxS*Coy)@t%|~`W-Ze4NYAQzJk~xpG1beS%x>I0kr- zKO!7bH68PTJwk{mZorVP9KCnK?laHBge=n4>3Q?s0Y2!qOyurlYL0SO9ogYhn;QzQ zm`}O^t3hvn(pAXJMcD~0;T01`IwoCmAiDQ?hUgbM_|&Q$0We=zx5dBA@`z>Ft#ky2 z()?+AI?YTpy*yu9`1rXkVNsKXib&>dU0<$9 zou?>+vVSa?VARN{O{Of-N&5Y2M^9LR%7X-0cEncuz9s2FNZ8Ejv&2gV(LeOZsmCRQ zZ+ThkA>n^O5V8Pl7Cu{#s2&LAFH_JZ%ZgAN1QF$epGLZN$0B=VH}G$nXxK((CV|t$TU2@utte*~ph{6ON@vv5y~Q!O%pVpG=srJx6f_j+VY&>7H+`vWkHH|OGWZ~RPK+k6b7?5q>P_*uK% z{LmFsaGQ*TuT_5kosEYaJq)Xpp)j3?X&8;GYGRYqA-lQCKx{ly>wRF5Jc4T`nUC*^ z3%%xTOa1)9jZW$wEd011sNkp=Vusp-uCbBs?7;W zoaxESt7KVgUSb1RU)AVh9BUI96R&eG5R4=mFY&ou9xpi4c8J1HQ5mujC+Xa31-)x8A#gc1w{c6j|?7y`8 z=>{w$6$%!HE#xe;cVz_!b~7?%J#CMVC+@iYI*BA zHL450khNF6nsw{!=~XI*v#)uYRgXQE(vINH3KIYziKg=H+&s>O~JOdFmZ?D9#>%j zVBa&R%b?)D8ApPp_RXx->mx+22KnS=!HltCq1xwRWzEb4Y52)te;uj#A=!fkY=FgCMSc|%*qRLp#<8&AqEs$@0#&mlN)69>=#|+bB#Yhren0CC|I(FKc>%mzta94ZavDp$nQKh z!l?Uj>QeZV_Q-wY(YGqa{sGKHR`X{TAOE^O#H+vpa)98oV-PS&=^VR6Y2c*AI;%YP zJAOcc;WB4#{dLP~hIkOayS#0YZ>s*sQGAN=wer+>PtQej>V9@Hs5! zweLQ+Yc!=rQS8VsuLhG( z>R_Wp`EwoL<;RG#Tv&3ahuRVTj7}eLadtTjNusZ~@<2^*TOi8XL6&6zQxS7 zs6SV%;$=O|IG+=C8()4EVy^GbX5vj^Z*yFbuyAB1;>REw&#od5MJfc2>g!<}2|Dxm zDh|7iY6IcDLdNcCv=9LvX(3O`9&36<-_UHoGfw7oV$x*>VZ3knpUD}Au$(;#9GjrL zsadk`Ah3re@B)W$apV2qk$(S1+Ce}a(P=5wm`1K*S;@v!6NT#j+3S{6rd*TOT3c?5 zv6PX9opDnyXq(aHmvRpNEP;i*J+8%IKm2E-;7P^5TuJIwFjI;IHFlFtOs5qpPtfo6 z<1{^~b%gQknV@s5YTlBo5`X*E?oa0yo?g9n^tTSPN^IHundj!dovlLWMrGg_BBkt& z8G{!a`~%qKwbQx~GzbW5>v_N_-%(2pTfxM8&kM=DIFhZpkKSC9M%~_~n>s)!ii~T} zgpd17sSGG85D?nmjbNcPZEy96#4w$cisyu8?m$4_Olu4PKu@QE;vzN^#(8Hj*DBPK zP@QlG3M^}%j32}FFz@_+s`<5W3CbLpm%5HBwpwn!s%Fbw|n6%~D4Rv{Zs)o{C?|N3^M=0cxe>S52AVr}%It9aCuhwKb%x zFIvD*Fh3SE*XGs5qQ6i-A2b*oZfgq_`O$ZWe5@&rZ3r^6W_fn{!|U1|wk zJ%HKLW+%&ZKYHWi99IYd!?DMz!VSU60UG|6;G9ZR%a5SS(c3V_7B{a~sa2bm`x=ut zyy^8H(e2__E7i2*{_`BDCOXGp)0Ev5O%dY;wD>P{-Q7cDot6X!TH| zCNJjd8fR+!j>t`3wWZ&{Cc9b ze!Q4`WAfLBL?)t9^lg~T>^livZ3nte9h%ko)WCiyK@Ho;#FgOP)YnJgG3fh zdEYhFw~TU-a8Yqo`o*Rk>Vbt#M^MubbT^JaO!JMEQ{SHksz6e6!K8o#@-af($?f0X5_e$R-H*p8HfZHnBdji@hD!cZh6 zg6{4=R1?(dC9kYh;o`Px(O|Q-fFWSa|FcdqZ>eFdmFXm|O`*v_T^zU}758s46q%>m z6dZeFqfRi62Lair$^S&!MXskOaFU3yP%2&vQC-#*R4=pl3j<;g_PSuqOXRX#uZxw) zt=Epp+ie*2vkcOz+wV9xYX!4fg?@}Rb#G_7aaUWCSKh#rW`LSC5rCM{@QwSXwj@$W zVxO%Fs}e}Uie-XrJSB$K-a**10h>YZGFVf!v8%GI#IngzsgUUfN>fici)xfAk4#o!-bv@WK)x zNte(!ObmMb`-^2Q488m%ZWDW{zis4Ij{jKg(mH7e3 zbBm*ysxb$8L%aiXI$fWhFKwv`Fe*djG7{8|kq3~4Gjzp)v*WMbKO5`=31l24y1e<{ zWMa!G7rO*JK6#TQk7V{AEIakum3lkxY9#TcVb8AmOc9=SmpFTT&P~|eJz1Jnsu8aI z!(5==PchyCpbK?#5_DdG5Htjv#7I?qd{q#Cj2(`e3?y2Cx(<>etZk5->EGvA=tL+ZtZ^EvR-(NEmnL#eauD>{9Gdrhlc7p$3%_4Fo0f}VvZ1EcQSY02| zp_NX*XIByGsC>ZND{#FihV1cTZ-1UUV72llIF!Hq^!MxT&+ zveb4*25vrePVh&3%)?)L$%i*+G{DWj<1-s`oHeh41RE6|S{Utn0QJ~OQ8gy*`1h84 zGL0m8Y}ZVXh;tKTjC~7=#(-P<7>QHGMD0^!!VjFPIemMS3hm2{!M;C+Rq18kF&>Fn zkj^R-{@OYN(qPqDxX=Z_l6BR>O#-r!k`Wy#2Ig?0oepya>-)#0yqcV6;&hjW+mwzA zo9PSfi;ZvkGeN5=eKn=a`8sF~OAgj;eu4oq2cMG%h15W%6cghtqSTBp7*RBy^_EmBZNtpS#(M{k;Almvv*ck4*HX zv*#&E5l4k`YWy%i!e+CEIXVfzFcmID(TKBOj<-4F^ZE1VtNsCQtyN?FGP(T9#gN$b zi1zyAR-via(Wj?yJ&j|t9wl?z(%iznyH@{6{ z_f0Joe7e5Nf#`45v{Qzq@@}0cf!BH-R~IhuM_%q0FZLh&n$t_K9ew-@)((t9Py8(? z`X*``+b_&IiR4RIPnRSC4N3A$YgYPG-%xXt>ddgtQ<18?*GT#J{PO0HWREOMf9_#j zb_H>IQ*{Jc^mB2!8UcpLr#;2x0JepSm1?Vz;`6bO@-Xx_1OO|7A6enFxYfya>nvW| z`5Gk&DwLgbD`ruLdi~f8I=AoOa2}uLRkQwnCJhaL4QqcbPtI8~;V;9nq>}G7mY9Dd zK49t=CUA+r)F%A~pnHgHrYxZt&f#ryL>mk9wUFEc@~x2j*?1y#o!*=&>I#9W8_v0( zOZ_9!pSH}u3Ye*|w-l&c$RGot@3#eaE$xCR08l15=mMmZr|MP@3uQb_jg#7eZ9#u_ ze6O%&rW5qt`^1x`|240Kg;-Hei2|F(rI1BD^gP2>XepbwvmsIK<8o^W@b>o<1#eL6 zTI%cT2njB6Q`aXx{Lq({sr}l_w?DVDZ2Ng`x&CXxCwruC1V_?l>wC($AgPB}NKAX$ zBWQ1sk5K&>dvsQS)rz8^^S!?p360wNd!LoJz^#(&Iq}@MOkC2K5FD;#VtdGg@FCE~ z>rG6)=DMX9K}?~=x@^rCPrI)fvcrL832HweWU|dquqP0YZQp;?NnYHmsoR5|VA^He~{l3=l_ZU@m}kh>9Zv3SsBb;HT$~ z&F)10;cl&(YpnHhJ+~ehpA?b?{+6a|{;(WSK)^G*ymQei2V{{yzgZ8;B|hw&?#xb5 zV}_7{=%3V)hUE(a2zj6WG5LzpH^9N)fOx@uLZvMT|K~B%H(aLt8i#~L-3aOFJVSx^ ziB$%iErGXz-ic~*g6llf|De>WBMOU0Qp3hm>@=c&zo=s+5sfZjof^DZ=GN};rbp;{ z_eS(A^zf%Qk(Aq@jqF$mW@mPwOoG}k$5#pw5I}+{?$`CvJO`;WwdD+jxVJ0e{X%o_ z#$elMh31FIT%O9+q8{V62I-fbBGi}^eC@t)$ zZm#^CZ!A5?)pv2AhtD5nc+0E{t4ht$5wyERVvf!+`!AYjw$7#lfr~`tl=B@+zV+Zq z4|~6f#AZoqOhD&n#b;Jr*SRs4FNe!kIc@!#ldE5N1KAxqY4rh6&70J^QCk()MDtuH zHqTL6ao9^o2&|ZvRbHo*ZhKRr1PS*iq>J~FqtA`B8qcqAWzMXg5dztMTppkwZAO&w zCXL{DLJE#R-7c zrOU#kh<`YP?3u8f5o=wDGYdag)G2wr=Kuy#Ca!Y(OFq--GpnE$hG(J^UsjTr2A93> zBDwiy#D#`TM;=Oz@swu;>KOa9jX?nR9~3XgG?si|lmbHV@&LpEpc4jB^5)n>{7jp4 zQ|g{>Slc1a79|1(H8N!Y-jDi;41vAt>G>wKAl)!pb{i3VwRJPnZUDmQ&-ptQW03tDz8=wt3!UcY{J8#$Omdmc%)4@~=|WES z%~$4tMbzvnuEQJHCI@!+;aeoZXb$2lq{7Tk2@M;17RB zhxx73htBB`PT>ohMC;2>=Z8)Kn2plX;b7fNCUAf|2G6N9j_p07&Db z=W4#{V=EGqvr}7))D=i5%czF^+GvxCE!xOl-$MZs{s`i;6?ng+$Tjx12X-l2p1EwB zE*jG>+=ecb$_Leur@L_Qu2u$cdeV$_7(L2542iI_8<2??CA=cZ)iSd=G6U63e5|$v z!|^&8&_2z0YHubY3om4ga1|6s_Ja7BQ-1pz;=qyI-e;nit^ha%Kopwt%p{V%aB_>) z2i)#sZ26vw%8c(m3()Sqg-nsd@Q%u=1c+T{0AUET#35hH)%R_SlDGYfR{DwdB z!x=WL-$$JRSi(fU#C%O^`a+ygV5G-VlIv+Am6@T+D`J)IqfhVQgeCH$iFTjsD`A{E;sz}8v5PC8LEZ+KfI$3GBZB+joVc@$fOBG$A)nQpLNFq^w>v zLkZrTO3Zshrj#m+dF(!Ce3TQgO!B}f;b{4yAiX@Wb`+nX ztB;*gl(2B?iSk6=wBxJ!j};Th|bXHjBynb|cY5iK7CBGBKyx zm*DFD!|xJ=O~ak1g25~vEqC9ptUu=?wVS22qjxos1Ht--=1{PZj`g=JwrM(Z-+TOgO=ySYpm+^d9^RPSr zSTOVG%uK(|3fMpvyo{-ZNNDe#t=$qiES{wV8pgR-KWXTR*(nzQL+fPHuYvW9W#JS( z`cPOe;-GWr{JFDk$MIytRk4Tt-xReW4N9{^Sgt10jpl+RY zlK34kH3#%B-kRj}1t+x0Yu#q0a%Ejlg_>9Ow5FI0tvTx8a|!l#K#^6GxXB#n7}VUqRJAiCBr z*s@4eo%n0v=thT+BB6T3j@tGdoJITlBKqqkFopp1uX|wVf$qoEc^I8@QFUoaS6*?j z-g39Li1Uo3^upUrh_p}uI8iP3sZcTlsIAJW^CP}$&IG&FHaJcmV9&$hzg5+{)g1*! zxMj#J%1{a5NKwRwx%{ehAYO+!wV_6?`V)rv+7$8%M2&@}91Axr<><_}C{*#~0;D^? zs&NnLAwmGi*rPmieN?|U2|*#i5h6Pk^fXd}HBvj$+;4M?5%#rTdGu;YiHC}Y8vzj? zjIxM@<5cZsb29(xLHgH;!AAmyD zI%J^EOcP1GSDwX>iR4}cxU)}KRUmm83RoK`2zlXwFED&mrx^DFc(Lsp(Rs`ck1Ivp zB{*AKAK>6vbxTdS?sSxA%=->{s=r0iuy<`-4sF^)UfY!~nU{-tPYXc)d1n4bZuuIv zE`x=QIqh_XvVn`*4L?JoqjK`LtLb7I*vpUueH|21;2PTI@&f?F9((48kr8nzv8cL6 zvxdKhUoe9jo6X?!0V0<+rQ<$u^PPNs>!ygma+jYudE#|s6NwfoI#VBJkc`u40F@G( zJ<6DaN#93J#fHtm_<;Co`lID5vI+Fom#rABg$WR{Y9d*P9PzXc#g|XJ#j)}G$-Hpq z<=iG4ODiY-DhxH8v5ghZ%@i%2qpdUZHJ^eR)8rnccVIo#jDR}L0)Ca1zoiKBfueQC zyzs0fTfIuC_q{JN$0zz}ppcNKsE$1Fr-UO9(IW7oac=hVYCHydgqnmXjqkb{*b`Ie zZkH85OcMA5C?IYkO^T~nuReN5UiC48Eg}f0;zI;b-iY>yqM0k3O{^qW%cTXtjr;OT z7R7DUpgY4gj`l@+j`e^%#t5M`P-^X)5}@iWWI_kKvvlzHRc$WtpubdohO0ks=S?nP zlA*H_Z-7m)S<8nKq&$_NJ0qxX^^(OVcbqeh~R?$vpN z2q6d}k|?8>2u2%GXAoudLSF9q;X6ri;(1sx3952meP~g!@0ah2 zZuz5&$VqM87ypYY&5r&V?dZFJR%H4_Lm@o0UH`!H>cuHNXcE(oc3qU=-mt-y*(tiLtOymPuj z&Es^_1m6)zUPZYAti0&x$A+d*fe`bdQ{yxNgKKxJ8Ij({UA%f< zvt~Y8j}2>XY-X5RI(9gU<=16lgO}FkWjdg>Qd6izaVcBh(rP~e0Bjup@d99L!vtIO zNwhP^h`8eG|2p%PIQK`i?==XrA+(HSw(}u2^AmlaH+1D1WgpHEGy;V*AIfSP3Dx6D z>Z{bFOHK1i{quTE&nCN0aibotnK=p<>#RaYCTh%QG3HMqfAETGKh>9Jq$qFdq(o9x zmi_AWom4lna`8&l9i$-_rA{0Khe)fe_kmZSE28Buiz|}i{nLe*or&HFxT4+Gx1OiS z^+=*TU|*3VzQwt)_dL%sj=y8O?Xp5)Eqt1DTamlVv)9%(BG>$hTYVg(0H@GvO1;ME zbIe@~U7y*UYQGP~Uuu;PFXwW09>?oLiCAkQh@X39-nt{_y8&3(j13q?UX-m>7Ee4! zV5}Lp<)gDFu}|pD=7|ue{sO+T5k1z(LNN9O6UELvx45m!4y$`Z7oQEuM3`XaF_oC@ z`Ul!c*F@h@DQ}VhjrA(2t-HRJZe!&67F4x%D0a|k{^{P}A!Q~L(Z2B$w*O)b#VP>8 zz}p6NU+0+XIr2bX$VYNI_%(@%skTu1v=ShV988wrY_dWRN&vP=sMUb1!QwrJys6Rs zh9AXpiv_iHiPaaXqB1tXsj6>+U1R}QNr}`#@l2oJa=Hq{Ee8W(>i{wScm_?%|E~{y zaU$zOUz8%~E8O!GjQX)VH?|wANbz;+khma_W#TVYgxG znQTW=;l&YIRe;kHWq0@t6oxTo(+>g=)ifu(D+ElXUans7$fB zXfZ6WmrCa&$II_zj{?5RnvKaEJ{Qw?Q z`klS7EmDhKQp zBZa+Z22g4a@;9J2WV8c@yf)-BPad;N(c~>0UyyEdZ#}c1QpxZ8xsSPs#4T-4W%Y%C zq4Wy83Qy59fP&Mcqh%`hs3_jeo9A5E0uMY^n^Hu^8>vTkl8ppx=N@!#)?5ldl=Ekq zzT6;vEN;02Ez@YSHgFqe|GRLxzjY8ZA`is8#zbJ0M#d84A}mO5NXG^YA0@v`l3CH? zP!%*ohpkBL+{B)kGbpfzaC-`!FALI*z|*d0RFjS$qies<)XR4fv0T(wz-^G%wuVdE z=@hVPFKoIDgN`m)ib~${U^;*&hfd=9f9(p1eROq^Cj3qTN|MB_p3VKpA-kg7o^-13 z;&Va~+o9TnOS26)50tZRN>*LaUHE4cd}r)~=ZX0wZ`RJO@(6>jxXPlwk*ysQB6#eg zF?RY8bIAo?`unQl6y;~37es*93#6avZ;;YKp3Z(`8sG**6t~0S--fSCNc=* z-!OpNq(PCs**gr>zEEI8zAJUA2c5^hcU4{39~1(pP@>cbF{tjlm|^wEde9)CWp(l3 zhqHC%kZ#zssJf_R$JrmR0%K0$b{4NZ(+5$l#n}c7$efFPj+2VIlW;Ob$1rTcTdlRe$1wQ|E!*N%uBWxV3fXSL(<$ZJo8+|JTnOHTCa>X|BJ0DYA1?M$q+#v;#ZRh2 zYjz!?nw@+=-*tnFfc9qyc8KbkwP@H#U5 zC6()>X2C~c+z@JV=YXPW$`Rt@SQ)Kho&0@Z_R`r8sEaVcwmC!Gi(iEYH<{d~R$xK; z;i=@%)g<8V!o_Z31f9ifd0m(cJutO4>uF-#WxS$)z32iiYCeJR-P8#vp`c&D;NRBW z!BzVT*}nT^MDFokwX%BwWAN%o|yj1b8kK%n!!9 z*6WE*leTW1hBVXQxSyW! za+c{5*&%GLe@2WAp^uMAk?_lW!M>Z+YxiCcuNA(ta7Q?AmhlL!9BQM;isdv6F93ev zd_v#saizle*OMa~D+b^|8yi6%o75CU{wv&nUUi;;Bg8iSfc@7)i1^v7C+we`iem$_ zIy-XjLZ~v3iO%*>&%cMh&NKe(Y@(l!T9ofQd;{$D@T_w5QX;~suwz$qd=99Zq}~>( zON#J_JV?5tGt#;Db2TJk>qY;K-~K{e^`~D7f7@bHM6=j$^X8vX zJ7vE60Wy=lJNn+-u%5d@^iKHfqx*N=Px8J7aO;^gV7UU#WniOHFrI$B*NOse@1f*Y z>P6H^4OD%3iEKBJ!rA3Lv(IGIE4M@)OTkGAEuD{Qym5K%L$ry+4i`@wo}uk_*b zIj*6b*ItH2v21sIQ&?AiPYsBlD;gRtr!ZnTi+n_3G-=n^7I?y4^#Jfw$@FJ(d;y!` zqC9_J52ohrWT0;B4sS^}&3%S0erne^cuUp}?I?W!3 zp{TEQHzJP`BS{Xd9_2rF9g@>I>c0<;SRHz2xcO&p+Fp)mUez^$1+fgF8sjzF`Sj8; zy)uGh*+3(8flVv>CO^S&b@NF(xf>#c)?&0E?vsS>P>j**I2G@%pRsrs>4jNINf)4P zVIx!a?x%>b>w;`WhY!Y^js~ zIfKvzBl_G|co&z#?w=;c;*P3n1Zcs{s@T)d=e7yEPMmYkNp2#UMk0IlLpfv}uvK6I$}? zbsDHfT@6^XK?q60Bot^8;SeNGf|WRAKFsUtqMCNIEuW7W61Wir3;4MX8|hmZ#8gsjIzB z=nu&iBxc}LXQ`z%gVYxqDt6kvNoGmwIZSchk|R3?M!~-$yRRTVrx73p-u@h84K%?{ zx_RB2B_@je;4*Ds&$X(1(4fI8Hw*7lFL7|zNvT-r)4%uOiK{uk4f$2|T#>eh9n5s8 zQhIbVEGGOD-Np8v@kivUbS*;U0MbY%ryO@EU}nt3Xlq>MXFLA&_t2WsP7@xfLN}tl zrLEMYdg0EJq`m^<2@_C50Uo4c1@^fvyCDcfP(GW{5Px4L6kUz@Yv_0}TB1OLjINuv#VTe&n( zc0*)Ufz`zre?zs)<-NEe7U++#H17Y~-9>ZyXqOR!jNTr%8Sb1ac2MAdo|?~m!OIBD zZCHRWRf%wvsEJs@MUg6ouZ-`WY-_>!7;nS@V|p58mSBPTFtNfAiIpF2N=vznI)aUP z;xZ>NM16OaB6ik~Z72vbn863?^52YVl++^cE^pSev8MKhpYZIDXJ`^FKaDUN?w}}C z)G|z!ShH~bZd06~&GnRDX|n!BIYL`_kNOXgCOu-{Ql`v0o{hPd=ioUbbXU)2ma`oa zl7^t{HC&Ozc6xaS+B7`y);nW}Wl-_kX~`ualL4pyyGS5<(+Y;R`+Z@q? zSEwFUR|=>c=7O;aw^V?#d~SSiy086T1VblZ+r{_^ z(7U)eyypHnmGX4;>F>cnvAp`<^>t3RU{Nz;E(B|Ki3q>Pz(XOpA~jE+-U49_FQ2;h zPiA-B(!%7YK$rBDJ#Bb^LGmA7KTDP*m83zjo!BGi;)IuZR@@gCpOSgKMnw=^Iil$v ztmyj-SeumV=c?ls{5t&fE!K&@)SH`@}XV*|`$yW?^^5KiBW&Vbq$$ zvHKVo#B!y6i{@kDTHf%^l4}$flh@Z~%ofp{$%80FSD85%+H(XOS@VqR1hZnE#SZ@n z=#n`p1fa&t?zp{+ebQr{ml1wgRV9jGSRAMeU%dBfB99mg-697~le2(@pZFWwddXdG z&iK{ZiijoSP}~Dl`P-Y$!%!H8b=Of_vr2RmN9$TFd7^HY`3mWDKP($#fQ7@>R$nMq zvivzlO(?imFQ$qibb%B9xZ6+5SJRJf3?)dyL%WC~JayfV#SPJZ&5R;p? z6Kj{#Rd5(C*Ca2d5zZdO$T{n%HwIyUJ2fQxXsVXdj!yaQAbz;jp}~mYMl(&d0DY98 zAjIECx>AV^*q*2U)0S5GGI}B764Jt(XK>c>SN7y6;?-`)_}M~}T;d<_njVM`aZq zc#nZQic(y#d4}*c zb>2SthSJ~Sa8vKu4h&QCUtga%@OCgK{xii@Bb?Gx?a}c&*qOTz|~QQ zkh&%AX#`ET%#0&tm~se9O?y9M{%tC5-%`_>Ps}^MG_lvcXqd9Xr-e}Ew|W1O!t#jP zx8riCHr-$Txv(rP_%r3H8%~$Mt_HZOyg2QYD^jbLYa2Xv+6}PZKG(_$GRj6iNt9sO zT^zfM)?Kcinq9v6%{0sP#0~h_Sgp+B@PcO8?p|SrGNL z?YTE|zWq(QVlA%ecqN$T6h>0BRZ1F^z{31uW)W3J$3MsNV8%y4G5`wN(h4VZfqjw$ zbv}@v(;k%Lbwf6$piwYes?DF#A3ZBa*=I5%wqh2gc_rx_wfSkM(|T-}zqP~BF2I!A zijbC<JC7{{Xpq1^SE;tl6L45+sp#P3<-2BG*AS8Pbq0Ya*GYJe)ncxS}O&#`#1O??`)lH|bw+CHwY4wxZIf zCvQG?M62R)7JPQqOh;qj&G(O%b>+?@gf8yWorKy_syO)k#v`p+63X_cAHB?ol)dgw zZ2ESWm1U~SUEMAw{`dK>RVFU9t{t3Kq4=*);T^ijr6f(7BaDKOMEC^X7aL>~pr86W sCKX9gdQo?BX{0a3mOc4<^@ilPNIS>W2Qm*Lp)9~a=e~B0=HuA^0r-4m@c;k- literal 0 HcmV?d00001 diff --git a/docs/sponsor_logos/red_hat.png b/docs/sponsor_logos/red_hat.png new file mode 100644 index 0000000000000000000000000000000000000000..b8c28b5d7b094b0531ea8ac7ed068da700513dd2 GIT binary patch literal 20118 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 R_uw*6=R(4QI|Jjt{}&3q{`~*| literal 0 HcmV?d00001 From 7d44f6873dbdf56da3483971d1f33e06afbad5cd Mon Sep 17 00:00:00 2001 From: Harsh Mishra Date: Wed, 29 Dec 2021 21:15:24 +0530 Subject: [PATCH 1605/4969] DOCS: Remove references to Atlassian for LocalStack (#4796) Co-authored-by: Kevin Wittek Co-authored-by: Richard North --- docs/modules/localstack.md | 4 ++-- .../containers/localstack/LocalStackContainer.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index b6058508ddb..1585c504cff 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -1,6 +1,6 @@ -# Localstack Module +# LocalStack Module -Testcontainers module for the Atlassian's [LocalStack](https://github.com/localstack/localstack), 'a fully functional local AWS cloud stack'. +Testcontainers module for [LocalStack](http://localstack.cloud/), 'a fully functional local AWS cloud stack', to develop and test your cloud and serverless apps without actually using the cloud. ## Usage example diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index fe3ea6ab34f..dd03a4206e0 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -25,7 +25,7 @@ import java.util.stream.Collectors; /** - *

Container for Atlassian Labs Localstack, 'A fully functional local AWS cloud stack'.

+ *

Container for LocalStack, 'A fully functional local AWS cloud stack'.

*

{@link LocalStackContainer#withServices(Service...)} should be used to select which services * are to be launched. See {@link Service} for available choices. It is advised that * {@link LocalStackContainer#getEndpointConfiguration(Service)} and From 5897437b33a385778e7e193f1eaed14524a2b8ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:26 +0000 Subject: [PATCH 1606/4969] Bump tomcat-jdbc from 10.0.13 to 10.0.14 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.13 to 10.0.14. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 7dd1023b95a..46088aa45ac 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.13' + api 'org.apache.tomcat:tomcat-jdbc:10.0.14' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.27' } From e90885ee0c818b0d39a5d3ad82a1b1e02701e72b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:27 +0000 Subject: [PATCH 1607/4969] Bump clickhouse-jdbc from 0.3.1-patch to 0.3.2 in /modules/clickhouse Bumps [clickhouse-jdbc](https://github.com/ClickHouse/clickhouse-jdbc) from 0.3.1-patch to 0.3.2. - [Release notes](https://github.com/ClickHouse/clickhouse-jdbc/releases) - [Changelog](https://github.com/ClickHouse/clickhouse-jdbc/blob/master/CHANGELOG) - [Commits](https://github.com/ClickHouse/clickhouse-jdbc/compare/v0.3.1-patch...v0.3.2) --- updated-dependencies: - dependency-name: ru.yandex.clickhouse:clickhouse-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/clickhouse/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/clickhouse/build.gradle b/modules/clickhouse/build.gradle index 39b269d794b..914ee7efbd4 100644 --- a/modules/clickhouse/build.gradle +++ b/modules/clickhouse/build.gradle @@ -5,5 +5,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'ru.yandex.clickhouse:clickhouse-jdbc:0.3.1-patch' + testImplementation 'ru.yandex.clickhouse:clickhouse-jdbc:0.3.2' } From 5c5d4df5772e193995916f0328d8747ecf14aea9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:28 +0000 Subject: [PATCH 1608/4969] Bump jedis from 3.7.0 to 4.0.1 in /modules/junit-jupiter Bumps [jedis](https://github.com/redis/jedis) from 3.7.0 to 4.0.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v3.7.0...v4.0.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7907b30e386..ad0d8d3218a 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:3.7.0' + testImplementation 'redis.clients:jedis:4.0.1' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testImplementation ('org.mockito:mockito-core:4.1.0') { exclude(module: 'hamcrest-core') From 107bf88af7054f48f94b79287b479acd826d25e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:28 +0000 Subject: [PATCH 1609/4969] Bump java-client from 3.2.3 to 3.2.4 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.2.3 to 3.2.4. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.2.3...java-client-3.2.4) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 772876b7bf1..ea720ca3725 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') - testImplementation 'com.couchbase.client:java-client:3.2.3' + testImplementation 'com.couchbase.client:java-client:3.2.4' testImplementation 'org.awaitility:awaitility:4.1.1' } From d7e28d23fffcfda2008a8963a615e20f4e3b1dcc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:29 +0000 Subject: [PATCH 1610/4969] Bump mockito-core from 4.1.0 to 4.2.0 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 4.1.0 to 4.2.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.1.0...v4.2.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 950f73c1d7b..859bdf1fdde 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -93,7 +93,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.14.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' - testImplementation ('org.mockito:mockito-core:4.1.0') { + testImplementation ('org.mockito:mockito-core:4.2.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 05923501981e3006e02f61c2179963935407e86a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:30 +0000 Subject: [PATCH 1611/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.122 to 1.12.131. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.122...1.12.131) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index fb4edcf1576..d891ed5b4d9 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.122' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.100' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.131' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.131' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 97eb8edf78cb4756e2ad22547bdec68f7f2a862a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:31 +0000 Subject: [PATCH 1612/4969] Bump mockito-core from 4.1.0 to 4.2.0 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 4.1.0 to 4.2.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.1.0...v4.2.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 7907b30e386..01e971407b8 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:3.7.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:4.1.0') { + testImplementation ('org.mockito:mockito-core:4.2.0') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.21.0' From 38ca320ff7700675c07cf6b6b3cc9e137c0aedb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:32 +0000 Subject: [PATCH 1613/4969] Bump jedis from 3.7.0 to 4.0.1 in /core Bumps [jedis](https://github.com/redis/jedis) from 3.7.0 to 4.0.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v3.7.0...v4.0.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 950f73c1d7b..6075f6d3089 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -89,7 +89,7 @@ dependencies { shaded 'org.zeroturnaround:zt-exec:1.12' testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' - testImplementation 'redis.clients:jedis:3.7.0' + testImplementation 'redis.clients:jedis:4.0.1' testImplementation 'com.rabbitmq:amqp-client:5.14.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' From 7be241be812c80b49bfbbf9a6f31b7f3f528431e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:33 +0000 Subject: [PATCH 1614/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.15.2 to 7.16.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.15.2...v7.16.2) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index ad1446a0f0f..7b92dc8279d 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.15.2" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2" testImplementation "org.elasticsearch.client:transport:7.15.2" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 39322a75e1a02c79ab2110f78a13f0cbbf878592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:35 +0000 Subject: [PATCH 1615/4969] Bump snakeyaml from 1.29 to 1.30 in /core Bumps [snakeyaml](https://bitbucket.org/snakeyaml/snakeyaml) from 1.29 to 1.30. - [Commits](https://bitbucket.org/snakeyaml/snakeyaml/branches/compare/snakeyaml-1.30..snakeyaml-1.29) --- updated-dependencies: - dependency-name: org.yaml:snakeyaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 950f73c1d7b..776c519f6b2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -82,7 +82,7 @@ dependencies { api 'com.github.docker-java:docker-java-transport-zerodep' - shaded "org.yaml:snakeyaml:1.29" + shaded "org.yaml:snakeyaml:1.30" shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From 86b37183cd103f6677d16626e5c03a02f2c4db4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:35 +0000 Subject: [PATCH 1616/4969] Bump s3 from 2.17.72 to 2.17.102 in /modules/localstack Bumps s3 from 2.17.72 to 2.17.102. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 4b62d30742f..541a33405ca 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.124' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.122' - testImplementation 'software.amazon.awssdk:s3:2.17.72' + testImplementation 'software.amazon.awssdk:s3:2.17.102' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 514226ae9cae9aaecd9d8a65f54cc517a328c7f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:35 +0000 Subject: [PATCH 1617/4969] Bump aws-java-sdk-sqs from 1.12.124 to 1.12.131 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.124 to 1.12.131. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.124...1.12.131) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 4b62d30742f..4adb5264616 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.124' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.131' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.122' testImplementation 'software.amazon.awssdk:s3:2.17.72' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From fbb031eb93844a6d968eb326dd13da1dcf68ea50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:38 +0000 Subject: [PATCH 1618/4969] Bump aws-java-sdk-s3 from 1.12.122 to 1.12.131 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.122 to 1.12.131. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.122...1.12.131) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 4b62d30742f..326778688ab 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.122' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.131' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.124' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.122' From a46d0a47bbd7a89a1f5162513a6adcf89c4f0f59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:56 +0000 Subject: [PATCH 1619/4969] Bump jedis from 3.0.1 to 4.0.1 in /modules/toxiproxy Bumps [jedis](https://github.com/redis/jedis) from 3.0.1 to 4.0.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/jedis-3.0.1...v4.0.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/toxiproxy/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index cad4b6b71f3..e055f5a52c5 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.5' - testImplementation 'redis.clients:jedis:3.0.1' + testImplementation 'redis.clients:jedis:4.0.1' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' testImplementation project(':test-support') From 3aabcf2fd9bc8a3fff29c08ed5cc3e204b51016c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:00:59 +0000 Subject: [PATCH 1620/4969] Bump gradle-update/update-gradle-wrapper-action from 1.0.15 to 1.0.16 Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 1.0.15 to 1.0.16. - [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases) - [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/a116d8b533be6c4e71a8b3c3871b7344ca72bf12...f31ab392a9d75029f9fd0883d8d6745c0139a006) --- updated-dependencies: - dependency-name: gradle-update/update-gradle-wrapper-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 08fbc91d00c..612aec0b406 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@a116d8b533be6c4e71a8b3c3871b7344ca72bf12 # v1.0.13 + uses: gradle-update/update-gradle-wrapper-action@f31ab392a9d75029f9fd0883d8d6745c0139a006 # v1.0.13 with: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies From cf2a23d4cf0c5ad151ac7ced12796edc075a51c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:01:00 +0000 Subject: [PATCH 1621/4969] Bump solr-solrj from 8.10.1 to 8.11.1 in /examples Bumps solr-solrj from 8.10.1 to 8.11.1. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 965a40b35a8..c0c69300377 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.22" annotationProcessor "org.projectlombok:lombok:1.18.22" - implementation 'org.apache.solr:solr-solrj:8.10.1' + implementation 'org.apache.solr:solr-solrj:8.11.1' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From 132476d4d85a044321ab288296c2dea4808890c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:01:03 +0000 Subject: [PATCH 1622/4969] Bump actions/setup-java from 2.4.0 to 2.5.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2.4.0 to 2.5.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2.4.0...v2.5.0) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 7403b53fd8e..d7351605e6d 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -17,7 +17,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.4.0 + - uses: actions/setup-java@v2.5.0 with: java-version: '8.0.302' distribution: temurin @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.4.0 + - uses: actions/setup-java@v2.5.0 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 990ffa666b9..0fd59f892f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.4.0 + - uses: actions/setup-java@v2.5.0 with: java-version: '8.0.302' distribution: temurin @@ -51,7 +51,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.4.0 + - uses: actions/setup-java@v2.5.0 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b727567ecb..d9026eb2257 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.4.0 + - uses: actions/setup-java@v2.5.0 with: java-version: '8.0.302' distribution: temurin From f0ddacf7150fe3d211b67ad97a9bb73abfa4361a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:01:07 +0000 Subject: [PATCH 1623/4969] Bump peter-evans/create-pull-request from 3.11.0 to 3.12.0 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 3.11.0 to 3.12.0. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/67df31e08a133c6a77008b89689677067fef169e...dcd5fd746d53dd8de555c0f10bca6c35628be47a) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 790dad57188..418598f230d 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -17,7 +17,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@67df31e08a133c6a77008b89689677067fef169e # v3.10.1 + uses: peter-evans/create-pull-request@dcd5fd746d53dd8de555c0f10bca6c35628be47a # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From 2c26b68bbc07d1f0706d97709e28eb6c13ed60d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:01:08 +0000 Subject: [PATCH 1624/4969] Bump jedis from 3.7.0 to 4.0.1 in /examples Bumps [jedis](https://github.com/redis/jedis) from 3.7.0 to 4.0.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v3.7.0...v4.0.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 8f30256e2da..7f81bbf4c57 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:3.7.0' + implementation 'redis.clients:jedis:4.0.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index b6ac1f4ddd6..5a71ca3d2ff 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:3.7.0' + implementation 'redis.clients:jedis:4.0.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index a8b10171d99..35f7483113f 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:3.7.0' + implementation 'redis.clients:jedis:4.0.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From 62fdbda74efd649278cee380d13d025ec8807457 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:01:10 +0000 Subject: [PATCH 1625/4969] Bump com.gradle.enterprise.gradle.plugin from 3.7.2 to 3.8 in /examples Bumps com.gradle.enterprise.gradle.plugin from 3.7.2 to 3.8. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 13645d5f5ff..22b279b1573 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.7.2" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8" } } From a3e264a0dfe858c1417a32fc135a5cb16cf6f3c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:01:16 +0000 Subject: [PATCH 1626/4969] Bump json from 20210307 to 20211205 in /examples Bumps [json](https://github.com/douglascrockford/JSON-java) from 20210307 to 20211205. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 091a35ae042..dfdc749d191 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'com.squareup.okhttp3:okhttp:4.9.3' - implementation 'org.json:json:20210307' + implementation 'org.json:json:20211205' testImplementation 'org.postgresql:postgresql:42.3.1' testImplementation 'ch.qos.logback:logback-classic:1.2.7' testImplementation 'org.testcontainers:postgresql' From 8374167877213329ccabdec1fb317c25592e2f1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:01:19 +0000 Subject: [PATCH 1627/4969] Bump org.jetbrains.kotlin.jvm from 1.6.0 to 1.6.10 in /examples Bumps org.jetbrains.kotlin.jvm from 1.6.0 to 1.6.10. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index a37b63e6557..e0028d26b4a 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.6.1" - id("org.jetbrains.kotlin.jvm") version "1.6.0" + id("org.jetbrains.kotlin.jvm") version "1.6.10" id("org.jetbrains.kotlin.plugin.spring") version "1.6.0" } From 23cbeb30d04a634c6c512e56446c37bf5c10664c Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 4 Jan 2022 09:27:50 +0100 Subject: [PATCH 1628/4969] Fix for API changes in Jedis Use `long` primitive instead of boxed type. --- .../junit/jupiter/inheritance/InheritedTests.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java index 720c31cf794..adeaf58675c 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java @@ -12,15 +12,15 @@ class InheritedTests extends AbstractTestBase { @Test void step1() { - assertEquals(1, redisPerClass.getJedis().incr("key").longValue()); - assertEquals(1, redisPerTest.getJedis().incr("key").longValue()); - assertEquals(1, myRedis.getJedis().incr("key").longValue()); + assertEquals(1, redisPerClass.getJedis().incr("key")); + assertEquals(1, redisPerTest.getJedis().incr("key")); + assertEquals(1, myRedis.getJedis().incr("key")); } @Test void step2() { - assertEquals(2, redisPerClass.getJedis().incr("key").longValue()); - assertEquals(1, redisPerTest.getJedis().incr("key").longValue()); - assertEquals(1, myRedis.getJedis().incr("key").longValue()); + assertEquals(2, redisPerClass.getJedis().incr("key")); + assertEquals(1, redisPerTest.getJedis().incr("key")); + assertEquals(1, myRedis.getJedis().incr("key")); } } From f89decebb35e6564495b084f6a5e826690678e95 Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Tue, 4 Jan 2022 11:15:13 +0100 Subject: [PATCH 1629/4969] Upgrade Neo4j server and driver dependencies. (#4789) * Upgrade Neo4j Java Driver for testing to 4.4.2. * Upgrade Neo4j to 4.4.1. * Default to 4.4 instead concrete 4.4.1. * Throw exception if using database copy with Neo4j version !=3. * More specific javadoc and version check. * Adjust documentation for copy database functionality. * More robust check for defined image version. --- docs/modules/databases/neo4j.md | 3 ++ modules/neo4j/build.gradle | 6 +-- .../containers/Neo4jContainer.java | 29 +++++++++++- .../Neo4jContainerJUnitIntegrationTest.java | 8 ++-- .../containers/Neo4jContainerTest.java | 47 ++++++++++++++----- .../containers/Neo4jTestImages.java | 2 +- .../example-container-license-acceptance.txt | 2 +- 7 files changed, 76 insertions(+), 21 deletions(-) diff --git a/docs/modules/databases/neo4j.md b/docs/modules/databases/neo4j.md index 702f9cc40d7..0310d37d817 100644 --- a/docs/modules/databases/neo4j.md +++ b/docs/modules/databases/neo4j.md @@ -139,6 +139,9 @@ public class ExampleTest { } ``` +!!! note +The `withDatabase` method will only work with Neo4j 3.5 and throw an exception if used in combination with a newer version. + ## Choose your Neo4j license If you need the Neo4j enterprise license, you can declare your Neo4j container like this: diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 51cc625dc9d..cdc727921b4 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -18,8 +18,8 @@ sourceSets { task customNeo4jPluginJar(type: Jar) { from sourceSets.customNeo4jPlugin.output - archiveName = "hello-world.jar" - destinationDir = customNeo4jPluginDestinationDir + archiveFileName = "hello-world.jar" + destinationDirectory = customNeo4jPluginDestinationDir inputs.files(sourceSets.customNeo4jPlugin.java.srcDirs) outputs.cacheIf { true } @@ -33,6 +33,6 @@ dependencies { api project(":testcontainers") - testImplementation "org.neo4j.driver:neo4j-java-driver:1.7.5" + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.2' testImplementation 'org.assertj:assertj-core:3.21.0' } diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index 7890bf5dcad..f844df3f945 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -10,6 +10,7 @@ import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.LicenseAcceptance; import org.testcontainers.utility.MountableFile; @@ -30,7 +31,7 @@ public class Neo4jContainer> extends GenericContaine /** * The default tag (version) to use. */ - private static final String DEFAULT_TAG = "3.5.0"; + private static final String DEFAULT_TAG = "4.4"; private static final String ENTERPRISE_TAG = DEFAULT_TAG + "-enterprise"; /** @@ -194,6 +195,8 @@ public S withoutAuthentication() { * If you want to map your database into the container instead of copying them, please use {@code #withClasspathResourceMapping}, * but this will only work when your test does not run in a container itself. *
+ * Note: This method only works with Neo4j 3.5. + *
* Mapping would work like this: *

      *      @Container
@@ -202,9 +205,14 @@ public S withoutAuthentication() {
      * 
* * @param graphDb The graph.db folder to copy into the container + * @throws IllegalArgumentException If the database version is not 3.5. * @return This container. */ public S withDatabase(MountableFile graphDb) { + if (!isNeo4jDatabaseVersionSupportingDbCopy()) { + throw new IllegalArgumentException( + "Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); + } return withCopyFileToContainer(graphDb, "/data/databases/graph.db"); } @@ -250,4 +258,23 @@ private static String formatConfigurationKey(String plainConfigKey) { .replaceAll("_", "__") .replaceAll("\\.", "_")); } + + private boolean isNeo4jDatabaseVersionSupportingDbCopy() { + String usedImageVersion = DockerImageName.parse(getDockerImageName()).getVersionPart(); + ComparableVersion usedComparableVersion = new ComparableVersion(usedImageVersion); + + boolean versionSupportingDbCopy = + usedComparableVersion.isLessThan("4.0") && usedComparableVersion.isGreaterThanOrEqualTo("2"); + + if (versionSupportingDbCopy) { + return true; + } + if (!usedComparableVersion.isSemanticVersion()) { + logger().warn("Version {} is not a semantic version. The function \"withDatabase\" will fail.", usedImageVersion); + logger().warn("Copying databases is only supported for Neo4j versions 3.5.x"); + + } + + return false; + } } diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java index 5a67674cbe8..ad6ccad8281 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java @@ -2,10 +2,10 @@ import org.junit.ClassRule; import org.junit.Test; -import org.neo4j.driver.v1.AuthTokens; -import org.neo4j.driver.v1.Driver; -import org.neo4j.driver.v1.GraphDatabase; -import org.neo4j.driver.v1.Session; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Session; import java.util.Collections; diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java index 6a32dac0af0..fcfda6f6873 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java @@ -1,13 +1,14 @@ package org.testcontainers.containers; +import org.assertj.core.api.Assertions; import org.junit.Test; -import org.neo4j.driver.v1.AuthToken; -import org.neo4j.driver.v1.AuthTokens; -import org.neo4j.driver.v1.Driver; -import org.neo4j.driver.v1.GraphDatabase; -import org.neo4j.driver.v1.Record; -import org.neo4j.driver.v1.Session; -import org.neo4j.driver.v1.StatementResult; +import org.neo4j.driver.AuthToken; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Record; +import org.neo4j.driver.Result; +import org.neo4j.driver.Session; import org.testcontainers.utility.MountableFile; import java.util.Collections; @@ -45,7 +46,7 @@ public void shouldDisableAuthentication() { @Test public void shouldCopyDatabase() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:3.5.30") .withDatabase(MountableFile.forClasspathResource("/test-graph.db")) ) { neo4jContainer.start(); @@ -53,13 +54,37 @@ public void shouldCopyDatabase() { Driver driver = getDriver(neo4jContainer); Session session = driver.session() ) { - StatementResult result = session.run("MATCH (t:Thing) RETURN t"); + Result result = session.run("MATCH (t:Thing) RETURN t"); assertThat(result.list().stream().map(r -> r.get("t").get("name").asString())) .containsExactlyInAnyOrder("Thing", "Thing 2", "Thing 3", "A box"); } } } + @Test + public void shouldFailOnCopyDatabaseForDefaultNeo4j4Image() { + Assertions.assertThatIllegalArgumentException() + .isThrownBy(() -> new Neo4jContainer<>() + .withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) + .withMessage("Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); + } + + @Test + public void shouldFailOnCopyDatabaseForCustomNeo4j4Image() { + Assertions.assertThatIllegalArgumentException() + .isThrownBy(() -> new Neo4jContainer<>("neo4j:4.4.1") + .withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) + .withMessage("Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); + } + + @Test + public void shouldFailOnCopyDatabaseForCustomNonSemverNeo4j4Image() { + Assertions.assertThatIllegalArgumentException() + .isThrownBy(() -> new Neo4jContainer<>("neo4j:latest") + .withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) + .withMessage("Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); + } + @Test public void shouldCopyPlugins() { try ( @@ -93,7 +118,7 @@ public void shouldCopyPlugin() { } private static void assertThatCustomPluginWasCopied(Session session) { - StatementResult result = session.run("RETURN ac.simons.helloWorld('Testcontainers') AS greeting"); + Result result = session.run("RETURN ac.simons.helloWorld('Testcontainers') AS greeting"); Record singleRecord = result.single(); assertThat(singleRecord).isNotNull(); assertThat(singleRecord.get("greeting").asString()).isEqualTo("Hello, Testcontainers"); @@ -103,7 +128,7 @@ private static void assertThatCustomPluginWasCopied(Session session) { public void shouldCheckEnterpriseLicense() { assumeThat(Neo4jContainerTest.class.getResource(ACCEPTANCE_FILE_LOCATION)).isNull(); - String expectedImageName = "neo4j:3.5.0-enterprise"; + String expectedImageName = "neo4j:4.4-enterprise"; assertThatExceptionOfType(IllegalStateException.class) .isThrownBy(() -> new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE).withEnterpriseEdition()) diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java index 2cab24baf2b..aee6f29fc5f 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java @@ -3,5 +3,5 @@ import org.testcontainers.utility.DockerImageName; public interface Neo4jTestImages { - DockerImageName NEO4J_TEST_IMAGE = DockerImageName.parse("neo4j:3.5.0"); + DockerImageName NEO4J_TEST_IMAGE = DockerImageName.parse("neo4j:4.4.1"); } diff --git a/modules/neo4j/src/test/resources/example-container-license-acceptance.txt b/modules/neo4j/src/test/resources/example-container-license-acceptance.txt index 9b92a79c737..e1f78f2d982 100644 --- a/modules/neo4j/src/test/resources/example-container-license-acceptance.txt +++ b/modules/neo4j/src/test/resources/example-container-license-acceptance.txt @@ -1 +1 @@ -neo4j:3.5.0-enterprise +neo4j:4.4.1-enterprise From 04d5247dc2d841dceceaa34e1e26a479ee73487e Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Tue, 4 Jan 2022 11:17:09 +0100 Subject: [PATCH 1630/4969] [couchbase] Explicitly configure service quotas (and allow customization). (#4802) This changeset explicitly configures the service memory quotas to their documented limits by default. This ensures that if a service is enabled, it does not consume more memory than absolutely needed. This is important because some services (like analytics) try to grab memory available which is good for production but of limited use in a testcontainers setting. A new API is also added which allows to customize the memory quota for each service should the test case require more than the minimum (which for most services is 256MB anyways). --- .../couchbase/CouchbaseContainer.java | 57 +++++++++++ .../couchbase/CouchbaseService.java | 97 ++++++++++++------- 2 files changed, 120 insertions(+), 34 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 9ef8e99e19d..5007a8d5ccf 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -36,8 +36,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -100,6 +102,11 @@ public class CouchbaseContainer extends GenericContainer { CouchbaseService.INDEX ); + /** + * Holds the custom service quotas if configured by the user. + */ + private final Map customServiceQuotas = new HashMap<>(); + private final List buckets = new ArrayList<>(); private boolean isEnterprise = false; @@ -158,6 +165,26 @@ public CouchbaseContainer withEnabledServices(final CouchbaseService... enabled) return this; } + /** + * Configures a custom memory quota for a given service. + * + * @param service the service to configure the quota for. + * @param quotaMb the memory quota in MB. + * @return this {@link CouchbaseContainer} for chaining purposes. + */ + public CouchbaseContainer withServiceQuota(final CouchbaseService service, final int quotaMb) { + checkNotRunning(); + if (!service.hasQuota()) { + throw new IllegalArgumentException("The provided service (" + service + ") has no quota to configure"); + } + if (quotaMb < service.getMinimumQuotaMb()) { + throw new IllegalArgumentException("The custom quota (" + quotaMb + ") must not be smaller than the " + + "minimum quota for the service (" + service.getMinimumQuotaMb() + ")"); + } + this.customServiceQuotas.put(service, quotaMb); + return this; + } + /** * Enables the analytics service which is not enabled by default. * @@ -262,6 +289,7 @@ protected void containerIsStarting(final InspectContainerResponse containerInfo) timePhase("initializeIsEnterprise", this::initializeIsEnterprise); timePhase("renameNode", this::renameNode); timePhase("initializeServices", this::initializeServices); + timePhase("setMemoryQuotas", this::setMemoryQuotas); timePhase("configureAdminUser", this::configureAdminUser); timePhase("configureExternalPorts", this::configureExternalPorts); @@ -341,6 +369,35 @@ private void initializeServices() { checkSuccessfulResponse(response, "Could not enable couchbase services"); } + /** + * Sets the memory quotas for each enabled service. + *

+ * If there is no explicit custom quota defined, the default minimum quota will be used. + */ + private void setMemoryQuotas() { + logger().debug("Custom service memory quotas: {}", customServiceQuotas); + + final FormBody.Builder quotaBuilder = new FormBody.Builder(); + for (CouchbaseService service : enabledServices) { + if (!service.hasQuota()) { + continue; + } + + int quota = customServiceQuotas.getOrDefault(service, service.getMinimumQuotaMb()); + if (CouchbaseService.KV.equals(service)) { + quotaBuilder.add("memoryQuota", Integer.toString(quota)); + } else { + quotaBuilder.add(service.getIdentifier() + "MemoryQuota", Integer.toString(quota)); + } + } + + @Cleanup Response response = doHttpRequest( + MGMT_PORT, "/pools/default", "POST", quotaBuilder.build(), false + ); + + checkSuccessfulResponse(response, "Could not configure service memory quotas"); + } + /** * Configures the admin user on the couchbase node. *

diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java index 57d3e37fcf2..a314bd5ccfc 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java @@ -21,38 +21,67 @@ */ public enum CouchbaseService { - /** - * Key-Value service. - */ - KV("kv"), - - /** - * Query (N1QL) service. - */ - QUERY("n1ql"), - - /** - * Search (FTS) service. - */ - SEARCH("fts"), - - /** - * Indexing service (needed if QUERY is also used!). - */ - INDEX("index"), - - /** - * Analytics service. - */ - ANALYTICS("cbas"); - - private final String identifier; - - CouchbaseService(String identifier) { - this.identifier = identifier; - } - - String getIdentifier() { - return identifier; - } + /** + * Key-Value service. + */ + KV("kv", 256), + + /** + * Query (N1QL) service. + *

+ * Note that the query service has no memory quota, so it is set to 0. + */ + QUERY("n1ql", 0), + + /** + * Search (FTS) service. + */ + SEARCH("fts", 256), + + /** + * Indexing service (needed if QUERY is also used!). + */ + INDEX("index", 256), + + /** + * Analytics service. + */ + ANALYTICS("cbas", 1024); + + private final String identifier; + + private final int minimumQuotaMb; + + CouchbaseService(final String identifier, final int minimumQuotaMb) { + this.identifier = identifier; + this.minimumQuotaMb = minimumQuotaMb; + } + + /** + * Returns the internal service identifier. + * + * @return the internal service identifier. + */ + String getIdentifier() { + return identifier; + } + + /** + * Returns the minimum quota for the service in MB. + * + * @return the minimum quota in MB. + */ + int getMinimumQuotaMb() { + return minimumQuotaMb; + } + + /** + * Returns true if the service has a quota that needs to be applied. + * + * @return true if its quota needs to be applied. + */ + boolean hasQuota() { + return minimumQuotaMb > 0; + } + } From f257ba3c1f628e01d6fe9612fd6f2dd29f9be521 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 11:44:24 +0000 Subject: [PATCH 1631/4969] Bump transport from 7.15.2 to 7.16.2 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.15.2 to 7.16.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.15.2...v7.16.2) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 7b92dc8279d..3f517353f24 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2" - testImplementation "org.elasticsearch.client:transport:7.15.2" + testImplementation "org.elasticsearch.client:transport:7.16.2" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From f8d4f6ad51b7b4aad93b7989de0df0cac4d0700b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 11:44:29 +0000 Subject: [PATCH 1632/4969] Bump logback-classic from 1.2.7 to 1.2.10 in /examples Bumps logback-classic from 1.2.7 to 1.2.10. --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 051e82f67d7..ff03cee54cc 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.7' + testImplementation 'ch.qos.logback:logback-classic:1.2.10' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 290a4295368..a686fc171c2 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:3.0.0' testImplementation 'org.assertj:assertj-core:3.21.0' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.7' + testImplementation 'ch.qos.logback:logback-classic:1.2.10' } diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index dfdc749d191..1d6c29b16eb 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'org.json:json:20211205' testImplementation 'org.postgresql:postgresql:42.3.1' - testImplementation 'ch.qos.logback:logback-classic:1.2.7' + testImplementation 'ch.qos.logback:logback-classic:1.2.10' testImplementation 'org.testcontainers:postgresql' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 7f81bbf4c57..e1b1f5d639a 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'ch.qos.logback:logback-classic:1.2.7' + testImplementation 'ch.qos.logback:logback-classic:1.2.10' testImplementation 'org.testng:testng:7.4.0' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 5a71ca3d2ff..38b3804b4b8 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -13,6 +13,6 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testImplementation 'ch.qos.logback:logback-classic:1.2.7' + testImplementation 'ch.qos.logback:logback-classic:1.2.10' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 35f7483113f..43d74d16244 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' - testImplementation 'ch.qos.logback:logback-classic:1.2.7' + testImplementation 'ch.qos.logback:logback-classic:1.2.10' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 8685bc3205ea95232f7dfbec67fcafc396b7229b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 11:44:32 +0000 Subject: [PATCH 1633/4969] Bump aws-java-sdk-logs from 1.12.122 to 1.12.132 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.122 to 1.12.132. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.122...1.12.132) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c0075ad198f..ad93e527043 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.131' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.131' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.122' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.132' testImplementation 'software.amazon.awssdk:s3:2.17.102' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 63a892b357947d4814baa9f6070783003ccdf553 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 11:44:33 +0000 Subject: [PATCH 1634/4969] Bump org.springframework.boot from 2.6.1 to 2.6.2 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.6.1 to 2.6.2. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.6.1...v2.6.2) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 242cfcd3810..f79edec4998 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.1' + id 'org.springframework.boot' version '2.6.2' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index e0028d26b4a..767d6922863 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.6.1" + id("org.springframework.boot") version "2.6.2" id("org.jetbrains.kotlin.jvm") version "1.6.10" id("org.jetbrains.kotlin.plugin.spring") version "1.6.0" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index b5ddd11cc84..782f03b561e 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.1' + id 'org.springframework.boot' version '2.6.2' } apply plugin: 'io.spring.dependency-management' From 0e8faedaa234d3cefa5af96fa8e20ba5be3a5a79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 11:44:33 +0000 Subject: [PATCH 1635/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.6.0 to 1.6.10. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index e0028d26b4a..fa951bd3415 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.6.1" id("org.jetbrains.kotlin.jvm") version "1.6.10" - id("org.jetbrains.kotlin.plugin.spring") version "1.6.0" + id("org.jetbrains.kotlin.plugin.spring") version "1.6.10" } apply plugin: 'io.spring.dependency-management' From e597f4ab445fad71130e535528d7ef4782c0f38e Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 4 Jan 2022 18:38:13 +0100 Subject: [PATCH 1636/4969] Rollback jedis to 3.0.1 (#4852) --- modules/toxiproxy/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index e055f5a52c5..cad4b6b71f3 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.5' - testImplementation 'redis.clients:jedis:4.0.1' + testImplementation 'redis.clients:jedis:3.0.1' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' testImplementation project(':test-support') From 3c30a267d1bb678dba13a17c5ccfd53eef4824e7 Mon Sep 17 00:00:00 2001 From: vincz7777 <96777535+vincz7777@users.noreply.github.com> Date: Wed, 5 Jan 2022 11:24:37 +0100 Subject: [PATCH 1637/4969] Display Ryuk logs when it fails to start (#4842) Co-authored-by: Sergei Egorov Co-authored-by: Vincent MIJOULE (contractor) Co-authored-by: Richard North --- .../utility/ResourceReaper.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 8c1f28378ef..f43835fd01b 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -34,7 +34,6 @@ import java.net.Socket; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; @@ -133,10 +132,10 @@ public void onNext(Frame frame) { } }); - ContainerState containerState = new ContainerState() { - + InspectContainerResponse inspectedContainer; + try { // inspect container response might initially not contain the mapped port - final InspectContainerResponse inspectedContainer = await() + inspectedContainer = await() .atMost(5, TimeUnit.SECONDS) .pollInterval(DynamicPollInterval.ofMillis(50)) .pollInSameThread() @@ -144,14 +143,20 @@ public void onNext(Frame frame) { () -> client.inspectContainerCmd(ryukContainerId).exec(), inspectContainerResponse -> { return inspectContainerResponse - .getNetworkSettings() - .getPorts() - .getBindings() - .values() - .stream() - .anyMatch(Objects::nonNull); + .getNetworkSettings() + .getPorts() + .getBindings() + .values() + .stream() + .anyMatch(Objects::nonNull); } ); + } catch (Exception e) { + log.warn("Ryuk container cannot be inspected and probably had a problem starting. Ryuk's logs:\n{}", ryukLog); + throw new IllegalStateException("Ryuk failed to start", e); + } + + ContainerState containerState = new ContainerState() { @Override public List getExposedPorts() { From 4fe304ab5128942df4cea708ed859f2e79b2b649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Prinet?= Date: Wed, 5 Jan 2022 11:54:19 +0100 Subject: [PATCH 1638/4969] Add Gradle Enterprise badge in README (#4850) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9bcf6f002f8..b1c0014c236 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Thundra Foresight](https://thundra-assets-prod.s3.us-west-2.amazonaws.com/images/badges/thundra-foresight-badge-enabled.svg)](https://foresight.thundra.live/testRuns/5a49cc30-f063-11eb-9a03-0242ac130003) [![Thundra Foresight Test Results](https://foresight.service.thundra.us/public/api/v1/badge/test/5a49cc30-f063-11eb-9a03-0242ac130003)](https://foresight.thundra.live/testRuns/5a49cc30-f063-11eb-9a03-0242ac130003) +[![Revved up by Gradle Enterprise](https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.testcontainers.org/scans) > Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. From ac020bc7ae265ac6f7268c8ae3a054aaf1d84626 Mon Sep 17 00:00:00 2001 From: Piotr Kubowicz Date: Wed, 5 Jan 2022 11:54:44 +0100 Subject: [PATCH 1639/4969] Stop logging about starting when reusing (#4844) --- .../java/org/testcontainers/containers/GenericContainer.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index c2387cf5977..69d40a6821b 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -421,12 +421,10 @@ private void tryStart(Instant startedAt) { if (!reused) { containerIsCreated(containerId); - logger().info("Starting container with ID: {}", containerId); + logger().info("Container {} is starting: {}", dockerImageName, containerId); dockerClient.startContainerCmd(containerId).exec(); } - logger().info("Container {} is starting: {}", dockerImageName, containerId); - // For all registered output consumers, start following as close to container startup as possible this.logConsumers.forEach(this::followOutput); From e42a37d615d48cdc60181b4ab634c555898bf988 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 5 Jan 2022 14:46:26 +0100 Subject: [PATCH 1640/4969] Reinstate usage of `READ_ONLY_REMOTE_GRADLE_CACHE` to avoid wrong cache hits (#4853) --- settings.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/settings.gradle b/settings.gradle index db8f11f14c0..75359bcbf7d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -42,10 +42,10 @@ buildCache { local { enabled = !isCI } - remote(HttpBuildCache) { - push = isCI + remote(HttpBuildCache) { + push = isCI && !System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") enabled = true - url = 'https://ge.testcontainers.org/cache/' + url = 'https://ge.testcontainers.org/cache/' credentials { username = 'ci' password = System.getenv("GRADLE_ENTERPRISE_CACHE_PASSWORD") From e70782a01820a12e99b33e1ec701afd107421598 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 5 Jan 2022 18:48:32 +0100 Subject: [PATCH 1641/4969] Increase AzureCI timeout to 120 minutes instead of using the default of 60 minutes (#4854) --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 91e33f202a9..53dabc6722b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,6 +1,7 @@ jobs: - job: azure_pipeline_tests + timeoutInMinutes: 120 steps: # Run all core tests when running the Windows CI tests From ba3748e3edb51c01f896fa930daadc8eec22e65f Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 5 Jan 2022 19:12:22 +0100 Subject: [PATCH 1642/4969] Add GE remote cache to examples project (#4855) Als add GE build scans for examples project --- examples/settings.gradle | 36 ++++++++++++++++++++++-------------- settings.gradle | 8 ++------ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 22b279b1573..8641c6134b1 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -7,11 +7,12 @@ buildscript { dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.2" } } -apply plugin: 'ch.myniva.s3-build-cache' apply plugin: 'com.gradle.enterprise' +apply plugin: "com.gradle.common-custom-user-data-gradle-plugin" rootProject.name = 'testcontainers-examples' @@ -32,23 +33,30 @@ include 'cucumber' include 'spring-boot-kotlin-redis' include 'spock' -ext.isMasterBuild = false || - (System.getenv("GITHUB_REF") == "refs/heads/master") || - (System.getenv("BUILD_SOURCEBRANCHNAME") == "master") +ext.isCI = System.getenv("CI") != null buildCache { local { - enabled = !isMasterBuild + enabled = !isCI } + remote(HttpBuildCache) { + push = isCI && !System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") + enabled = true + url = 'https://ge.testcontainers.org/cache/' + credentials { + username = 'ci' + password = System.getenv("GRADLE_ENTERPRISE_CACHE_PASSWORD") + } + } +} - remote(ch.myniva.gradle.caching.s3.AwsS3BuildCache) { - endpoint = 'fra1.digitaloceanspaces.com' - region = 'fra1' - bucket = 'testcontainers' - path = 'cache' - push = isMasterBuild && !System.getenv("READ_ONLY_REMOTE_GRADLE_CACHE") - headers = [ - 'x-amz-acl': 'public-read' - ] +gradleEnterprise { + buildScan { + server = "https://ge.testcontainers.org/" + publishAlways() + publishIfAuthenticated() + uploadInBackground = !isCI + captureTaskInputFiles = true } + } diff --git a/settings.gradle b/settings.gradle index 75359bcbf7d..57f18b531b1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,8 +5,8 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.7.2" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.1" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.2" } } @@ -32,10 +32,6 @@ include ':docs:examples:spock:redis' include 'test-support' -ext.isMasterBuild = false || - (System.getenv("GITHUB_REF") == "refs/heads/master") || - (System.getenv("BUILD_SOURCEBRANCHNAME") == "master") - ext.isCI = System.getenv("CI") != null buildCache { From e6caada4f902c171e6db0dc606b4cc2b8ca2fe4e Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 6 Jan 2022 15:49:23 +0000 Subject: [PATCH 1643/4969] Tweak logging around reusable mode (#4858) --- .../java/org/testcontainers/containers/GenericContainer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 69d40a6821b..3851cf42fca 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -423,6 +423,8 @@ private void tryStart(Instant startedAt) { logger().info("Container {} is starting: {}", dockerImageName, containerId); dockerClient.startContainerCmd(containerId).exec(); + } else { + logger().info("Reusing existing container ({}) and not creating a new one", containerId); } // For all registered output consumers, start following as close to container startup as possible From 74bea3a37cf259c4b8a1b40da07e06328e4a13ad Mon Sep 17 00:00:00 2001 From: Dan Dobrin <20207377+ddobrin@users.noreply.github.com> Date: Tue, 11 Jan 2022 05:29:57 -0500 Subject: [PATCH 1644/4969] Update gCloud dependencies (#4857) Fixes #4856 --- modules/gcloud/build.gradle | 12 ++++++------ .../containers/BigtableEmulatorContainerTest.java | 2 +- .../containers/DatastoreEmulatorContainerTest.java | 2 +- .../containers/FirestoreEmulatorContainerTest.java | 2 +- .../containers/PubSubEmulatorContainerTest.java | 2 +- .../containers/SpannerEmulatorContainerTest.java | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 11e68824c34..d20a9edbed0 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,10 +3,10 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:1.102.4' - testImplementation 'com.google.cloud:google-cloud-firestore:1.33.0' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.105.0' - testImplementation 'com.google.cloud:google-cloud-spanner:1.50.0' - testImplementation 'com.google.cloud:google-cloud-bigtable:1.17.3' - testImplementation 'org.assertj:assertj-core:3.15.0' + testImplementation 'com.google.cloud:google-cloud-datastore:2.2.1' + testImplementation 'com.google.cloud:google-cloud-firestore:3.0.9' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.0' + testImplementation 'com.google.cloud:google-cloud-spanner:6.17.3' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.4.0' + testImplementation 'org.assertj:assertj-core:3.22.0' } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java index 0cc44afcc77..4ba59a75488 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java @@ -43,7 +43,7 @@ public class BigtableEmulatorContainerTest { @Rule // emulatorContainer { public BigtableEmulatorContainer emulator = new BigtableEmulatorContainer( - DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); // } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java index f7b35936197..ba998e402ce 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java @@ -17,7 +17,7 @@ public class DatastoreEmulatorContainerTest { @Rule // creatingDatastoreEmulatorContainer { public DatastoreEmulatorContainer emulator = new DatastoreEmulatorContainer( - DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); // } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java index 138ff946f6f..04939ecc30e 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java @@ -22,7 +22,7 @@ public class FirestoreEmulatorContainerTest { @Rule // emulatorContainer { public FirestoreEmulatorContainer emulator = new FirestoreEmulatorContainer( - DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); // } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java index 2e692956418..8db49eb3649 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java @@ -35,7 +35,7 @@ public class PubSubEmulatorContainerTest { @Rule // emulatorContainer { public PubSubEmulatorContainer emulator = new PubSubEmulatorContainer( - DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators") + DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); // } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java index f801ca5b547..64b81546499 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java @@ -27,7 +27,7 @@ public class SpannerEmulatorContainerTest { @Rule // emulatorContainer { public SpannerEmulatorContainer emulator = new SpannerEmulatorContainer( - DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.1.0") + DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.4.0") ); // } From d0c4ced72ddca93838c1107b66913b5141872906 Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 11 Jan 2022 11:21:06 +0000 Subject: [PATCH 1645/4969] Update dependabot rules for new modules (#4864) --- .github/dependabot.yml | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4caa6509af2..355d44f2bb4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,11 @@ updates: open-pull-requests-limit: 10 # Explicit entry for each module + - package-ecosystem: "gradle" + directory: "/modules/azure" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/cassandra" schedule: @@ -17,6 +22,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/cockroachdb" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/couchbase" schedule: @@ -27,6 +37,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/db2" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/dynalite" schedule: @@ -37,6 +52,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/gcloud" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/influxdb" schedule: @@ -57,6 +77,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/k3s" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/kafka" schedule: @@ -77,6 +102,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/mongodb" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/mssqlserver" schedule: @@ -102,21 +132,46 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/orientdb" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/postgresql" schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/presto" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/pulsar" schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/r2dbc" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/rabbitmq" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/selenium" schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/solr" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/spock" schedule: @@ -127,6 +182,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/trino" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/vault" schedule: From e681a4f854acde4a7e54fd2c6745714537eaeaa6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:30 +0000 Subject: [PATCH 1646/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/jdbc Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 973bc9b01df..a6f71690e1e 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -11,5 +11,5 @@ dependencies { testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' } From 8fdae9c304bdfe3bf12ee88fdbc42a220f40ea9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:30 +0000 Subject: [PATCH 1647/4969] Bump jcc from 11.5.0.0 to 11.5.7.0 in /modules/db2 Bumps jcc from 11.5.0.0 to 11.5.7.0. --- updated-dependencies: - dependency-name: com.ibm.db2:jcc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/db2/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/db2/build.gradle b/modules/db2/build.gradle index 9d5d8a61ab0..0c8cd323779 100644 --- a/modules/db2/build.gradle +++ b/modules/db2/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'com.ibm.db2:jcc:11.5.0.0' + testImplementation 'com.ibm.db2:jcc:11.5.7.0' } From 954529be0e1b6b8cc81895eac8d67c4358da49cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:31 +0000 Subject: [PATCH 1648/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/database-commons Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/database-commons/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle index 73735b0d03d..7a201d772fb 100644 --- a/modules/database-commons/build.gradle +++ b/modules/database-commons/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons" dependencies { api project(':testcontainers') - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' } From d0a0f21ef89bdf03fb7667fee16aba89c5108559 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:31 +0000 Subject: [PATCH 1649/4969] Bump postgresql from 42.2.12 to 42.3.1 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.2.12 to 42.3.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.2.12...REL42.3.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index 5222208fae0..ee6a7e2731e 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.2.12' + testImplementation 'org.postgresql:postgresql:42.3.1' } From 78754f8ce6fb19054d5a43d46a513619d79b1ad4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:32 +0000 Subject: [PATCH 1650/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.131 to 1.12.137. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.131...1.12.137) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index d891ed5b4d9..52881514ac5 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.131' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.131' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 0c6854077d2e550a21ef023bb8b84930c674e824 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:32 +0000 Subject: [PATCH 1651/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/junit-jupiter Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 8344db5aebb..77ff3f842d0 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -12,7 +12,7 @@ dependencies { testImplementation ('org.mockito:mockito-core:4.2.0') { exclude(module: 'hamcrest-core') } - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' testRuntimeOnly 'org.postgresql:postgresql:42.3.1' From 762251dd30f675e0bd4031d5d9bfe15f5232a181 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:34 +0000 Subject: [PATCH 1652/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/kafka Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index b37105f7463..b9157d9d539 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -13,6 +13,6 @@ dependencies { api project(':testcontainers') testImplementation 'org.apache.kafka:kafka-clients:3.0.0' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'com.google.guava:guava:23.0' } From f3fed54fe55d672af31806c6327051a26d297c55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:35 +0000 Subject: [PATCH 1653/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /core Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 3ca76eab47a..074273e8fc7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -100,13 +100,13 @@ dependencies { testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation project(':test-support') jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestImplementation 'junit:junit:4.13.2' - jarFileTestImplementation 'org.assertj:assertj-core:3.20.2' + jarFileTestImplementation 'org.assertj:assertj-core:3.22.0' jarFileTestImplementation 'org.ow2.asm:asm-debug-all:5.2' } From 28ada89db26aea589876a514f84b9d7807d47d07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:35 +0000 Subject: [PATCH 1654/4969] Bump google-cloud-firestore from 3.0.9 to 3.0.10 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.0.9 to 3.0.10. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.0.9...v3.0.10) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index d20a9edbed0..f1e473b8c35 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.2.1' - testImplementation 'com.google.cloud:google-cloud-firestore:3.0.9' + testImplementation 'com.google.cloud:google-cloud-firestore:3.0.10' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.17.3' testImplementation 'com.google.cloud:google-cloud-bigtable:2.4.0' From 18234abf497226469d9cc450b378cc40dc87be1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:38 +0000 Subject: [PATCH 1655/4969] Bump azure-cosmos from 4.16.0 to 4.24.0 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.16.0 to 4.24.0. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.16.0...azure-cosmos_4.24.0) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 19d9b3458fd..d3a902cf728 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':testcontainers') testImplementation 'org.assertj:assertj-core:3.15.0' - testImplementation 'com.azure:azure-cosmos:4.16.0' + testImplementation 'com.azure:azure-cosmos:4.24.0' } From b5f534b09d971d58bda6da47063e524e6ec2faac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:38 +0000 Subject: [PATCH 1656/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/neo4j Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index cdc727921b4..fe99774538c 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -34,5 +34,5 @@ dependencies { api project(":testcontainers") testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.2' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' } From 6a7f32ba11e80a9fa5e2343d758f24a590cc61ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:39 +0000 Subject: [PATCH 1657/4969] Bump pulsar-client-admin from 2.7.3 to 2.7.4 in /modules/pulsar Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.7.3 to 2.7.4. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.7.3...v2.7.4) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client-admin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 8bdabcd9dc3..7ad057e2e91 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.3' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.21.0' - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.3' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.4' } From 6604418e5a956a5eccde8f6609792fe8eecf3576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:39 +0000 Subject: [PATCH 1658/4969] Bump reactor-core from 3.3.4.RELEASE to 3.4.14 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.3.4.RELEASE to 3.4.14. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.3.4.RELEASE...v3.4.14) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 21d3c1894e4..232714886dc 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.3.4.RELEASE' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.14' testFixturesImplementation 'org.assertj:assertj-core:3.14.0' } From ee75985196ec9a483c905724d1bb8411b48ce941 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:40 +0000 Subject: [PATCH 1659/4969] Bump trino-jdbc from 352 to 367 in /modules/trino Bumps trino-jdbc from 352 to 367. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index 5a3b733934f..fb154ba7266 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:352' + testImplementation 'io.trino:trino-jdbc:367' compileOnly 'org.jetbrains:annotations:20.0.0' } From 0ece0ce0851b72e8c5713611ab045f65e9cc0ec4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:41 +0000 Subject: [PATCH 1660/4969] Bump presto-jdbc from 331 to 350 in /modules/presto Bumps presto-jdbc from 331 to 350. --- updated-dependencies: - dependency-name: io.prestosql:presto-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/presto/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/presto/build.gradle b/modules/presto/build.gradle index 1db76199969..2b6955efd8a 100644 --- a/modules/presto/build.gradle +++ b/modules/presto/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.prestosql:presto-jdbc:331' + testImplementation 'io.prestosql:presto-jdbc:350' compileOnly 'org.jetbrains:annotations:20.0.0' } From 2d83ea0bb119307d4db5dc764a1e3c66a54c0cb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:41 +0000 Subject: [PATCH 1661/4969] Bump mongodb-driver-sync from 4.0.2 to 4.4.1 in /modules/mongodb Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.0.2 to 4.4.1. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.0.2...r4.4.1) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/mongodb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index e332badb68b..95919c931d4 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: MongoDB" dependencies { api project(':testcontainers') - testImplementation("org.mongodb:mongodb-driver-sync:4.0.2") + testImplementation("org.mongodb:mongodb-driver-sync:4.4.1") } From 0df60341337267cf40e376d18a94997ee7dba682 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:43 +0000 Subject: [PATCH 1662/4969] Bump assertj-core from 3.12.0 to 3.22.0 in /modules/orientdb Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.12.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.12.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/orientdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/orientdb/build.gradle b/modules/orientdb/build.gradle index 5be59938603..820e96e114f 100644 --- a/modules/orientdb/build.gradle +++ b/modules/orientdb/build.gradle @@ -5,7 +5,7 @@ dependencies { api "com.orientechnologies:orientdb-client:3.0.24" - testImplementation 'org.assertj:assertj-core:3.12.0' + testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'org.apache.tinkerpop:gremlin-driver:3.3.4' testImplementation "com.orientechnologies:orientdb-gremlin:3.0.18" } From e89b2e650259be9e3ec89c989505c44e3cd25448 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:45 +0000 Subject: [PATCH 1663/4969] Bump assertj-core from 3.14.0 to 3.22.0 in /modules/r2dbc Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.14.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.14.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 21d3c1894e4..94867299969 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -11,7 +11,7 @@ dependencies { api project(':testcontainers') api 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE' - testImplementation 'org.assertj:assertj-core:3.14.0' + testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' testImplementation project(':postgresql') From 88cbf80101deaec9a4593c5e42b5d578a2554888 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:45 +0000 Subject: [PATCH 1664/4969] Bump assertj-core from 3.12.2 to 3.22.0 in /modules/rabbitmq Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.12.2 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.12.2...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/rabbitmq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 13638b51b97..de778979f0f 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: RabbitMQ" dependencies { api project(":testcontainers") testImplementation 'com.rabbitmq:amqp-client:5.7.0' - testImplementation 'org.assertj:assertj-core:3.12.2' + testImplementation 'org.assertj:assertj-core:3.22.0' compileOnly 'org.jetbrains:annotations:20.0.0' } From 6db0f46bc762b1d25cce6a0733c3934aa001f416 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:46 +0000 Subject: [PATCH 1665/4969] Bump testng from 7.4.0 to 7.5 in /examples Bumps [testng](https://github.com/cbeust/testng) from 7.4.0 to 7.5. - [Release notes](https://github.com/cbeust/testng/releases) - [Changelog](https://github.com/cbeust/testng/blob/master/CHANGES.txt) - [Commits](https://github.com/cbeust/testng/compare/7.4.0...7.5) --- updated-dependencies: - dependency-name: org.testng:testng dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index e1b1f5d639a..2046da278f2 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.10' - testImplementation 'org.testng:testng:7.4.0' + testImplementation 'org.testng:testng:7.5' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 8f545a1362d3d9cefdc9b1884f20ce2c2897ae7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:46 +0000 Subject: [PATCH 1666/4969] Bump google-cloud-spanner from 6.17.3 to 6.17.4 in /modules/gcloud Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.17.3 to 6.17.4. - [Release notes](https://github.com/googleapis/java-spanner/releases) - [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-spanner/compare/v6.17.3...v6.17.4) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-spanner dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index d20a9edbed0..b9828fb1871 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.2.1' testImplementation 'com.google.cloud:google-cloud-firestore:3.0.9' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.0' - testImplementation 'com.google.cloud:google-cloud-spanner:6.17.3' + testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' testImplementation 'com.google.cloud:google-cloud-bigtable:2.4.0' testImplementation 'org.assertj:assertj-core:3.22.0' } From 9e755a161546946d823d6be3bdbf0e5b565be387 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:46 +0000 Subject: [PATCH 1667/4969] Bump pulsar-client from 2.7.3 to 2.7.4 in /modules/pulsar Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.7.3 to 2.7.4. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.7.3...v2.7.4) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 8bdabcd9dc3..cb03e560730 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { api project(':testcontainers') - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.3' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.4' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.21.0' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.3' } From 1bcccbcd8a8f3afb8346f987ca5004b3e16ef09e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:21:48 +0000 Subject: [PATCH 1668/4969] Bump aws-java-sdk-s3 from 1.12.131 to 1.12.137 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.131 to 1.12.137. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.131...1.12.137) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ad93e527043..900fbfed541 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.131' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.137' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.131' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.132' testImplementation 'software.amazon.awssdk:s3:2.17.102' From 32fbe075ac3f1e63daa2d3ad34c6eb57d3f134a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:23:00 +0000 Subject: [PATCH 1669/4969] Bump solr-solrj from 8.3.0 to 8.11.1 in /modules/solr Bumps solr-solrj from 8.3.0 to 8.11.1. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/solr/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index 76535a2b7c8..b3dfc9b3f92 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -2,6 +2,6 @@ description = "Testcontainers :: Solr" dependencies { api project(':testcontainers') - testImplementation 'org.apache.solr:solr-solrj:8.3.0' + testImplementation 'org.apache.solr:solr-solrj:8.11.1' } From 65b73bbd348bf9a2a61eea68cb599d1da4c37c33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:23:29 +0000 Subject: [PATCH 1670/4969] Bump s3 from 2.17.102 to 2.17.108 in /modules/localstack Bumps s3 from 2.17.102 to 2.17.108. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ad93e527043..4e5371b7bc6 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.122' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.131' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.132' - testImplementation 'software.amazon.awssdk:s3:2.17.102' + testImplementation 'software.amazon.awssdk:s3:2.17.108' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From a282f4185a00b8cd516d5dad32cbccd9e4b2d009 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:23:53 +0000 Subject: [PATCH 1671/4969] Bump auto-service from 1.0-rc6 to 1.0.1 in /modules/r2dbc Bumps [auto-service](https://github.com/google/auto) from 1.0-rc6 to 1.0.1. - [Release notes](https://github.com/google/auto/releases) - [Commits](https://github.com/google/auto/commits/auto-common-1.0.1) --- updated-dependencies: - dependency-name: com.google.auto.service:auto-service dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 21d3c1894e4..e7011b1d32c 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -5,7 +5,7 @@ plugins { description = "Testcontainers :: R2DBC" dependencies { - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6' + annotationProcessor 'com.google.auto.service:auto-service:1.0.1' compileOnly 'com.google.auto.service:auto-service:1.0-rc6' api project(':testcontainers') From 510a97507f242f6a23bad1b757c55d02c0b6f8f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:24:46 +0000 Subject: [PATCH 1672/4969] Bump cucumber-junit from 7.1.0 to 7.2.2 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.1.0 to 7.2.2. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.1.0...v7.2.2) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index edb62670134..3f37cbf45e4 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.1.0' - testImplementation 'io.cucumber:cucumber-junit:7.1.0' + testImplementation 'io.cucumber:cucumber-junit:7.2.2' testImplementation 'org.testcontainers:selenium' } From 9cc0b82b5df8ff5f63db5435b784de5205c61598 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:23 +0000 Subject: [PATCH 1673/4969] Bump assertj-core from 3.15.0 to 3.22.0 in /modules/azure Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.15.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.15.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index d3a902cf728..1dbad6a6698 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Azure" dependencies { api project(':testcontainers') - testImplementation 'org.assertj:assertj-core:3.15.0' + testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'com.azure:azure-cosmos:4.24.0' } From 9cefa10a9c83bfebcb6ae95bd065396fc9190327 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:30 +0000 Subject: [PATCH 1674/4969] Bump google-cloud-datastore from 2.2.1 to 2.2.2 in /modules/gcloud Bumps [google-cloud-datastore](https://github.com/googleapis/java-datastore) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/googleapis/java-datastore/releases) - [Changelog](https://github.com/googleapis/java-datastore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-datastore/compare/v2.2.1...v2.2.2) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-datastore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 72041c6d14b..ab2966c3051 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:2.2.1' + testImplementation 'com.google.cloud:google-cloud-datastore:2.2.2' testImplementation 'com.google.cloud:google-cloud-firestore:3.0.10' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' From 740479210f0fe0a7a7cfc6eb35f2e29df7ceb158 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:36 +0000 Subject: [PATCH 1675/4969] Bump annotations from 20.0.0 to 23.0.0 in /modules/presto Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/presto/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/presto/build.gradle b/modules/presto/build.gradle index 2b6955efd8a..fe0064bf199 100644 --- a/modules/presto/build.gradle +++ b/modules/presto/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'io.prestosql:presto-jdbc:350' - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' } From 6c015557bf939b030277bf3107928e77dc7c9161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:41 +0000 Subject: [PATCH 1676/4969] Bump amqp-client from 5.7.0 to 5.14.0 in /modules/rabbitmq Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.7.0 to 5.14.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.7.0...v5.14.0) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/rabbitmq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index de778979f0f..005fcf3d97c 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: RabbitMQ" dependencies { api project(":testcontainers") - testImplementation 'com.rabbitmq:amqp-client:5.7.0' + testImplementation 'com.rabbitmq:amqp-client:5.14.0' testImplementation 'org.assertj:assertj-core:3.22.0' compileOnly 'org.jetbrains:annotations:20.0.0' } From 45eae3ef861e1a00cd12259d59dc97becf09953f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:41 +0000 Subject: [PATCH 1677/4969] Bump google-cloud-bigtable from 2.4.0 to 2.5.1 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.4.0 to 2.5.1. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.4.0...v2.5.1) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 72041c6d14b..16f2b6e4fc2 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.0.10' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.4.0' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.1' testImplementation 'org.assertj:assertj-core:3.22.0' } From 957ee23957ee93412d5d398d3a0e5458f069cf1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:41 +0000 Subject: [PATCH 1678/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/vault Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 4fdb274f999..8aa0a2d689e 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -5,6 +5,6 @@ dependencies { testImplementation 'com.bettercloud:vault-java-driver:5.1.0' testImplementation 'io.rest-assured:rest-assured:4.4.0' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' } From 1378f53c4a498c790e2b5df942b94759ee6b7ab6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:43 +0000 Subject: [PATCH 1679/4969] Bump annotations from 20.0.0 to 23.0.0 in /modules/rabbitmq Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/rabbitmq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index de778979f0f..613ef37808f 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(":testcontainers") testImplementation 'com.rabbitmq:amqp-client:5.7.0' testImplementation 'org.assertj:assertj-core:3.22.0' - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' } From fcd3892afaa56d6c30d4607d98973b29968b3869 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:43 +0000 Subject: [PATCH 1680/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/pulsar Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 95b373eb5ef..cf11a36b411 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.4' - testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.21.0' + testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.22.0' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.4' } From aae6a044a1025662ea300ff913ee7f59cbfbf86b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:44 +0000 Subject: [PATCH 1681/4969] Bump google-cloud-pubsub from 1.115.0 to 1.115.1 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.115.0 to 1.115.1. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.115.0...v1.115.1) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 72041c6d14b..0a6b351e8a0 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.2.1' testImplementation 'com.google.cloud:google-cloud-firestore:3.0.10' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.0' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' testImplementation 'com.google.cloud:google-cloud-bigtable:2.4.0' testImplementation 'org.assertj:assertj-core:3.22.0' From 6db619e8abf6b1bc4f450c3c311f75da2201496d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:48 +0000 Subject: [PATCH 1682/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /examples Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index a686fc171c2..3f28ca4ca9c 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -11,7 +11,7 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:1.18.22" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:3.0.0' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.10' } From 0a9122295062fd9634ea101e8bc848b704a5b0d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:18:54 +0000 Subject: [PATCH 1683/4969] Bump annotations from 20.0.0 to 23.0.0 in /modules/trino Bumps [annotations](https://github.com/JetBrains/java-annotations) from 20.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/20.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index fb154ba7266..f9223c174a5 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'io.trino:trino-jdbc:367' - compileOnly 'org.jetbrains:annotations:20.0.0' + compileOnly 'org.jetbrains:annotations:23.0.0' } From 5d45556f02206678f3367c6fd6debc765d2160b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:19:06 +0000 Subject: [PATCH 1684/4969] Bump cucumber-java from 7.1.0 to 7.2.2 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 7.1.0 to 7.2.2. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.1.0...v7.2.2) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 3f37cbf45e4..b018d3df5fc 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:7.1.0' + testImplementation 'io.cucumber:cucumber-java:7.2.2' testImplementation 'io.cucumber:cucumber-junit:7.2.2' testImplementation 'org.testcontainers:selenium' } From d59b9e6eaa8979717672b385dd34da6381f02049 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:19:10 +0000 Subject: [PATCH 1685/4969] Bump aws-java-sdk-sqs from 1.12.131 to 1.12.139 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.131 to 1.12.139. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.131...1.12.139) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9ae7a3536b3..0e0ee5c7323 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.137' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.131' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.139' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.132' testImplementation 'software.amazon.awssdk:s3:2.17.108' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 8526f53bd74d771d7896fcfa87194ebf7dde9b5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:19:22 +0000 Subject: [PATCH 1686/4969] Bump r2dbc-postgresql in /modules/r2dbc Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.1.RELEASE to 0.8.11.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.11.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.1.RELEASE...v0.8.11.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 7844671959c..74ab1c9f7f0 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -12,7 +12,7 @@ dependencies { api 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE' testImplementation 'org.assertj:assertj-core:3.22.0' - testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE' + testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' testImplementation project(':postgresql') testFixturesImplementation 'io.projectreactor:reactor-core:3.4.14' From f305f8ec61fc0645c632641f72e3fa9a653df42b Mon Sep 17 00:00:00 2001 From: Anna Chernyshova Date: Thu, 13 Jan 2022 13:11:26 +0300 Subject: [PATCH 1687/4969] Update BrowserWebDriverContainer to add Selenium 4 support, drop Selenium 2 support (#4914) Fixes #4593 Co-authored-by: Tobias Stadler --- docs/modules/webdriver_containers.md | 2 +- .../containers/BrowserWebDriverContainer.java | 54 +++++++++---------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/docs/modules/webdriver_containers.md b/docs/modules/webdriver_containers.md index 34d3430830c..3c6b0ffae27 100644 --- a/docs/modules/webdriver_containers.md +++ b/docs/modules/webdriver_containers.md @@ -5,7 +5,7 @@ from SeleniumHQ's [docker-selenium](https://github.com/SeleniumHQ/docker-seleniu ## Benefits -* Fully compatible with Selenium 2/Webdriver tests, by providing a `RemoteWebDriver` instance +* Fully compatible with Selenium 3 & 4 tests, by providing a `RemoteWebDriver` instance * No need to have specific web browsers, or even a desktop environment, installed on test servers. The only dependency is a working Docker installation and your Java JUnit test suite. * Browsers are always launched from a fixed, clean image. This means no configuration drift from user changes or diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 7bc37e4701c..bd38dead8ac 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -35,6 +35,7 @@ import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.lifecycle.TestDescription; import org.testcontainers.lifecycle.TestLifecycleAware; +import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; /** @@ -44,13 +45,15 @@ */ public class BrowserWebDriverContainer> extends GenericContainer implements LinkableContainer, TestLifecycleAware { - private static final DockerImageName CHROME_IMAGE = DockerImageName.parse("selenium/standalone-chrome-debug"); - private static final DockerImageName FIREFOX_IMAGE = DockerImageName.parse("selenium/standalone-firefox-debug"); + private static final DockerImageName CHROME_IMAGE = DockerImageName.parse("selenium/standalone-chrome"); + private static final DockerImageName FIREFOX_IMAGE = DockerImageName.parse("selenium/standalone-firefox"); + private static final DockerImageName CHROME_DEBUG_IMAGE = DockerImageName.parse("selenium/standalone-chrome-debug"); + private static final DockerImageName FIREFOX_DEBUG_IMAGE = DockerImageName.parse("selenium/standalone-firefox-debug"); private static final DockerImageName[] COMPATIBLE_IMAGES = new DockerImageName[] { CHROME_IMAGE, FIREFOX_IMAGE, - DockerImageName.parse("selenium/standalone-chrome"), - DockerImageName.parse("selenium/standalone-firefox") + CHROME_DEBUG_IMAGE, + FIREFOX_DEBUG_IMAGE }; private static final String DEFAULT_PASSWORD = "secret"; @@ -156,23 +159,6 @@ protected void configure() { String seleniumVersion = SeleniumUtils.determineClasspathSeleniumVersion(); - if (capabilities == null) { - if (seleniumVersion.startsWith("2.")) { - logger().info("No capabilities provided, falling back to DesiredCapabilities.chrome()"); - capabilities = DesiredCapabilities.chrome(); - } else { - logger().info("No capabilities provided, falling back to ChromeOptions"); - capabilities = new ChromeOptions(); - } - } - - // Hack for new selenium-chrome image that contains Chrome 92. - // If not disabled, container startup will fail in most cases and consume excessive amounts of CPU. - if (capabilities instanceof ChromeOptions) { - ChromeOptions options = (ChromeOptions) this.capabilities; - options.addArguments("--disable-gpu"); - } - if (recordingMode != VncRecordingMode.SKIP) { if (vncRecordingDirectory == null) { @@ -244,12 +230,14 @@ public static String getDockerImageForCapabilities(Capabilities capabilities, St } private static DockerImageName getStandardImageForCapabilities(Capabilities capabilities, String seleniumVersion) { - String browserName = capabilities.getBrowserName(); + String browserName = capabilities == null ? BrowserType.CHROME : capabilities.getBrowserName(); + boolean supportsVncWithoutDebugImage = new ComparableVersion(seleniumVersion).isGreaterThanOrEqualTo("4"); + switch (browserName) { case BrowserType.CHROME: - return CHROME_IMAGE.withTag(seleniumVersion); + return (supportsVncWithoutDebugImage ? CHROME_IMAGE : CHROME_DEBUG_IMAGE).withTag(seleniumVersion); case BrowserType.FIREFOX: - return FIREFOX_IMAGE.withTag(seleniumVersion); + return (supportsVncWithoutDebugImage ? FIREFOX_IMAGE : FIREFOX_DEBUG_IMAGE).withTag(seleniumVersion); default: throw new UnsupportedOperationException("Browser name must be 'chrome' or 'firefox'; provided '" + browserName + "' is not supported"); } @@ -280,10 +268,6 @@ public int getPort() { @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { - driver = Unreliables.retryUntilSuccess(30, TimeUnit.SECONDS, - () -> Timeouts.getWithTimeout(10, TimeUnit.SECONDS, - () -> new RemoteWebDriver(getSeleniumAddress(), capabilities))); - if (vncRecordingContainer != null) { LOGGER.debug("Starting VNC recording"); vncRecordingContainer.start(); @@ -298,7 +282,19 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { * * @return a new Remote Web Driver instance */ - public RemoteWebDriver getWebDriver() { + public synchronized RemoteWebDriver getWebDriver() { + if (driver == null) { + if (capabilities == null) { + logger().warn("No capabilities provided - this will cause an exception in future versions. Falling back to ChromeOptions"); + capabilities = new ChromeOptions(); + } + + driver = Unreliables.retryUntilSuccess(30, TimeUnit.SECONDS, () -> { + return Timeouts.getWithTimeout(10, TimeUnit.SECONDS, () -> { + return new RemoteWebDriver(getSeleniumAddress(), capabilities); + }); + }); + } return driver; } From 74173e51e0981bf3a5ea3fc617f385b4fedb6528 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 13:03:38 +0000 Subject: [PATCH 1688/4969] Bump aws-java-sdk-logs from 1.12.132 to 1.12.139 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.132 to 1.12.139. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.132...1.12.139) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 0e0ee5c7323..7bfec27ccaf 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.139' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.132' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.139' testImplementation 'software.amazon.awssdk:s3:2.17.108' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 3a16a794162064effec0e805d7d34342c63f65ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 13:03:39 +0000 Subject: [PATCH 1689/4969] Bump r2dbc-postgresql in /modules/postgresql Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.8.RELEASE to 0.8.11.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.11.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.8.RELEASE...v0.8.11.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index c38b9bc4fc2..a8a6495bfc1 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -7,14 +7,14 @@ dependencies { api project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.8.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' testImplementation project(':jdbc-test') testImplementation project(':test-support') testImplementation 'org.postgresql:postgresql:42.3.1' testImplementation testFixtures(project(':r2dbc')) - testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.5.RELEASE' + testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' compileOnly 'org.jetbrains:annotations:23.0.0' } From 8186795449a3b32108e663e3208406b38fc61d7e Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 13 Jan 2022 15:27:22 +0000 Subject: [PATCH 1690/4969] Basic K3S module (#4582) --- docs/modules/k3s.md | 53 +++++++++++++++ mkdocs.yml | 1 + modules/k3s/build.gradle | 11 ++++ .../org/testcontainers/k3s/K3sContainer.java | 64 +++++++++++++++++++ .../k3s/Fabric8K3sContainerTest.java | 43 +++++++++++++ .../k3s/OfficialClientK3sContainerTest.java | 43 +++++++++++++ .../k3s/src/test/resources/logback-test.xml | 16 +++++ 7 files changed, 231 insertions(+) create mode 100644 docs/modules/k3s.md create mode 100644 modules/k3s/build.gradle create mode 100644 modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java create mode 100644 modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java create mode 100644 modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java create mode 100644 modules/k3s/src/test/resources/logback-test.xml diff --git a/docs/modules/k3s.md b/docs/modules/k3s.md new file mode 100644 index 00000000000..a3c2c0fa754 --- /dev/null +++ b/docs/modules/k3s.md @@ -0,0 +1,53 @@ +# K3s Module + +!!! note + This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +Testcontainers module for Rancher's [K3s](https://rancher.com/products/k3s/) lightweight Kubernetes. +This module is intended to be used for testing components that interact with Kubernetes APIs - for example, operators. + +## Usage example + +Start a K3s server as follows: + + +[Starting a K3S server](../../modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java) inside_block:starting_k3s + + +### Connecting to the server + +`K3sContainer` exposes a working Kubernetes client configuration, as a YAML String, via the `getKubeConfigYaml()` method. + +This may be used with Kubernetes clients - e.g. for the [official Java client](connecting_with_k8sio) and +[the Fabric8 Kubernetes client](https://github.com/fabric8io/kubernetes-client): + + +[Official Java client](../../modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java) inside_block:connecting_with_k8sio +[Fabric8 Kubernetes client](../../modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java) inside_block:connecting_with_fabric8 + + +## Known limitations + +!!! warning + * K3sContainer runs as a privileged container and needs to be able to spawn its own containers. For these reasons, + K3sContainer will not work in certain rootless Docker, Docker-in-Docker, or other environments where privileged + containers are disallowed. + + * k3s containers may be unable to run on host machines where `/var/lib/docker` is on a BTRFS filesystem. See [k3s-io/k3s#4863](https://github.com/k3s-io/k3s/issues/4863) for an example. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testImplementation "org.testcontainers:k3s:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + k3s + {{latest_version}} + test + +``` diff --git a/mkdocs.yml b/mkdocs.yml index be30f26a964..827ef6a836d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -65,6 +65,7 @@ nav: - modules/docker_compose.md - modules/elasticsearch.md - modules/gcloud.md + - modules/k3s.md - modules/kafka.md - modules/localstack.md - modules/mockserver.md diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle new file mode 100644 index 00000000000..85ee36652b3 --- /dev/null +++ b/modules/k3s/build.gradle @@ -0,0 +1,11 @@ +description = "Testcontainers :: K3S" + +dependencies { + api project(":testcontainers") + + shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1' + + testImplementation 'io.fabric8:kubernetes-client:5.11.0' + testImplementation 'io.kubernetes:client-java:14.0.0' + testImplementation 'org.assertj:assertj-core:3.21.0' +} diff --git a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java new file mode 100644 index 00000000000..1080563226a --- /dev/null +++ b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java @@ -0,0 +1,64 @@ +package org.testcontainers.k3s; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.github.dockerjava.api.command.InspectContainerResponse; +import lombok.SneakyThrows; +import org.testcontainers.containers.BindMode; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; + +import java.util.HashMap; +import java.util.Map; + +public class K3sContainer extends GenericContainer { + + private String kubeConfigYaml; + + public K3sContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DockerImageName.parse("rancher/k3s")); + + addExposedPorts(6443, 8443); + setPrivilegedMode(true); + addFileSystemBind("/sys/fs/cgroup", "/sys/fs/cgroup", BindMode.READ_WRITE); + + Map tmpFsMapping = new HashMap<>(); + tmpFsMapping.put("/run", ""); + tmpFsMapping.put("/var/run", ""); + setTmpFsMapping(tmpFsMapping); + + setCommand( + "server", + "--no-deploy=traefik", + "--tls-san=" + this.getHost() + ); + setWaitStrategy(new LogMessageWaitStrategy().withRegEx(".*Node controller sync successful.*")); + } + + @SneakyThrows + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + + ObjectNode rawKubeConfig = copyFileFromContainer( + "/etc/rancher/k3s/k3s.yaml", + is -> objectMapper.readValue(is, ObjectNode.class) + ); + + ObjectNode clusterConfig = rawKubeConfig.at("/clusters/0/cluster").require(); + clusterConfig.replace("server", new TextNode("https://" + this.getHost() + ":" + this.getMappedPort(6443))); + + rawKubeConfig.set("current-context", new TextNode("default")); + + kubeConfigYaml = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(rawKubeConfig); + } + + public String getKubeConfigYaml() { + return kubeConfigYaml; + } +} diff --git a/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java new file mode 100644 index 00000000000..8e7b601c5b0 --- /dev/null +++ b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java @@ -0,0 +1,43 @@ +package org.testcontainers.k3s; + +import io.fabric8.kubernetes.api.model.Node; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.DefaultKubernetesClient; +import lombok.extern.slf4j.Slf4j; +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.utility.DockerImageName; + +import java.util.List; + +@Slf4j +public class Fabric8K3sContainerTest { + + @Test + public void shouldStartAndHaveListableNode() { + try ( + // starting_k3s { + K3sContainer k3s = new K3sContainer(DockerImageName.parse("rancher/k3s:v1.21.3-k3s1")) + .withLogConsumer(new Slf4jLogConsumer(log)) + // } + ) { + k3s.start(); + + // connecting_with_fabric8 { + // obtain a kubeconfig file which allows us to connect to k3s + String kubeConfigYaml = k3s.getKubeConfigYaml(); + + // requires io.fabric8:kubernetes-client:5.11.0 or higher + Config config = Config.fromKubeconfig(kubeConfigYaml); + + DefaultKubernetesClient client = new DefaultKubernetesClient(config); + + // interact with the running K3s server, e.g.: + List nodes = client.nodes().list().getItems(); + // } + + Assertions.assertThat(nodes).hasSize(1); + } + } +} diff --git a/modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java b/modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java new file mode 100644 index 00000000000..970e2390457 --- /dev/null +++ b/modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java @@ -0,0 +1,43 @@ +package org.testcontainers.k3s; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1NodeList; +import io.kubernetes.client.util.Config; +import lombok.extern.slf4j.Slf4j; +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.utility.DockerImageName; + +import java.io.IOException; +import java.io.StringReader; + +@Slf4j +public class OfficialClientK3sContainerTest { + + @Test + public void shouldStartAndHaveListableNode() throws IOException, ApiException { + try ( + // starting_k3s { + K3sContainer k3s = new K3sContainer(DockerImageName.parse("rancher/k3s:v1.21.3-k3s1")) + .withLogConsumer(new Slf4jLogConsumer(log)) + // } + ) { + k3s.start(); + + // connecting_with_k8sio { + String kubeConfigYaml = k3s.getKubeConfigYaml(); + + ApiClient client = Config.fromConfig(new StringReader(kubeConfigYaml)); + CoreV1Api api = new CoreV1Api(client); + + // interact with the running K3s server, e.g.: + V1NodeList nodes = api.listNode(null, null, null, null, null, null, null, null, null, null); + // } + + Assertions.assertThat(nodes.getItems()).hasSize(1); + } + } +} diff --git a/modules/k3s/src/test/resources/logback-test.xml b/modules/k3s/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/k3s/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From af7cec02ea6b658dfcb61f50da0ef5dbe08cacaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Prinet?= Date: Mon, 17 Jan 2022 10:58:06 +0100 Subject: [PATCH 1691/4969] Bump up Gradle Enterprise plugin dependencies (#4926) --- examples/settings.gradle | 2 +- settings.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 8641c6134b1..f58ea83fb9b 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8.1" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.2" } } diff --git a/settings.gradle b/settings.gradle index 57f18b531b1..e4c65186fb8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8.1" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.2" } } From f7dcfa8593625a490017135698ff6dbb1d794f6b Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 17 Jan 2022 14:34:28 +0100 Subject: [PATCH 1692/4969] Use jackson 2.8.8 in k3s module (#4928) To ensure same jackson version across TC core and modules, this commit manually aligns them. --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 85ee36652b3..95d2d3bc97c 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: K3S" dependencies { api project(":testcontainers") - shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1' + shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' testImplementation 'io.fabric8:kubernetes-client:5.11.0' testImplementation 'io.kubernetes:client-java:14.0.0' From 19b58cdb7b8d2ca56c13743527bb0c674676b60d Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 17 Jan 2022 17:47:16 +0100 Subject: [PATCH 1693/4969] Use 2.8.8 compatible Jackson API (#4930) --- .../src/main/java/org/testcontainers/k3s/K3sContainer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java index 1080563226a..800d80c67e1 100644 --- a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java +++ b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java @@ -50,7 +50,12 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { is -> objectMapper.readValue(is, ObjectNode.class) ); - ObjectNode clusterConfig = rawKubeConfig.at("/clusters/0/cluster").require(); + JsonNode clusterNode = rawKubeConfig.at("/clusters/0/cluster"); + if (!clusterNode.isObject()) { + throw new IllegalStateException("'/clusters/0/cluster' expected to be an object"); + } + ObjectNode clusterConfig = (ObjectNode) clusterNode; + clusterConfig.replace("server", new TextNode("https://" + this.getHost() + ":" + this.getMappedPort(6443))); rawKubeConfig.set("current-context", new TextNode("default")); From 04937b52434edfac91bfbcfb672621d68c327891 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 17 Jan 2022 18:24:31 +0100 Subject: [PATCH 1694/4969] Replace jcenter with mavenCentral in all examples (#4931) --- examples/build.gradle | 2 +- examples/cucumber/build.gradle | 2 +- examples/disque-job-queue/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/mongodb-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/selenium-container/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- examples/solr-container/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/build.gradle b/examples/build.gradle index 83e196dac00..d340e297d33 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -5,6 +5,6 @@ subprojects { apply plugin:"java" repositories { - jcenter() + mavenCentral() } } diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index b018d3df5fc..4f462ed4740 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index ff03cee54cc..1639a091e91 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 3f28ca4ca9c..6351be31488 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 1d6c29b16eb..5ca68b2c514 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle index 23f193115ba..1ae43055790 100644 --- a/examples/mongodb-container/build.gradle +++ b/examples/mongodb-container/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 2046da278f2..c60d5f08cf4 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 38b3804b4b8..dff9ae7024f 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index f79edec4998..495c279937a 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -5,7 +5,7 @@ plugins { apply plugin: 'io.spring.dependency-management' repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 43d74d16244..a56f269fa40 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index c0c69300377..cec4f59625b 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } dependencies { diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 782f03b561e..09b82c34ea7 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -5,7 +5,7 @@ plugins { apply plugin: 'io.spring.dependency-management' repositories { - jcenter() + mavenCentral() } dependencies { From 34cfdc8e3fa86852a05131eb7f48b86966864c0a Mon Sep 17 00:00:00 2001 From: Richard North Date: Tue, 18 Jan 2022 13:12:32 +0000 Subject: [PATCH 1695/4969] Fix k3s for latest Docker for Mac (cgroupsv2) (#4937) --- .../org/testcontainers/k3s/K3sContainer.java | 6 +++ .../k3s/Fabric8K3sContainerTest.java | 42 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java index 800d80c67e1..511b309e0d5 100644 --- a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java +++ b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.node.TextNode; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.DockerObjectAccessor; import lombok.SneakyThrows; import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; @@ -25,6 +26,11 @@ public K3sContainer(DockerImageName dockerImageName) { addExposedPorts(6443, 8443); setPrivilegedMode(true); + withCreateContainerCmdModifier(it -> { + DockerObjectAccessor.overrideRawValue( + it.getHostConfig(), "CgroupnsMode", "host" + ); + }); addFileSystemBind("/sys/fs/cgroup", "/sys/fs/cgroup", BindMode.READ_WRITE); Map tmpFsMapping = new HashMap<>(); diff --git a/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java index 8e7b601c5b0..8b31c299634 100644 --- a/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java +++ b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java @@ -1,15 +1,27 @@ package org.testcontainers.k3s; +import io.fabric8.kubernetes.api.model.ContainerBuilder; +import io.fabric8.kubernetes.api.model.ContainerPortBuilder; import io.fabric8.kubernetes.api.model.Node; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodSpecBuilder; +import io.fabric8.kubernetes.api.model.ProbeBuilder; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.DefaultKubernetesClient; +import io.fabric8.kubernetes.client.dsl.PodResource; +import io.fabric8.kubernetes.client.dsl.Readiable; import lombok.extern.slf4j.Slf4j; import org.assertj.core.api.Assertions; +import org.assertj.core.api.Condition; import org.junit.Test; import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.utility.DockerImageName; import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; @Slf4j public class Fabric8K3sContainerTest { @@ -38,6 +50,36 @@ public void shouldStartAndHaveListableNode() { // } Assertions.assertThat(nodes).hasSize(1); + + // verify that we can start a pod + Pod helloworld = dummyStartablePod(); + client.pods().create(helloworld); + client.pods().inNamespace("default").withName("helloworld").waitUntilReady(30, TimeUnit.SECONDS); + + Assertions.assertThat(client.pods().inNamespace("default").withName("helloworld")) + .extracting(Readiable::isReady) + .isEqualTo(true); } } + + private Pod dummyStartablePod() { + PodSpec podSpec = new PodSpecBuilder() + .withContainers( + new ContainerBuilder() + .withName("helloworld") + .withImage("testcontainers/helloworld:1.1.0") + .withPorts(new ContainerPortBuilder().withContainerPort(8080).build()) + .withReadinessProbe(new ProbeBuilder().withNewTcpSocket().withNewPort(8080).endTcpSocket().build()) + .build() + ) + .build(); + + return new PodBuilder() + .withNewMetadata() + .withName("helloworld") + .withNamespace("default") + .endMetadata() + .withSpec(podSpec) + .build(); + } } From 5fe437f0e7ef18d735ab31245d81aed710690778 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 19 Jan 2022 13:09:34 +0100 Subject: [PATCH 1696/4969] Use JDK 1.8 in Azure pipelines (#4942) --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 53dabc6722b..0f01bb7bcd2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,7 +13,7 @@ jobs: AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) inputs: gradleWrapperFile: 'gradlew' - jdkVersionOption: '1.11' + jdkVersionOption: '1.8' options: '--no-daemon --continue' tasks: 'clean testcontainers:check' publishJUnitResults: true @@ -28,7 +28,7 @@ jobs: AWS_SECRET_ACCESS_KEY: $(aws.secretAccessKey) inputs: gradleWrapperFile: 'gradlew' - jdkVersionOption: '1.11' + jdkVersionOption: '1.8' options: '--no-daemon --continue' tasks: 'clean check -x testcontainers:test' publishJUnitResults: true From e50ae1da134eb9ab986e068ba820eaa7fbd98dc0 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Wed, 19 Jan 2022 16:51:41 +0100 Subject: [PATCH 1697/4969] Simplify dependency management for JUnit Jupiter (#4704) By using the junit-jupiter aggregator artifact. --- docs/quickstart/junit_5_quickstart.md | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/docs/quickstart/junit_5_quickstart.md b/docs/quickstart/junit_5_quickstart.md index eb43bf05797..b50272cb68d 100644 --- a/docs/quickstart/junit_5_quickstart.md +++ b/docs/quickstart/junit_5_quickstart.md @@ -22,10 +22,7 @@ Let's start from here, and see how to improve the test with Testcontainers: First, add Testcontainers as a dependency as follows: ```groovy tab='Gradle' -def junitJupiterVersion = '5.4.2' -testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion" -testImplementation "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion" -testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion" +testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" testImplementation "org.testcontainers:testcontainers:{{latest_version}}" testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" ``` @@ -33,20 +30,8 @@ testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" ```xml tab='Maven' org.junit.jupiter - junit-jupiter-api - 5.4.2 - test - - - org.junit.jupiter - junit-jupiter-params - 5.4.2 - test - - - org.junit.jupiter - junit-jupiter-engine - 5.4.2 + junit-jupiter + 5.8.1 test From f9538d16b7f636420cc269ce15fd6b5742be278c Mon Sep 17 00:00:00 2001 From: Alex Stockinger Date: Mon, 24 Jan 2022 11:16:32 +0100 Subject: [PATCH 1698/4969] Remove some dead code from PostgreSQLContainer (#4948) --- .../java/org/testcontainers/containers/PostgreSQLContainer.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 2b905bd3d37..3bfb508aa47 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -32,8 +32,6 @@ public class PostgreSQLContainer> extends private static final String FSYNC_OFF_OPTION = "fsync=off"; - private static final String QUERY_PARAM_SEPARATOR = "&"; - /** * @deprecated use {@link #PostgreSQLContainer(DockerImageName)} or {@link #PostgreSQLContainer(String)} instead */ From 639fe41a3ca71bf4b2401b82922bb8f20e2cf41d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Jan 2022 12:32:54 +0100 Subject: [PATCH 1699/4969] Update docs version to 1.16.3 (#4932) --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 827ef6a836d..694fca299ca 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -98,4 +98,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.16.2 + latest_version: 1.16.3 From 242dfde521020ea803a37941b6d043d6bafb56d1 Mon Sep 17 00:00:00 2001 From: Tayeb Chlyah Date: Mon, 31 Jan 2022 09:31:17 +0100 Subject: [PATCH 1700/4969] [Couchbase] Add support for Eventing service (#4953) --- .../couchbase/CouchbaseContainer.java | 43 +++++++++++++++++-- .../couchbase/CouchbaseService.java | 7 ++- .../couchbase/CouchbaseContainerTest.java | 18 +++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 5007a8d5ccf..c2becc68fc3 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -74,6 +74,10 @@ public class CouchbaseContainer extends GenericContainer { private static final int ANALYTICS_SSL_PORT = 18095; + private static final int EVENTING_PORT = 8096; + + private static final int EVENTING_SSL_PORT = 18096; + private static final int KV_PORT = 11210; private static final int KV_SSL_PORT = 11207; @@ -196,6 +200,17 @@ public CouchbaseContainer withAnalyticsService() { return this; } + /** + * Enables the eventing service which is not enabled by default. + * + * @return this {@link CouchbaseContainer} for chaining purposes. + */ + public CouchbaseContainer withEventingService() { + checkNotRunning(); + this.enabledServices.add(CouchbaseService.EVENTING); + return this; + } + public final String getUsername() { return username; } @@ -232,7 +247,9 @@ protected void configure() { ANALYTICS_PORT, ANALYTICS_SSL_PORT, KV_PORT, - KV_SSL_PORT + KV_SSL_PORT, + EVENTING_PORT, + EVENTING_SSL_PORT ); WaitAllStrategy waitStrategy = new WaitAllStrategy(); @@ -278,6 +295,16 @@ protected void configure() { ); } + if (enabledServices.contains(CouchbaseService.EVENTING)) { + waitStrategy = waitStrategy.withStrategy( + new HttpWaitStrategy() + .forPath("/api/v1/config") + .forPort(EVENTING_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + ); + } + waitingFor(waitStrategy); } @@ -328,8 +355,13 @@ private void initializeIsEnterprise() { throw new IllegalStateException("Couchbase /pools did not return valid JSON"); } - if (!isEnterprise && enabledServices.contains(CouchbaseService.ANALYTICS)) { - throw new IllegalStateException("The Analytics Service is only supported with the Enterprise version"); + if (!isEnterprise) { + if (enabledServices.contains(CouchbaseService.ANALYTICS)) { + throw new IllegalStateException("The Analytics Service is only supported with the Enterprise version"); + } + if (enabledServices.contains(CouchbaseService.EVENTING)) { + throw new IllegalStateException("The Eventing Service is only supported with the Enterprise version"); + } } } @@ -452,6 +484,11 @@ private void configureExternalPorts() { builder.add("cbasSSL", Integer.toString(getMappedPort(ANALYTICS_SSL_PORT))); } + if (enabledServices.contains(CouchbaseService.EVENTING)) { + builder.add("eventingAdminPort", Integer.toString(getMappedPort(EVENTING_PORT))); + builder.add("eventingSSL", Integer.toString(getMappedPort(EVENTING_SSL_PORT))); + } + @Cleanup Response response = doHttpRequest( MGMT_PORT, "/node/controller/setupAlternateAddresses/external", diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java index a314bd5ccfc..ffb0c9f7f1f 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java @@ -46,7 +46,12 @@ public enum CouchbaseService { /** * Analytics service. */ - ANALYTICS("cbas", 1024); + ANALYTICS("cbas", 1024), + + /** + * Eventing service. + */ + EVENTING("eventing", 256); private final String identifier; diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index 5d2d7d9402a..c91f3f12d7c 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -35,9 +35,9 @@ public class CouchbaseContainerTest { private static final DockerImageName COUCHBASE_IMAGE_ENTERPRISE = - DockerImageName.parse("couchbase/server:enterprise-6.6.2"); + DockerImageName.parse("couchbase/server:enterprise-7.0.3"); private static final DockerImageName COUCHBASE_IMAGE_COMMUNITY = - DockerImageName.parse("couchbase/server:community-6.6.0"); + DockerImageName.parse("couchbase/server:community-7.0.2"); @Test public void testBasicContainerUsageForEnterpriseContainer() { @@ -127,6 +127,20 @@ public void testFailureIfCommunityUsedWithAnalytics() { } } + /** + * Make sure that the code fails fast if the Eventing service is enabled on the community + * edition which is not supported. + */ + @Test + public void testFailureIfCommunityUsedWithEventing() { + try ( + CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) + .withEnabledServices(CouchbaseService.KV, CouchbaseService.EVENTING) + ) { + assertThrows(ContainerLaunchException.class, () -> setUpClient(container, cluster -> {})); + } + } + private void setUpClient(CouchbaseContainer container, Consumer consumer) { container.start(); From 205f21c242d067d67fc7f09d8d4738da28efcd08 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 31 Jan 2022 08:53:01 -0500 Subject: [PATCH 1701/4969] Prune from JVM hook if Ryuk is disabled (#4960) If Ryuk is disabled, singleton containers and other uncontrolled containers were remaining dangling. This change adds best-effort Ryuk-like functionality that will use a JVM hook to clean by labels. Co-authored-by: Richard North --- .../testcontainers/DockerClientFactory.java | 3 + .../containers/DockerComposeContainer.java | 6 +- .../utility/ResourceReaper.java | 97 +++++++++++++++---- 3 files changed, 82 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 36c4c717b76..1ad7a0bec7e 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -225,6 +225,9 @@ public void close() { } else { log.debug("Ryuk is disabled"); ryukContainerId = null; + // best-efforts cleanup at JVM shutdown, without using the Ryuk container + //noinspection deprecation + ResourceReaper.instance().setHook(); } boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks(); diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 961d066cb91..b56c70cb959 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -41,7 +41,6 @@ import java.io.File; import java.time.Duration; -import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -56,7 +55,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; -import java.util.stream.Collectors; import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkArgument; @@ -310,8 +308,8 @@ private void runWithCompose(String cmd) { } private void registerContainersForShutdown() { - ResourceReaper.instance().registerFilterForCleanup(Arrays.asList( - new SimpleEntry<>("label", "com.docker.compose.project=" + project) + ResourceReaper.instance().registerLabelsFilterForCleanup(Collections.singletonMap( + "com.docker.compose.project", project )); } diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index f43835fd01b..8c2cd3a6108 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -5,12 +5,14 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.Container; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Network; import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.api.model.PruneType; import com.github.dockerjava.api.model.Volume; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; @@ -36,6 +38,7 @@ import java.nio.charset.StandardCharsets; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -58,7 +61,14 @@ public final class ResourceReaper { private static final Logger LOGGER = LoggerFactory.getLogger(ResourceReaper.class); - private static final List>> DEATH_NOTE = new ArrayList<>(); + private static final List>> DEATH_NOTE = new ArrayList<>( + Arrays.asList( + DockerClientFactory.DEFAULT_LABELS.entrySet().stream() + .>map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())) + .collect(Collectors.toList()) + ) + ); + private static final RateLimiter RYUK_ACK_RATE_LIMITER = RateLimiterBuilder .newBuilder() .withRate(4, TimeUnit.SECONDS) @@ -66,16 +76,13 @@ public final class ResourceReaper { .build(); private static ResourceReaper instance; - private final DockerClient dockerClient; + private static AtomicBoolean ryukStarted = new AtomicBoolean(false); + private final DockerClient dockerClient = DockerClientFactory.lazyClient(); private Map registeredContainers = new ConcurrentHashMap<>(); private Set registeredNetworks = Sets.newConcurrentHashSet(); private Set registeredImages = Sets.newConcurrentHashSet(); private AtomicBoolean hookIsSet = new AtomicBoolean(false); - private ResourceReaper() { - dockerClient = DockerClientFactory.instance().client(); - } - /** * @@ -173,14 +180,6 @@ public InspectContainerResponse getContainerInfo() { CountDownLatch ryukScheduledLatch = new CountDownLatch(1); - synchronized (DEATH_NOTE) { - DEATH_NOTE.add( - DockerClientFactory.DEFAULT_LABELS.entrySet().stream() - .>map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())) - .collect(Collectors.toList()) - ); - } - String host = containerState.getHost(); Integer ryukPort = containerState.getFirstMappedPort(); Thread kiraThread = new Thread( @@ -238,6 +237,7 @@ public InspectContainerResponse getContainerInfo() { } } + ryukStarted.set(true); return ryukContainerId; } @@ -253,7 +253,7 @@ public synchronized static ResourceReaper instance() { * Perform a cleanup. */ public synchronized void performCleanup() { - registeredContainers.forEach(this::stopContainer); + registeredContainers.forEach(this::removeContainer); registeredNetworks.forEach(this::removeNetwork); registeredImages.forEach(this::removeImage); } @@ -262,7 +262,9 @@ public synchronized void performCleanup() { * Register a filter to be cleaned up. * * @param filter the filter + * @deprecated only label filter is supported by the prune API, use {@link #registerLabelsFilterForCleanup(Map)} */ + @Deprecated public void registerFilterForCleanup(List> filter) { synchronized (DEATH_NOTE) { DEATH_NOTE.add(filter); @@ -270,6 +272,19 @@ public void registerFilterForCleanup(List> filter) { } } + /** + * Register a label to be cleaned up. + * + * @param labels the filter + */ + public void registerLabelsFilterForCleanup(Map labels) { + registerFilterForCleanup( + labels.entrySet().stream() + .map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())) + .collect(Collectors.toList()) + ); + } + /** * Register a container to be cleaned up, either on explicit call to stopAndRemoveContainer, or at JVM shutdown. * @@ -287,7 +302,7 @@ public void registerContainerForCleanup(String containerId, String imageName) { * @param containerId the ID of the container */ public void stopAndRemoveContainer(String containerId) { - stopContainer(containerId, registeredContainers.get(containerId)); + removeContainer(containerId, registeredContainers.get(containerId)); registeredContainers.remove(containerId); } @@ -299,12 +314,12 @@ public void stopAndRemoveContainer(String containerId) { * @param imageName the image name of the container (used for logging) */ public void stopAndRemoveContainer(String containerId, String imageName) { - stopContainer(containerId, imageName); + removeContainer(containerId, imageName); registeredContainers.remove(containerId); } - private void stopContainer(String containerId, String imageName) { + private void removeContainer(String containerId, String imageName) { boolean running; try { InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); @@ -444,10 +459,52 @@ private void removeImage(String dockerImageName) { } } - private void setHook() { + private void prune(PruneType pruneType, List> filters) { + String[] labels = filters.stream() + .filter(it -> "label".equals(it.getKey())) + .map(Map.Entry::getValue) + .toArray(String[]::new); + switch (pruneType) { + // Docker only prunes stopped containers, so we have to do it manually + case CONTAINERS: + List containers = dockerClient.listContainersCmd() + .withFilter("label", Arrays.asList(labels)) + .withShowAll(true) + .exec(); + + containers.parallelStream().forEach(container -> { + removeContainer(container.getId(), container.getImage()); + }); + break; + default: + dockerClient.pruneCmd(pruneType).withLabelFilter(labels).exec(); + break; + } + } + + /** + * @deprecated internal API, not intended for public usage + */ + @Deprecated + public void setHook() { if (hookIsSet.compareAndSet(false, true)) { // If the JVM stops without containers being stopped, try and stop the container. - Runtime.getRuntime().addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, this::performCleanup)); + Runtime.getRuntime().addShutdownHook( + new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, + () -> { + performCleanup(); + + if (!ryukStarted.get()) { + synchronized (DEATH_NOTE) { + DEATH_NOTE.forEach(filters -> prune(PruneType.CONTAINERS, filters)); + DEATH_NOTE.forEach(filters -> prune(PruneType.NETWORKS, filters)); + DEATH_NOTE.forEach(filters -> prune(PruneType.VOLUMES, filters)); + DEATH_NOTE.forEach(filters -> prune(PruneType.IMAGES, filters)); + } + } + } + ) + ); } } From 53538f4898dad0a0989b40e6f7532a4178df326e Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 1 Feb 2022 11:18:05 +0100 Subject: [PATCH 1702/4969] Remove the INCUBATING label from CockroachDB module docs (#4963) --- docs/modules/databases/cockroachdb.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/modules/databases/cockroachdb.md b/docs/modules/databases/cockroachdb.md index 540f4820a84..17c5efae8f8 100644 --- a/docs/modules/databases/cockroachdb.md +++ b/docs/modules/databases/cockroachdb.md @@ -1,8 +1,5 @@ # CockroachDB Module -!!! note - This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. - See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. ## Adding this module to your project dependencies From 0b12ed23ed757347c81d9e55847d73d9bc6de2dd Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 1 Feb 2022 05:38:11 -0500 Subject: [PATCH 1703/4969] Extract `RyukResourceReaper` (#4959) --- .../utility/ResourceReaper.java | 172 +--------------- .../utility/RyukResourceReaper.java | 188 ++++++++++++++++++ 2 files changed, 192 insertions(+), 168 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 8c2cd3a6108..69c849b6c82 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -1,30 +1,18 @@ package org.testcontainers.utility; import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; -import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Container; -import com.github.dockerjava.api.model.ExposedPort; -import com.github.dockerjava.api.model.Frame; -import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Network; -import com.github.dockerjava.api.model.PortBinding; -import com.github.dockerjava.api.model.Ports; import com.github.dockerjava.api.model.PruneType; -import com.github.dockerjava.api.model.Volume; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; import com.google.common.collect.Sets; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.rnorth.ducttape.ratelimits.RateLimiter; -import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.ContainerState; import java.io.BufferedReader; import java.io.IOException; @@ -32,26 +20,16 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import java.net.InetSocketAddress; -import java.net.Socket; import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.awaitility.Awaitility.await; /** * Component that responsible for container removal and automatic cleanup of dead containers at JVM shutdown. @@ -61,7 +39,7 @@ public final class ResourceReaper { private static final Logger LOGGER = LoggerFactory.getLogger(ResourceReaper.class); - private static final List>> DEATH_NOTE = new ArrayList<>( + static final List>> DEATH_NOTE = new ArrayList<>( Arrays.asList( DockerClientFactory.DEFAULT_LABELS.entrySet().stream() .>map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())) @@ -69,12 +47,6 @@ public final class ResourceReaper { ) ); - private static final RateLimiter RYUK_ACK_RATE_LIMITER = RateLimiterBuilder - .newBuilder() - .withRate(4, TimeUnit.SECONDS) - .withConstantThroughput() - .build(); - private static ResourceReaper instance; private static AtomicBoolean ryukStarted = new AtomicBoolean(false); private final DockerClient dockerClient = DockerClientFactory.lazyClient(); @@ -98,147 +70,11 @@ public static String start(String hostIpAddress, DockerClient client) { * @deprecated internal API */ @Deprecated - @SneakyThrows(InterruptedException.class) public static String start(DockerClient client) { - String ryukImage = ImageNameSubstitutor.instance() - .apply(DockerImageName.parse("testcontainers/ryuk:0.3.3")) - .asCanonicalNameString(); - DockerClientFactory.instance().checkAndPullImage(client, ryukImage); - - List binds = new ArrayList<>(); - binds.add(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); - - ExposedPort ryukExposedPort = ExposedPort.tcp(8080); - String ryukContainerId = client.createContainerCmd(ryukImage) - .withHostConfig( - new HostConfig() - .withAutoRemove(true) - .withPortBindings(new PortBinding(Ports.Binding.empty(), ryukExposedPort)) - ) - .withExposedPorts(ryukExposedPort) - .withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID) - .withLabels(Collections.singletonMap(DockerClientFactory.TESTCONTAINERS_LABEL, "true")) - .withBinds(binds) - .withPrivileged(TestcontainersConfiguration.getInstance().isRyukPrivileged()) - .exec() - .getId(); - - client.startContainerCmd(ryukContainerId).exec(); - - StringBuilder ryukLog = new StringBuilder(); - - ResultCallback.Adapter logCallback = client.logContainerCmd(ryukContainerId) - .withSince(0) - .withFollowStream(true) - .withStdOut(true) - .withStdErr(true) - .exec(new ResultCallback.Adapter() { - @Override - public void onNext(Frame frame) { - ryukLog.append(new String(frame.getPayload(), StandardCharsets.UTF_8)); - } - }); - - InspectContainerResponse inspectedContainer; - try { - // inspect container response might initially not contain the mapped port - inspectedContainer = await() - .atMost(5, TimeUnit.SECONDS) - .pollInterval(DynamicPollInterval.ofMillis(50)) - .pollInSameThread() - .until( - () -> client.inspectContainerCmd(ryukContainerId).exec(), - inspectContainerResponse -> { - return inspectContainerResponse - .getNetworkSettings() - .getPorts() - .getBindings() - .values() - .stream() - .anyMatch(Objects::nonNull); - } - ); - } catch (Exception e) { - log.warn("Ryuk container cannot be inspected and probably had a problem starting. Ryuk's logs:\n{}", ryukLog); - throw new IllegalStateException("Ryuk failed to start", e); - } - - ContainerState containerState = new ContainerState() { - - @Override - public List getExposedPorts() { - return Stream.of(getContainerInfo().getConfig().getExposedPorts()) - .map(ExposedPort::getPort) - .collect(Collectors.toList()); - } - - @Override - public InspectContainerResponse getContainerInfo() { - return inspectedContainer; - } - }; - - CountDownLatch ryukScheduledLatch = new CountDownLatch(1); - - String host = containerState.getHost(); - Integer ryukPort = containerState.getFirstMappedPort(); - Thread kiraThread = new Thread( - DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, - () -> { - while (true) { - RYUK_ACK_RATE_LIMITER.doWhenReady(() -> { - int index = 0; - // not set the read timeout, as Ryuk would not send anything unless a new filter is submitted, meaning that we would get a timeout exception pretty quick - try (Socket clientSocket = new Socket()) { - clientSocket.connect(new InetSocketAddress(host, ryukPort), 5 * 1000); - FilterRegistry registry = new FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); - - synchronized (DEATH_NOTE) { - while (true) { - if (DEATH_NOTE.size() <= index) { - try { - DEATH_NOTE.wait(1_000); - continue; - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - List> filters = DEATH_NOTE.get(index); - boolean isAcknowledged = registry.register(filters); - if (isAcknowledged) { - log.debug("Received 'ACK' from Ryuk"); - ryukScheduledLatch.countDown(); - index++; - } else { - log.debug("Didn't receive 'ACK' from Ryuk. Will retry to send filters."); - } - } - } - } catch (IOException e) { - log.warn("Can not connect to Ryuk at {}:{}", host, ryukPort, e); - } - }); - } - }, - "testcontainers-ryuk" - ); - kiraThread.setDaemon(true); - kiraThread.start(); - try { - // We need to wait before we can start any containers to make sure that we delete them - if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { - log.error("Timed out waiting for Ryuk container to start. Ryuk's logs:\n{}", ryukLog); - throw new IllegalStateException(String.format("Could not connect to Ryuk at %s:%s", host, ryukPort)); - } - } finally { - try { - logCallback.close(); - } catch (IOException ignored) { - } - } - + RyukResourceReaper ryuk = new RyukResourceReaper(client); + String containerId = ryuk.getContainerId(); ryukStarted.set(true); - return ryukContainerId; + return containerId; } public synchronized static ResourceReaper instance() { diff --git a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java new file mode 100644 index 00000000000..e8aed92fa9d --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java @@ -0,0 +1,188 @@ +package org.testcontainers.utility; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.api.model.Volume; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.rnorth.ducttape.ratelimits.RateLimiter; +import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.ContainerState; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.awaitility.Awaitility.await; + +@Slf4j +class RyukResourceReaper { + + private static final RateLimiter RYUK_ACK_RATE_LIMITER = RateLimiterBuilder + .newBuilder() + .withRate(4, TimeUnit.SECONDS) + .withConstantThroughput() + .build(); + + @Getter + private final String containerId; + + @SneakyThrows(InterruptedException.class) + RyukResourceReaper(DockerClient client) { + String ryukImage = ImageNameSubstitutor.instance() + .apply(DockerImageName.parse("testcontainers/ryuk:0.3.3")) + .asCanonicalNameString(); + DockerClientFactory.instance().checkAndPullImage(client, ryukImage); + + List binds = new ArrayList<>(); + binds.add(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); + + ExposedPort ryukExposedPort = ExposedPort.tcp(8080); + containerId = client.createContainerCmd(ryukImage) + .withHostConfig( + new HostConfig() + .withAutoRemove(true) + .withPortBindings(new PortBinding(Ports.Binding.empty(), ryukExposedPort)) + ) + .withExposedPorts(ryukExposedPort) + .withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID) + .withLabels(Collections.singletonMap(DockerClientFactory.TESTCONTAINERS_LABEL, "true")) + .withBinds(binds) + .withPrivileged(TestcontainersConfiguration.getInstance().isRyukPrivileged()) + .exec() + .getId(); + + client.startContainerCmd(containerId).exec(); + + StringBuilder ryukLog = new StringBuilder(); + + ResultCallback.Adapter logCallback = client.logContainerCmd(containerId) + .withSince(0) + .withFollowStream(true) + .withStdOut(true) + .withStdErr(true) + .exec(new ResultCallback.Adapter() { + @Override + public void onNext(Frame frame) { + ryukLog.append(new String(frame.getPayload(), StandardCharsets.UTF_8)); + } + }); + + InspectContainerResponse inspectedContainer; + try { + // inspect container response might initially not contain the mapped port + inspectedContainer = await() + .atMost(5, TimeUnit.SECONDS) + .pollInterval(DynamicPollInterval.ofMillis(50)) + .pollInSameThread() + .until( + () -> client.inspectContainerCmd(containerId).exec(), + inspectContainerResponse -> { + return inspectContainerResponse + .getNetworkSettings() + .getPorts() + .getBindings() + .values() + .stream() + .anyMatch(Objects::nonNull); + } + ); + } catch (Exception e) { + log.warn("Ryuk container cannot be inspected and probably had a problem starting. Ryuk's logs:\n{}", ryukLog); + throw new IllegalStateException("Ryuk failed to start", e); + } + + ContainerState containerState = new ContainerState() { + + @Override + public List getExposedPorts() { + return Stream.of(getContainerInfo().getConfig().getExposedPorts()) + .map(ExposedPort::getPort) + .collect(Collectors.toList()); + } + + @Override + public InspectContainerResponse getContainerInfo() { + return inspectedContainer; + } + }; + + CountDownLatch ryukScheduledLatch = new CountDownLatch(1); + + String host = containerState.getHost(); + Integer ryukPort = containerState.getFirstMappedPort(); + Thread kiraThread = new Thread( + DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, + () -> { + while (true) { + RYUK_ACK_RATE_LIMITER.doWhenReady(() -> { + int index = 0; + // not set the read timeout, as Ryuk would not send anything unless a new filter is submitted, meaning that we would get a timeout exception pretty quick + try (Socket clientSocket = new Socket()) { + clientSocket.connect(new InetSocketAddress(host, ryukPort), 5 * 1000); + ResourceReaper.FilterRegistry registry = new ResourceReaper.FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); + + synchronized (ResourceReaper.DEATH_NOTE) { + while (true) { + if (ResourceReaper.DEATH_NOTE.size() <= index) { + try { + ResourceReaper.DEATH_NOTE.wait(1_000); + continue; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + List> filters = ResourceReaper.DEATH_NOTE.get(index); + boolean isAcknowledged = registry.register(filters); + if (isAcknowledged) { + log.debug("Received 'ACK' from Ryuk"); + ryukScheduledLatch.countDown(); + index++; + } else { + log.debug("Didn't receive 'ACK' from Ryuk. Will retry to send filters."); + } + } + } + } catch (IOException e) { + log.warn("Can not connect to Ryuk at {}:{}", host, ryukPort, e); + } + }); + } + }, + "testcontainers-ryuk" + ); + kiraThread.setDaemon(true); + kiraThread.start(); + try { + // We need to wait before we can start any containers to make sure that we delete them + if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { + log.error("Timed out waiting for Ryuk container to start. Ryuk's logs:\n{}", ryukLog); + throw new IllegalStateException(String.format("Could not connect to Ryuk at %s:%s", host, ryukPort)); + } + } finally { + try { + logCallback.close(); + } catch (IOException ignored) { + } + } + } +} From fd6e581f9ab5e904ab30709e614c8ad2b8221871 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:34 +0000 Subject: [PATCH 1704/4969] Bump java-client from 3.2.4 to 3.2.5 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.2.4 to 3.2.5. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.2.4...java-client-3.2.5) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index ea720ca3725..2c68f163a57 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') - testImplementation 'com.couchbase.client:java-client:3.2.4' + testImplementation 'com.couchbase.client:java-client:3.2.5' testImplementation 'org.awaitility:awaitility:4.1.1' } From 865a5c1c132cdc9765f6fae06607870661429a90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:35 +0000 Subject: [PATCH 1705/4969] Bump tomcat-jdbc from 10.0.14 to 10.0.16 in /modules/jdbc Bumps tomcat-jdbc from 10.0.14 to 10.0.16. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index a6f71690e1e..71940e0026a 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.14' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.16' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From cc031c6b64666812a1c9f75f9d0ae65a647bae83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:36 +0000 Subject: [PATCH 1706/4969] Bump tomcat-jdbc from 10.0.14 to 10.0.16 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.14 to 10.0.16. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 46088aa45ac..98570722e6a 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.14' + api 'org.apache.tomcat:tomcat-jdbc:10.0.16' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.27' } From a080cc5f4e764aa5e7edbe20e4dd8841e6e9e834 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:37 +0000 Subject: [PATCH 1707/4969] Bump neo4j-java-driver from 4.4.2 to 4.4.3 in /modules/neo4j Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 4.4.2 to 4.4.3. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/4.4.2...4.4.3) --- updated-dependencies: - dependency-name: org.neo4j.driver:neo4j-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index fe99774538c..1d5cffc1955 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -33,6 +33,6 @@ dependencies { api project(":testcontainers") - testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.2' + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.3' testImplementation 'org.assertj:assertj-core:3.22.0' } From 4cf33a40bf1ab7a36289234a6b27d65b200cfb94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:38 +0000 Subject: [PATCH 1708/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.137 to 1.12.150. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.137...1.12.150) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 52881514ac5..ce09dde17e6 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.137' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.131' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.150' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.150' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 38bd2919b94344113b1e782d3d580ac4992a824d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:38 +0000 Subject: [PATCH 1709/4969] Bump mariadb-java-client from 2.7.4 to 3.0.3 in /modules/mariadb Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.7.4 to 3.0.3. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.7.4...3.0.3) --- updated-dependencies: - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index af67719f8ad..8d65ed00deb 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:1.0.3' testImplementation project(':jdbc-test') - testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4' + testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.3' testImplementation testFixtures(project(':r2dbc')) testImplementation 'org.mariadb:r2dbc-mariadb:1.0.2' From 04e88c03810a97c38d306223ba4f26b8d8d79ccd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:38 +0000 Subject: [PATCH 1710/4969] Bump aws-java-sdk-sqs from 1.12.139 to 1.12.150 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.139 to 1.12.150. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.139...1.12.150) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 7bfec27ccaf..6e0f620beed 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.137' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.139' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.150' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.139' testImplementation 'software.amazon.awssdk:s3:2.17.108' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 7b8edbda16c4b9c962b568e71212159ffe93c0d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:39 +0000 Subject: [PATCH 1711/4969] Bump testcontainers from 1.16.2 to 1.16.3 in /core Bumps [testcontainers](https://github.com/testcontainers/testcontainers-java) from 1.16.2 to 1.16.3. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.16.2...1.16.3) --- updated-dependencies: - dependency-name: org.testcontainers:testcontainers dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 074273e8fc7..a5e627a77aa 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -53,7 +53,7 @@ configurations.all { } dependencies { - baseline 'org.testcontainers:testcontainers:1.16.2', { + baseline 'org.testcontainers:testcontainers:1.16.3', { exclude group: "*", module: "*" } From cf2e9d83ccea626f1acb758cb8afde0effc9a633 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:40 +0000 Subject: [PATCH 1712/4969] Bump mysql-connector-java from 8.0.27 to 8.0.28 in /modules/spock Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.27 to 8.0.28. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.27...8.0.28) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index cec493cf77d..26158b6db57 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.3.1' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.28' testCompileClasspath 'org.jetbrains:annotations:23.0.0' } From 293059233d4ae97bd5c852dc6e2b6d34843640d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:41 +0000 Subject: [PATCH 1713/4969] Bump jedis from 4.0.1 to 4.1.1 in /examples Bumps [jedis](https://github.com/redis/jedis) from 4.0.1 to 4.1.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v4.0.1...v4.1.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index c60d5f08cf4..ec3d0bd134c 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:4.0.1' + implementation 'redis.clients:jedis:4.1.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index dff9ae7024f..32e35f07766 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:4.0.1' + implementation 'redis.clients:jedis:4.1.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index a56f269fa40..2ebaba5be50 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:4.0.1' + implementation 'redis.clients:jedis:4.1.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From 98bf56bbfb27f21b9020f97ca6288a2cb0da6421 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:41 +0000 Subject: [PATCH 1714/4969] Bump mockito-core from 4.2.0 to 4.3.1 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 4.2.0 to 4.3.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.2.0...v4.3.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 77ff3f842d0..2069545531d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:4.0.1' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:4.2.0') { + testImplementation ('org.mockito:mockito-core:4.3.1') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.22.0' From ca9423cfe0b83417a795cfe05edb6ff6527c7d73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:42 +0000 Subject: [PATCH 1715/4969] Bump transport from 7.16.2 to 7.17.0 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.16.2 to 7.17.0. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.16.2...v7.17.0) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 3f517353f24..fca8ecfe9fb 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2" - testImplementation "org.elasticsearch.client:transport:7.16.2" + testImplementation "org.elasticsearch.client:transport:7.17.0" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 7aabc275a4b810ab5200104b665d10b6a9c06e91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:42 +0000 Subject: [PATCH 1716/4969] Bump aws-java-sdk-s3 from 1.12.137 to 1.12.150 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.137 to 1.12.150. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.137...1.12.150) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 7bfec27ccaf..54a3f71a769 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.137' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.150' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.139' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.139' From 5cd78705c86800e790e3662e1191db62f6ff8455 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:44 +0000 Subject: [PATCH 1717/4969] Bump slf4j-api from 1.7.32 to 1.7.35 in /core Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.32 to 1.7.35. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.32...v_1.7.35) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 074273e8fc7..f9b373083ad 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -58,7 +58,7 @@ dependencies { } api 'junit:junit:4.13.2' - api 'org.slf4j:slf4j-api:1.7.32' + api 'org.slf4j:slf4j-api:1.7.35' compileOnly 'org.jetbrains:annotations:23.0.0' testCompileClasspath 'org.jetbrains:annotations:23.0.0' api 'org.apache.commons:commons-compress:1.21' From 0f0398f4a78f86c43baff8fab62cab80112fc647 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:44 +0000 Subject: [PATCH 1718/4969] Bump org.springframework.boot from 2.6.2 to 2.6.3 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.6.2 to 2.6.3. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.6.2...v2.6.3) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 495c279937a..d728c13e3c0 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.2' + id 'org.springframework.boot' version '2.6.3' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 25d92d3ea16..5a9495d86bf 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.6.2" + id("org.springframework.boot") version "2.6.3" id("org.jetbrains.kotlin.jvm") version "1.6.10" id("org.jetbrains.kotlin.plugin.spring") version "1.6.10" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 09b82c34ea7..ace47d12ebe 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.2' + id 'org.springframework.boot' version '2.6.3' } apply plugin: 'io.spring.dependency-management' From 8ed5e42c62f6b6ebc16f50de948f3f029ec7a95e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:44 +0000 Subject: [PATCH 1719/4969] Bump jedis from 4.0.1 to 4.1.1 in /modules/junit-jupiter Bumps [jedis](https://github.com/redis/jedis) from 4.0.1 to 4.1.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v4.0.1...v4.1.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 77ff3f842d0..0c2ffd8d41d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:4.0.1' + testImplementation 'redis.clients:jedis:4.1.1' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testImplementation ('org.mockito:mockito-core:4.2.0') { exclude(module: 'hamcrest-core') From b24418439fe7280f23a399cf4b1c25953daac580 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:46 +0000 Subject: [PATCH 1720/4969] Bump postgresql from 42.3.1 to 42.3.2 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.1 to 42.3.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.1...REL42.3.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 77ff3f842d0..f450bd15a24 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' - testRuntimeOnly 'org.postgresql:postgresql:42.3.1' + testRuntimeOnly 'org.postgresql:postgresql:42.3.2' testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' } From 8899d1ea4d4f245fb3f0ef5f0e6817e322ed94c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:47 +0000 Subject: [PATCH 1721/4969] Bump postgresql from 42.3.1 to 42.3.2 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.1 to 42.3.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.1...REL42.3.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 5ca68b2c514..37fc1b71226 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'org.json:json:20211205' - testImplementation 'org.postgresql:postgresql:42.3.1' + testImplementation 'org.postgresql:postgresql:42.3.2' testImplementation 'ch.qos.logback:logback-classic:1.2.10' testImplementation 'org.testcontainers:postgresql' } From fc2a95e0e66553a1970f04b3d85c200753d6d8ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:47 +0000 Subject: [PATCH 1722/4969] Bump mockito-core from 4.2.0 to 4.3.1 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 4.2.0 to 4.3.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.2.0...v4.3.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 074273e8fc7..e835eac8b38 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -93,7 +93,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.14.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' - testImplementation ('org.mockito:mockito-core:4.2.0') { + testImplementation ('org.mockito:mockito-core:4.3.1') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 2e520b2bd3a9e23019b4953ea3c1d7d1454c4be6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:50 +0000 Subject: [PATCH 1723/4969] Bump amqp-client from 5.14.0 to 5.14.1 in /core Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.14.0 to 5.14.1. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.14.0...v5.14.1) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 074273e8fc7..c5c5771f649 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -90,7 +90,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:4.0.1' - testImplementation 'com.rabbitmq:amqp-client:5.14.0' + testImplementation 'com.rabbitmq:amqp-client:5.14.1' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' testImplementation ('org.mockito:mockito-core:4.2.0') { From 7085b4f1494b4a491f3ac896b8416924f20cc536 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:50 +0000 Subject: [PATCH 1724/4969] Bump kafka-clients from 3.0.0 to 3.1.0 in /examples Bumps kafka-clients from 3.0.0 to 3.1.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 6351be31488..2e37410bcea 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompileOnly "org.projectlombok:lombok:1.18.22" testAnnotationProcessor "org.projectlombok:lombok:1.18.22" testImplementation 'org.testcontainers:kafka' - testImplementation 'org.apache.kafka:kafka-clients:3.0.0' + testImplementation 'org.apache.kafka:kafka-clients:3.1.0' testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.10' From 3ac2016e162186c7383b2c73c54084a78d940ec7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:00:54 +0000 Subject: [PATCH 1725/4969] Bump cucumber-java from 7.2.2 to 7.2.3 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 7.2.2 to 7.2.3. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.2.2...v7.2.3) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 4f462ed4740..9a402b51b47 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:7.2.2' + testImplementation 'io.cucumber:cucumber-java:7.2.3' testImplementation 'io.cucumber:cucumber-junit:7.2.2' testImplementation 'org.testcontainers:selenium' } From eaa6a9f0fbffa61e9dfbce97262ec704a1a51459 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:01:23 +0000 Subject: [PATCH 1726/4969] Bump release-drafter/release-drafter from 5.15.0 to 5.17.6 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.15.0 to 5.17.6. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/fe52e97d262833ae07d05efaf1a239df3f1b5cd4...436492609a0c75979acf131d57f61b5321571950) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 629280b1241..aec34acb8ff 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -12,6 +12,6 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@fe52e97d262833ae07d05efaf1a239df3f1b5cd4 # v5.15.0 + - uses: release-drafter/release-drafter@436492609a0c75979acf131d57f61b5321571950 # v5.15.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 9100051f213d5c8391ae4730a1011e797f833349 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:01:26 +0000 Subject: [PATCH 1727/4969] Bump gradle-update/update-gradle-wrapper-action from 1.0.16 to 1.0.17 Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 1.0.16 to 1.0.17. - [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases) - [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/f31ab392a9d75029f9fd0883d8d6745c0139a006...5b865a8b4d09fdf6afaaa20397ba68455bb48f0d) --- updated-dependencies: - dependency-name: gradle-update/update-gradle-wrapper-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 612aec0b406..253e37c23eb 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@f31ab392a9d75029f9fd0883d8d6745c0139a006 # v1.0.13 + uses: gradle-update/update-gradle-wrapper-action@5b865a8b4d09fdf6afaaa20397ba68455bb48f0d # v1.0.13 with: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies From 15456fc10ffdd1116fde31c666bb91b4d7435163 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:02:38 +0000 Subject: [PATCH 1728/4969] Bump peter-evans/create-pull-request from 3.12.0 to 3.12.1 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 3.12.0 to 3.12.1. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/dcd5fd746d53dd8de555c0f10bca6c35628be47a...f22a7da129c901513876a2380e2dae9f8e145330) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 418598f230d..2c7626c7ec7 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -17,7 +17,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@dcd5fd746d53dd8de555c0f10bca6c35628be47a # v3.10.1 + uses: peter-evans/create-pull-request@f22a7da129c901513876a2380e2dae9f8e145330 # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From 60725f6dfa4d88b0e8e526519d5ef7b1dc7b3a33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:05:58 +0000 Subject: [PATCH 1729/4969] Bump trino-jdbc from 367 to 369 in /modules/trino Bumps trino-jdbc from 367 to 369. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index f9223c174a5..9bf0e24f06b 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:367' + testImplementation 'io.trino:trino-jdbc:369' compileOnly 'org.jetbrains:annotations:23.0.0' } From f5e943f31e5c1f51dc01cf3312ed64d060fd9c8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:05:59 +0000 Subject: [PATCH 1730/4969] Bump postgresql from 42.3.1 to 42.3.2 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.1 to 42.3.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.1...REL42.3.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index ee6a7e2731e..71011c6534b 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.3.1' + testImplementation 'org.postgresql:postgresql:42.3.2' } From 900ae910073066def9c422016b25bab310840ff3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:06:00 +0000 Subject: [PATCH 1731/4969] Bump google-cloud-firestore from 3.0.10 to 3.0.11 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.0.10 to 3.0.11. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.0.10...v3.0.11) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 07d0c06a04b..9cda3994e8d 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.2.2' - testImplementation 'com.google.cloud:google-cloud-firestore:3.0.10' + testImplementation 'com.google.cloud:google-cloud-firestore:3.0.11' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.1' From 9502c445d7eaddf899043a699791f39957961958 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:06:01 +0000 Subject: [PATCH 1732/4969] Bump amqp-client from 5.14.0 to 5.14.1 in /modules/rabbitmq Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.14.0 to 5.14.1. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.14.0...v5.14.1) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/rabbitmq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 4b437605785..9b680b12968 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: RabbitMQ" dependencies { api project(":testcontainers") - testImplementation 'com.rabbitmq:amqp-client:5.14.0' + testImplementation 'com.rabbitmq:amqp-client:5.14.1' testImplementation 'org.assertj:assertj-core:3.22.0' compileOnly 'org.jetbrains:annotations:23.0.0' } From 8256b642dd017b4718513db5af3c5e8fef6c396b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:06:04 +0000 Subject: [PATCH 1733/4969] Bump jackson-dataformat-yaml from 2.8.8 to 2.13.1 in /modules/k3s Bumps [jackson-dataformat-yaml](https://github.com/FasterXML/jackson-dataformats-text) from 2.8.8 to 2.13.1. - [Release notes](https://github.com/FasterXML/jackson-dataformats-text/releases) - [Commits](https://github.com/FasterXML/jackson-dataformats-text/commits/jackson-dataformats-text-2.13.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 95d2d3bc97c..85ee36652b3 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: K3S" dependencies { api project(":testcontainers") - shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' + shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1' testImplementation 'io.fabric8:kubernetes-client:5.11.0' testImplementation 'io.kubernetes:client-java:14.0.0' From dcf6bd01d4225ddf54193fd158983251a38b4ff1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:06:07 +0000 Subject: [PATCH 1734/4969] Bump assertj-core from 3.21.0 to 3.22.0 in /modules/k3s Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.22.0. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 95d2d3bc97c..0674ee2b24c 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -7,5 +7,5 @@ dependencies { testImplementation 'io.fabric8:kubernetes-client:5.11.0' testImplementation 'io.kubernetes:client-java:14.0.0' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.22.0' } From bc4b8ada94a93a5f8790d58098ce098bf51eb11c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 22:06:09 +0000 Subject: [PATCH 1735/4969] Bump google-cloud-bigtable from 2.5.1 to 2.5.2 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.5.1 to 2.5.2. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.5.1...v2.5.2) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 07d0c06a04b..81dd0e9dff1 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.0.10' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.1' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.2' testImplementation 'org.assertj:assertj-core:3.22.0' } From f66a6d256fa5e5f7b9b2c358a41953b5ca5699ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Feb 2022 14:14:38 +0000 Subject: [PATCH 1736/4969] Bump mysql-connector-java from 8.0.27 to 8.0.28 in /modules/jdbc-test Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.27 to 8.0.28. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.27...8.0.28) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 98570722e6a..2ea623f75a1 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -16,5 +16,5 @@ dependencies { api 'org.apache.tomcat:tomcat-jdbc:10.0.16' api 'org.vibur:vibur-dbcp:25.0' - api 'mysql:mysql-connector-java:8.0.27' + api 'mysql:mysql-connector-java:8.0.28' } From c5bec3cee6de41c89c0270da0b42fc126141ec7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Feb 2022 14:14:43 +0000 Subject: [PATCH 1737/4969] Bump cucumber-junit from 7.2.2 to 7.2.3 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.2.2 to 7.2.3. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.2.2...v7.2.3) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 9a402b51b47..78d042b95fd 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.2.3' - testImplementation 'io.cucumber:cucumber-junit:7.2.2' + testImplementation 'io.cucumber:cucumber-junit:7.2.3' testImplementation 'org.testcontainers:selenium' } From 8de57a2c31db71a3375a70580f73a2c7d702f7ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Feb 2022 14:14:47 +0000 Subject: [PATCH 1738/4969] Bump mysql-connector-java from 8.0.27 to 8.0.28 in /modules/mysql Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.27 to 8.0.28. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.27...8.0.28) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 88a4473f56c..1796ff17ef0 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.27' + testImplementation 'mysql:mysql-connector-java:8.0.28' testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' From 2d09155faa529074f53b10a2e7f828bf531efa2d Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 3 Feb 2022 15:04:50 +0000 Subject: [PATCH 1739/4969] Upgrade mkdocs (#3443) Co-authored-by: Kevin Wittek --- docs/contributing.md | 2 +- docs/index.md | 57 ++++---- docs/modules/azure.md | 26 ++-- docs/modules/databases/cassandra.md | 79 +++++------ docs/modules/databases/clickhouse.md | 24 ++-- docs/modules/databases/cockroachdb.md | 24 ++-- docs/modules/databases/couchbase.md | 25 ++-- docs/modules/databases/db2.md | 25 ++-- docs/modules/databases/dynalite.md | 25 ++-- docs/modules/databases/influxdb.md | 25 ++-- docs/modules/databases/mariadb.md | 25 ++-- docs/modules/databases/mongodb.md | 25 ++-- docs/modules/databases/mssqlserver.md | 25 ++-- docs/modules/databases/mysql.md | 25 ++-- docs/modules/databases/neo4j.md | 146 +++++++++++---------- docs/modules/databases/oraclexe.md | 25 ++-- docs/modules/databases/orientdb.md | 88 +++++++------ docs/modules/databases/postgres.md | 25 ++-- docs/modules/databases/presto.md | 25 ++-- docs/modules/databases/trino.md | 26 ++-- docs/modules/docker_compose.md | 25 ++-- docs/modules/elasticsearch.md | 26 ++-- docs/modules/gcloud.md | 25 ++-- docs/modules/k3s.md | 25 ++-- docs/modules/kafka.md | 25 ++-- docs/modules/localstack.md | 25 ++-- docs/modules/mockserver.md | 25 ++-- docs/modules/nginx.md | 25 ++-- docs/modules/pulsar.md | 25 ++-- docs/modules/rabbitmq.md | 25 ++-- docs/modules/solr.md | 25 ++-- docs/modules/toxiproxy.md | 25 ++-- docs/modules/vault.md | 25 ++-- docs/modules/webdriver_containers.md | 47 +++---- docs/quickstart/junit_4_quickstart.md | 25 ++-- docs/quickstart/junit_5_quickstart.md | 53 ++++---- docs/quickstart/spock_quickstart.md | 34 ++--- docs/test_framework_integration/junit_5.md | 25 ++-- docs/test_framework_integration/spock.md | 25 ++-- mkdocs.yml | 2 + requirements.txt | 9 +- 41 files changed, 675 insertions(+), 618 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 4094fab14ef..6cd3e2719f8 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -35,7 +35,7 @@ If the answers to the above are all yes, then a new module may be a good approac Otherwise, it is entirely possible for you to: * publish a code snippet -* contribute an [example](../examples/README.md) to the Testcontainers repo +* contribute an example to the Testcontainers repo * publish your own third party library In any case, please contact us to help validate your proposal! diff --git a/docs/index.md b/docs/index.md index 136ae53d2ca..998722af50f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,7 @@ # Testcontainers -![Testcontainers logo](./logo.png) + +Testcontainers logo ## About @@ -31,18 +32,19 @@ Testcontainers is distributed as separate JARs with a common version number: For the core library, the latest Maven/Gradle dependency is as follows: -```groovy tab='Gradle' -testImplementation "org.testcontainers:testcontainers:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - testcontainers - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:testcontainers:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + testcontainers + {{latest_version}} + test + + ``` You can also [check the latest version available on Maven Central](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.testcontainers%22). @@ -51,8 +53,8 @@ You can also [check the latest version available on Maven Central](https://searc To avoid specifying the version of each dependency, you can use a `BOM` or `Bill Of Materials`. Using Maven you can add the following to `dependencyManagement` section in your `pom.xml`: - -```xml tab='Maven' +=== "Maven" +```xml @@ -67,21 +69,22 @@ Using Maven you can add the following to `dependencyManagement` section in your ``` and then use dependencies without specifying a version: - -```xml tab='Maven' - - org.testcontainers - mysql - test - -``` +=== "Maven" + ```xml + + org.testcontainers + mysql + test + + ``` Using Gradle 5.0 or higher, you can add the following to the `dependencies` section in your `build.gradle`: -```groovy tab='Gradle' -implementation platform('org.testcontainers:testcontainers-bom:{{latest_version}}') //import bom -testImplementation('org.testcontainers:mysql') //no version specified -``` +=== "Gradle" + ```groovy + implementation platform('org.testcontainers:testcontainers-bom:{{latest_version}}') //import bom + testImplementation('org.testcontainers:mysql') //no version specified + ``` [JitPack](jitpack_dependencies.md) builds are available for pre-release versions. diff --git a/docs/modules/azure.md b/docs/modules/azure.md index 529f058ea52..5e80270e90c 100644 --- a/docs/modules/azure.md +++ b/docs/modules/azure.md @@ -49,16 +49,18 @@ Test against the Emulator: Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:azure:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - azure - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:azure:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + azure + {{latest_version}} + test + + ``` diff --git a/docs/modules/databases/cassandra.md b/docs/modules/databases/cassandra.md index 63213d27343..f7ed3094886 100644 --- a/docs/modules/databases/cassandra.md +++ b/docs/modules/databases/cassandra.md @@ -4,48 +4,51 @@ This example connects to the Cassandra Cluster, creates a keyspaces and asserts that is has been created. -```java tab="JUnit 4 example" -public class SomeTest { - - @Rule - public CassandraContainer cassandra = new CassandraContainer(); - - - @Test - public void test(){ - Cluster cluster = cassandra.getCluster(); - - try(Session session = cluster.connect()) { - - session.execute("CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + - "{'class':'SimpleStrategy','replication_factor':'1'};"); - - List keyspaces = session.getCluster().getMetadata().getKeyspaces(); - List filteredKeyspaces = keyspaces - .stream() - .filter(km -> km.getName().equals("test")) - .collect(Collectors.toList()); - - assertEquals(1, filteredKeyspaces.size()); +=== "JUnit 4 example" + ```java + public class SomeTest { + + @Rule + public CassandraContainer cassandra = new CassandraContainer(); + + + @Test + public void test(){ + Cluster cluster = cassandra.getCluster(); + + try(Session session = cluster.connect()) { + + session.execute("CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};"); + + List keyspaces = session.getCluster().getMetadata().getKeyspaces(); + List filteredKeyspaces = keyspaces + .stream() + .filter(km -> km.getName().equals("test")) + .collect(Collectors.toList()); + + assertEquals(1, filteredKeyspaces.size()); + } } + } - -} -``` + ``` ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:cassandra:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - cassandra - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:cassandra:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + cassandra + {{latest_version}} + test + + ``` diff --git a/docs/modules/databases/clickhouse.md b/docs/modules/databases/clickhouse.md index a52a75af51f..b3494867edf 100644 --- a/docs/modules/databases/clickhouse.md +++ b/docs/modules/databases/clickhouse.md @@ -4,18 +4,20 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:clickhouse:{{latest_version}}" -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:clickhouse:{{latest_version}}" + ``` -```xml tab='Maven' - - org.testcontainers - clickhouse - {{latest_version}} - test - -``` +=== "Maven" + ```xml + + org.testcontainers + clickhouse + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/cockroachdb.md b/docs/modules/databases/cockroachdb.md index 17c5efae8f8..45e3f75b86c 100644 --- a/docs/modules/databases/cockroachdb.md +++ b/docs/modules/databases/cockroachdb.md @@ -6,18 +6,20 @@ See [Database containers](./index.md) for documentation and usage that is common Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:cockroachdb:{{latest_version}}" -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:cockroachdb:{{latest_version}}" + ``` -```xml tab='Maven' - - org.testcontainers - cockroachdb - {{latest_version}} - test - -``` +=== "Maven" + ```xml + + org.testcontainers + cockroachdb + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/couchbase.md b/docs/modules/databases/couchbase.md index e45a971f626..5c1ff9f5580 100644 --- a/docs/modules/databases/couchbase.md +++ b/docs/modules/databases/couchbase.md @@ -27,15 +27,16 @@ Running Couchbase as a stand-in in a test: Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:couchbase:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - couchbase - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:couchbase:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + couchbase + {{latest_version}} + test + + ``` diff --git a/docs/modules/databases/db2.md b/docs/modules/databases/db2.md index 3872e7fa857..945536cac05 100644 --- a/docs/modules/databases/db2.md +++ b/docs/modules/databases/db2.md @@ -33,18 +33,19 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:db2:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - db2 - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:db2:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + db2 + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/dynalite.md b/docs/modules/databases/dynalite.md index dfc32f35d2e..8807ad7f025 100644 --- a/docs/modules/databases/dynalite.md +++ b/docs/modules/databases/dynalite.md @@ -29,18 +29,19 @@ In part, because it's light and quick to run. Also, please see the [reasons give Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:dynalite:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - dynalite - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:dynalite:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + dynalite + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add an AWS SDK JAR to your project. You should ensure that your project also has a suitable AWS SDK JAR as a dependency. diff --git a/docs/modules/databases/influxdb.md b/docs/modules/databases/influxdb.md index 5de7d36182a..3f5fe0654db 100644 --- a/docs/modules/databases/influxdb.md +++ b/docs/modules/databases/influxdb.md @@ -22,18 +22,19 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:influxdb:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - influxdb - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:influxdb:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + influxdb + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/mariadb.md b/docs/modules/databases/mariadb.md index 7ef14bed3cc..495965bee0a 100644 --- a/docs/modules/databases/mariadb.md +++ b/docs/modules/databases/mariadb.md @@ -23,18 +23,19 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:mariadb:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - mariadb - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:mariadb:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + mariadb + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/mongodb.md b/docs/modules/databases/mongodb.md index 3d49ecc6809..9e81e28c39f 100644 --- a/docs/modules/databases/mongodb.md +++ b/docs/modules/databases/mongodb.md @@ -40,18 +40,19 @@ That's where the MongoDBContainer might come in handy. Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:mongodb:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - mongodb - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:mongodb:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + mongodb + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency diff --git a/docs/modules/databases/mssqlserver.md b/docs/modules/databases/mssqlserver.md index 6dea62def25..7ddd5350a40 100644 --- a/docs/modules/databases/mssqlserver.md +++ b/docs/modules/databases/mssqlserver.md @@ -29,18 +29,19 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:mssqlserver:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - mssqlserver - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:mssqlserver:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + mssqlserver + {{latest_version}} + test + + ``` !!! hint diff --git a/docs/modules/databases/mysql.md b/docs/modules/databases/mysql.md index f5a428e1cdc..26fc62308ef 100644 --- a/docs/modules/databases/mysql.md +++ b/docs/modules/databases/mysql.md @@ -17,18 +17,19 @@ and will be able to override server settings when the container starts. Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:mysql:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - mysql - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:mysql:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + mysql + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/neo4j.md b/docs/modules/databases/neo4j.md index 0310d37d817..17e1e154fc8 100644 --- a/docs/modules/databases/neo4j.md +++ b/docs/modules/databases/neo4j.md @@ -13,58 +13,59 @@ On the JVM you would most likely use the [Java driver](https://github.com/neo4j/ The following example uses the JUnit 5 extension `@Testcontainers` and demonstrates both the usage of the Java Driver and the REST endpoint: -```java tab="JUnit 5 example" -@Testcontainers -public class ExampleTest { - - @Container - private static Neo4jContainer neo4jContainer = new Neo4jContainer() - .withAdminPassword(null); // Disable password - - @Test - void testSomethingUsingBolt() { - - // Retrieve the Bolt URL from the container - String boltUrl = neo4jContainer.getBoltUrl(); - try ( - Driver driver = GraphDatabase.driver(boltUrl, AuthTokens.none()); - Session session = driver.session() - ) { - long one = session.run("RETURN 1", Collections.emptyMap()).next().get(0).asLong(); - assertThat(one, is(1L)); - } catch (Exception e) { - fail(e.getMessage()); - } - } - - @Test - void testSomethingUsingHttp() throws IOException { - - // Retrieve the HTTP URL from the container - String httpUrl = neo4jContainer.getHttpUrl(); - - URL url = new URL(httpUrl + "/db/data/transaction/commit"); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - - con.setRequestMethod("POST"); - con.setRequestProperty("Content-Type", "application/json"); - con.setDoOutput(true); - - try (Writer out = new OutputStreamWriter(con.getOutputStream())) { - out.write("{\"statements\":[{\"statement\":\"RETURN 1\"}]}"); - out.flush(); +=== "JUnit 5 example" + ```java + @Testcontainers + public class ExampleTest { + + @Container + private static Neo4jContainer neo4jContainer = new Neo4jContainer() + .withAdminPassword(null); // Disable password + + @Test + void testSomethingUsingBolt() { + + // Retrieve the Bolt URL from the container + String boltUrl = neo4jContainer.getBoltUrl(); + try ( + Driver driver = GraphDatabase.driver(boltUrl, AuthTokens.none()); + Session session = driver.session() + ) { + long one = session.run("RETURN 1", Collections.emptyMap()).next().get(0).asLong(); + assertThat(one, is(1L)); + } catch (Exception e) { + fail(e.getMessage()); + } } - - assertThat(con.getResponseCode(), is(HttpURLConnection.HTTP_OK)); - try (BufferedReader buffer = new BufferedReader(new InputStreamReader(con.getInputStream()))) { - String expectedResponse = - "{\"results\":[{\"columns\":[\"1\"],\"data\":[{\"row\":[1],\"meta\":[null]}]}],\"errors\":[]}"; - String response = buffer.lines().collect(Collectors.joining("\n")); - assertThat(response, is(expectedResponse)); + + @Test + void testSomethingUsingHttp() throws IOException { + + // Retrieve the HTTP URL from the container + String httpUrl = neo4jContainer.getHttpUrl(); + + URL url = new URL(httpUrl + "/db/data/transaction/commit"); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + + con.setRequestMethod("POST"); + con.setRequestProperty("Content-Type", "application/json"); + con.setDoOutput(true); + + try (Writer out = new OutputStreamWriter(con.getOutputStream())) { + out.write("{\"statements\":[{\"statement\":\"RETURN 1\"}]}"); + out.flush(); + } + + assertThat(con.getResponseCode(), is(HttpURLConnection.HTTP_OK)); + try (BufferedReader buffer = new BufferedReader(new InputStreamReader(con.getInputStream()))) { + String expectedResponse = + "{\"results\":[{\"columns\":[\"1\"],\"data\":[{\"row\":[1],\"meta\":[null]}]}],\"errors\":[]}"; + String response = buffer.lines().collect(Collectors.joining("\n")); + assertThat(response, is(expectedResponse)); + } } } -} -``` + ``` You are not limited to Unit tests and can of course use an instance of the Neo4j Testcontainer in vanilla Java code as well. @@ -165,33 +166,36 @@ You'll find more information about licensing Neo4j here: [About Neo4j Licenses]( Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:neo4j:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - neo4j - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:neo4j:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + neo4j + {{latest_version}} + test + + ``` !!! hint Add the Neo4j Java driver if you plan to access the Testcontainer via Bolt: - ```groovy tab='Gradle' - compile "org.neo4j.driver:neo4j-java-driver:1.7.1" - ``` + === "Gradle" + ```groovy + compile "org.neo4j.driver:neo4j-java-driver:1.7.1" + ``` - ```xml tab='Maven' - - org.neo4j.driver - neo4j-java-driver - 1.7.1 - - ``` + === "Maven" + ```xml + + org.neo4j.driver + neo4j-java-driver + 1.7.1 + + ``` diff --git a/docs/modules/databases/oraclexe.md b/docs/modules/databases/oraclexe.md index 56eb57bc0e5..583d68f3c3d 100644 --- a/docs/modules/databases/oraclexe.md +++ b/docs/modules/databases/oraclexe.md @@ -30,18 +30,19 @@ containing `oracle.container.image=IMAGE`, where IMAGE is a suitable image name Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:oracle-xe:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - oracle-xe - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:oracle-xe:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + oracle-xe + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/orientdb.md b/docs/modules/databases/orientdb.md index 4f0b3550e44..4beffefa6c2 100644 --- a/docs/modules/databases/orientdb.md +++ b/docs/modules/databases/orientdb.md @@ -16,27 +16,28 @@ On the JVM you would most likely use the [Java driver](https://github.com/). The following example uses the JUnit 5 extension `@Testcontainers` and demonstrates both the usage of the Java Client: -```java tab="JUnit 5 example" -@Testcontainers -public class ExampleTest { - - @Container - private static OrientDBContainer container = new OrientDBContainer(); - - @Test - void testDbCreation() { - - final ODatabaseSession session = container.getSession(); - - session.command("CREATE CLASS Person EXTENDS V"); - session.command("INSERT INTO Person set name='john'"); - session.command("INSERT INTO Person set name='jane'"); - - assertThat(session.query("SELECT FROM Person").stream()).hasSize(2); +=== "JUnit 5 example" + ```java + @Testcontainers + public class ExampleTest { + + @Container + private static OrientDBContainer container = new OrientDBContainer(); + + @Test + void testDbCreation() { + + final ODatabaseSession session = container.getSession(); + + session.command("CREATE CLASS Person EXTENDS V"); + session.command("INSERT INTO Person set name='john'"); + session.command("INSERT INTO Person set name='jane'"); + + assertThat(session.query("SELECT FROM Person").stream()).hasSize(2); + } + } - -} -``` + ``` You are not limited to Unit tests and can of course use an instance of the OrientDB Testcontainer in vanilla Java code as well. @@ -45,33 +46,36 @@ You are not limited to Unit tests and can of course use an instance of the Orien Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:orientdb:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - orientdb - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:orientdb:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + orientdb + {{latest_version}} + test + + ``` !!! hint Add the OrientDB Java client if you plan to access the Testcontainer: - ```groovy tab='Gradle' - compile "com.orientechnologies:orientdb-client:3.0.24" - ``` + === "Gradle" + ```groovy + compile "com.orientechnologies:orientdb-client:3.0.24" + ``` - ```xml tab='Maven' - - com.orientechnologies - orientdb-client - 3.0.24 - - ``` + === "Maven" + ```xml + + com.orientechnologies + orientdb-client + 3.0.24 + + ``` diff --git a/docs/modules/databases/postgres.md b/docs/modules/databases/postgres.md index 0777296b0c0..b7632d78293 100644 --- a/docs/modules/databases/postgres.md +++ b/docs/modules/databases/postgres.md @@ -6,18 +6,19 @@ See [Database containers](./index.md) for documentation and usage that is common Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:postgresql:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - postgresql - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:postgresql:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + postgresql + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/docs/modules/databases/presto.md b/docs/modules/databases/presto.md index 3b987796360..d0a47fc1d7a 100644 --- a/docs/modules/databases/presto.md +++ b/docs/modules/databases/presto.md @@ -67,18 +67,19 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:presto:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - presto - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:presto:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + presto + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add the Presto JDBC driver JAR to your project. diff --git a/docs/modules/databases/trino.md b/docs/modules/databases/trino.md index 5b65f45934a..b6aeddafb40 100644 --- a/docs/modules/databases/trino.md +++ b/docs/modules/databases/trino.md @@ -67,18 +67,20 @@ public class SomeTest { Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:trino:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - trino - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:trino:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + trino + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add the Trino JDBC driver JAR to your project. diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index b789a0030a7..50bb946f311 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -177,16 +177,17 @@ There are 3 ways to specify location of the `config.json` for Docker Compose: Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:testcontainers:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - testcontainers - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:testcontainers:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + testcontainers + {{latest_version}} + test + + ``` diff --git a/docs/modules/elasticsearch.md b/docs/modules/elasticsearch.md index 738bf427a56..845ee0d2d1a 100644 --- a/docs/modules/elasticsearch.md +++ b/docs/modules/elasticsearch.md @@ -41,15 +41,17 @@ other new and advanced features), you can use this instead: Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:elasticsearch:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - elasticsearch - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:elasticsearch:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + elasticsearch + {{latest_version}} + test + + ``` diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index aeab52fc932..7431ed0de0f 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -141,15 +141,16 @@ See more examples: Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:gcloud:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - gcloud - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:gcloud:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + gcloud + {{latest_version}} + test + + ``` diff --git a/docs/modules/k3s.md b/docs/modules/k3s.md index a3c2c0fa754..27d2f863122 100644 --- a/docs/modules/k3s.md +++ b/docs/modules/k3s.md @@ -39,15 +39,16 @@ This may be used with Kubernetes clients - e.g. for the [official Java client](c Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:k3s:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - k3s - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:k3s:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + k3s + {{latest_version}} + test + + ``` diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index 58f447d412e..9b222cef125 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -50,15 +50,16 @@ You will need to explicitly create a network and set it on the Kafka container a Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:kafka:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - kafka - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:kafka:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + kafka + {{latest_version}} + test + + ``` diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index 1585c504cff..b551536af74 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -66,15 +66,16 @@ Testcontainers will inform Localstack of the best hostname automatically, using Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:localstack:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - localstack - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:localstack:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + localstack + {{latest_version}} + test + + ``` diff --git a/docs/modules/mockserver.md b/docs/modules/mockserver.md index bf56046deda..c739278acff 100644 --- a/docs/modules/mockserver.md +++ b/docs/modules/mockserver.md @@ -20,18 +20,19 @@ And how to set a simple expectation using the Java MockServerClient. Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:mockserver:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - mockserver - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:mockserver:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + mockserver + {{latest_version}} + test + + ``` Additionally, don't forget to add a [client dependency `org.mock-server:mockserver-client-java`](https://search.maven.org/search?q=mockserver-client-java) to be able to set expectations, it's not provided by the testcontainers module. Client version should match to the version in a container tag. diff --git a/docs/modules/nginx.md b/docs/modules/nginx.md index 5169d3c5625..fb4270ba4a3 100644 --- a/docs/modules/nginx.md +++ b/docs/modules/nginx.md @@ -26,15 +26,16 @@ And how to query the Nginx server for the custom content added. Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:nginx:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - nginx - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:nginx:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + nginx + {{latest_version}} + test + + ``` diff --git a/docs/modules/pulsar.md b/docs/modules/pulsar.md index 92eda498f7c..6d16a248872 100644 --- a/docs/modules/pulsar.md +++ b/docs/modules/pulsar.md @@ -4,15 +4,16 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:pulsar:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - pulsar - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:pulsar:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + pulsar + {{latest_version}} + test + + ``` diff --git a/docs/modules/rabbitmq.md b/docs/modules/rabbitmq.md index dff8631eeca..8a9ae9d9b97 100644 --- a/docs/modules/rabbitmq.md +++ b/docs/modules/rabbitmq.md @@ -7,15 +7,16 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:rabbitmq:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - rabbitmq - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:rabbitmq:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + rabbitmq + {{latest_version}} + test + + ``` diff --git a/docs/modules/solr.md b/docs/modules/solr.md index bb2d18d6431..44be46c1a1a 100644 --- a/docs/modules/solr.md +++ b/docs/modules/solr.md @@ -20,15 +20,16 @@ You can start a solr container instance from any Java application by using: Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:solr:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - solr - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:solr:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + solr + {{latest_version}} + test + + ``` diff --git a/docs/modules/toxiproxy.md b/docs/modules/toxiproxy.md index a3403ccc377..aa6013284ed 100644 --- a/docs/modules/toxiproxy.md +++ b/docs/modules/toxiproxy.md @@ -72,18 +72,19 @@ Additionally we can disable the proxy to simulate a complete interruption to the Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:toxiproxy:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - toxiproxy - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:toxiproxy:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + toxiproxy + {{latest_version}} + test + + ``` ## Acknowledgements diff --git a/docs/modules/vault.md b/docs/modules/vault.md index 3140a6258bc..577ed91a32f 100644 --- a/docs/modules/vault.md +++ b/docs/modules/vault.md @@ -41,18 +41,19 @@ test how your application behaves with Vault by writing different test scenarios Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:vault:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - vault - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:vault:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + vault + {{latest_version}} + test + + ``` ## License diff --git a/docs/modules/webdriver_containers.md b/docs/modules/webdriver_containers.md index 3c6b0ffae27..d589aa18098 100644 --- a/docs/modules/webdriver_containers.md +++ b/docs/modules/webdriver_containers.md @@ -88,32 +88,35 @@ A few different examples are shown in [ChromeWebDriverContainerTest.java](https: Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:selenium:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - selenium - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:selenium:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + selenium + {{latest_version}} + test + + ``` !!! hint Adding this Testcontainers library JAR will not automatically add a Selenium Webdriver JAR to your project. You should ensure that your project also has suitable Selenium dependencies in place, for example: - ```groovy tab='Gradle' - compile "org.seleniumhq.selenium:selenium-remote-driver:3.141.59" - ``` + === "Gradle" + ```groovy + compile "org.seleniumhq.selenium:selenium-remote-driver:3.141.59" + ``` - ```xml tab='Maven' - - org.seleniumhq.selenium - selenium-remote-driver - 3.141.59 - - ``` + === "Maven" + ```xml + + org.seleniumhq.selenium + selenium-remote-driver + 3.141.59 + + ``` Testcontainers will try and match the version of the Dockerized browser to whichever version of Selenium is found on the classpath diff --git a/docs/quickstart/junit_4_quickstart.md b/docs/quickstart/junit_4_quickstart.md index 1a2cd84c77e..57946c1fb74 100644 --- a/docs/quickstart/junit_4_quickstart.md +++ b/docs/quickstart/junit_4_quickstart.md @@ -21,18 +21,19 @@ Let's start from here, and see how to improve the test with Testcontainers: First, add Testcontainers as a dependency as follows: -```groovy tab='Gradle' -testImplementation "org.testcontainers:testcontainers:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - testcontainers - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:testcontainers:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + testcontainers + {{latest_version}} + test + + ``` ## 2. Get Testcontainers to run a Redis container during our tests diff --git a/docs/quickstart/junit_5_quickstart.md b/docs/quickstart/junit_5_quickstart.md index b50272cb68d..24e9dd71a74 100644 --- a/docs/quickstart/junit_5_quickstart.md +++ b/docs/quickstart/junit_5_quickstart.md @@ -21,32 +21,33 @@ Let's start from here, and see how to improve the test with Testcontainers: First, add Testcontainers as a dependency as follows: -```groovy tab='Gradle' -testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" -testImplementation "org.testcontainers:testcontainers:{{latest_version}}" -testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" -``` - -```xml tab='Maven' - - org.junit.jupiter - junit-jupiter - 5.8.1 - test - - - org.testcontainers - testcontainers - {{latest_version}} - test - - - org.testcontainers - junit-jupiter - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" + testImplementation "org.testcontainers:testcontainers:{{latest_version}}" + testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.testcontainers + testcontainers + {{latest_version}} + test + + + org.testcontainers + junit-jupiter + {{latest_version}} + test + + ``` ## 2. Get Testcontainers to run a Redis container during our tests diff --git a/docs/quickstart/spock_quickstart.md b/docs/quickstart/spock_quickstart.md index 875c1976c93..267954e99ee 100644 --- a/docs/quickstart/spock_quickstart.md +++ b/docs/quickstart/spock_quickstart.md @@ -21,27 +21,29 @@ Let's start from here, and see how to improve the test with Testcontainers: First, add Testcontainers as a dependency as follows: -```groovy tab='Gradle' -testImplementation "org.testcontainers:spock:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - spock - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:spock:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + spock + {{latest_version}} + test + + ``` ## 2. Get Testcontainers to run a Redis container during our tests Annotate the Spock specification class with the Testcontainers extension: -```groovy tab='Spock Testcontainers annotation' -@org.testcontainers.spock.Testcontainers -class RedisBackedCacheIntTest extends Specification { -``` +=== "Spock Testcontainers annotation" + ```groovy + @org.testcontainers.spock.Testcontainers + class RedisBackedCacheIntTest extends Specification { + ``` And add the following field to the body of our test class: diff --git a/docs/test_framework_integration/junit_5.md b/docs/test_framework_integration/junit_5.md index 7f3689c0301..15597f90cdb 100644 --- a/docs/test_framework_integration/junit_5.md +++ b/docs/test_framework_integration/junit_5.md @@ -68,15 +68,16 @@ This extension has only be tested with sequential test execution. Using it with Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - junit-jupiter - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:junit-jupiter:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + junit-jupiter + {{latest_version}} + test + + ``` diff --git a/docs/test_framework_integration/spock.md b/docs/test_framework_integration/spock.md index 11ccf058767..b8c1d5b7eae 100644 --- a/docs/test_framework_integration/spock.md +++ b/docs/test_framework_integration/spock.md @@ -17,18 +17,19 @@ can be mixed with Spock's `@Shared` annotation to indicate, that containers shou Add the following dependency to your `pom.xml`/`build.gradle` file: -```groovy tab='Gradle' -testImplementation "org.testcontainers:spock:{{latest_version}}" -``` - -```xml tab='Maven' - - org.testcontainers - spock - {{latest_version}} - test - -``` +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:spock:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + spock + {{latest_version}} + test + + ``` ## Attributions diff --git a/mkdocs.yml b/mkdocs.yml index 694fca299ca..e4115625a7f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,8 @@ markdown_extensions: - codehilite: linenums: False - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true - pymdownx.snippets nav: - Home: index.md diff --git a/requirements.txt b/requirements.txt index f962b36a44f..8f4a1a5f100 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ -mkdocs==1.0.4 -mkdocs-codeinclude-plugin==0.1.0 -mkdocs-material==4.6.0 -mkdocs-markdownextradata-plugin==0.1.1 -markdown>=3.1,<3.2 +mkdocs==1.2.3 +mkdocs-codeinclude-plugin==0.2.0 +mkdocs-material==8.1.3 +mkdocs-markdownextradata-plugin==0.2.5 From 720c2ea81f6bf624ff7d8ad1b2b3f89824c3b006 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Feb 2022 09:23:15 +0100 Subject: [PATCH 1740/4969] Update Gradle Wrapper to 7.4 (#5036) Signed-off-by: gradle-update-robot Co-authored-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes .../gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.jar b/examples/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 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 diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 59250647c40..1debed0d8fd 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionSha256Sum=8cc27038d5dbd815759851ba53e70cf62e481b87494cc97cfd97982ada5ba634 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ee6ba9a3ac4..dcf5e2cb7b3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=c9490e938b221daf0094982288e4038deed954a3f12fb54cbf270ddf4e37d879 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionSha256Sum=cd5c2958a107ee7f0722004a12d0f8559b4564c34daad7df06cffd4d12a426d0 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From affee6c23f2f5192813f1be84b4ec050116b56fd Mon Sep 17 00:00:00 2001 From: Stefan Decker Date: Thu, 10 Feb 2022 10:02:42 +0100 Subject: [PATCH 1741/4969] #5032 - MS SQL Server disable encrypt by default (#5033) This disables the JDBC driver encrypt option by default for MS SQL Server container connections. Since release 10.1.0 of the MS JDBC driver, the encrypt option is enabled by default (see https://github.com/microsoft/mssql-jdbc/releases/tag/v10.1.0). To be able to use the container without having to manually add params the encrypt option will be switched off if it is not set. Signed-off-by: Decker, Stefan Co-authored-by: Kevin Wittek --- modules/mssqlserver/build.gradle | 3 +-- .../containers/MSSQLServerContainer.java | 11 +++++++++++ .../junit/mssqlserver/SimpleMSSQLServerTest.java | 3 +-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 1e554440939..1f754303ae1 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,12 +10,11 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.5.0.jre8-preview' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:10.2.0.jre8' testImplementation project(':r2dbc') testImplementation 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' // MSSQL's wait strategy requires the JDBC driver testImplementation testFixtures(project(':r2dbc')) - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:9.5.0.jre8-preview' } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index ecccc320b28..fe6270d04c7 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -91,6 +91,17 @@ public String getDriverClassName() { return "com.microsoft.sqlserver.jdbc.SQLServerDriver"; } + @Override + protected String constructUrlForConnection(String queryString) { + // The JDBC driver of MS SQL Server enables encryption by default for versions > 10.1.0. + // We need to disable it by default to be able to use the container without having to pass extra params. + // See https://github.com/microsoft/mssql-jdbc/releases/tag/v10.1.0 + if (urlParameters.keySet().stream().map(String::toLowerCase).noneMatch("encrypt"::equals)) { + urlParameters.put("encrypt", "false"); + } + return super.constructUrlForConnection(queryString); + } + @Override public String getJdbcUrl() { String additionalUrlParams = constructUrlParameters(";", ";"); diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index 100b29b34f7..1530760b673 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -1,7 +1,6 @@ package org.testcontainers.junit.mssqlserver; import org.junit.Test; -import org.testcontainers.MSSQLServerTestImages; import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -11,7 +10,7 @@ import java.sql.Statement; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.testcontainers.MSSQLServerTestImages.MSSQL_SERVER_IMAGE; From 71a073bc5ddfce38b2b5348d9d7d4eb63f296290 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 17 Feb 2022 14:40:19 +0100 Subject: [PATCH 1742/4969] Polish code samples on container logs so that they are easier to copy & paste (#5038) --- docs/features/container_logs.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/features/container_logs.md b/docs/features/container_logs.md index d603981059a..a063e5329e4 100644 --- a/docs/features/container_logs.md +++ b/docs/features/container_logs.md @@ -40,19 +40,19 @@ By default both standard out and standard error will both be emitted at INFO lev Standard error may be emitted at ERROR level, if desired: ```java -Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log).withSeparateOutputStreams() +Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withSeparateOutputStreams(); ``` The [Mapped Diagnostic Context (MDC)](http://logback.qos.ch/manual/mdc.html) for emitted messages may be configured using the `withMdc(...)` option: ```java -Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log).withMdc("key", "value") +Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withMdc("key", "value"); ``` or using an existing map of key-value pairs: ```java -Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log).withMdc(map) +Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withMdc(map); ``` ### Capturing container output as a String From bfb8cecd69f852eb2ffa8ee93edbfb0edc54762a Mon Sep 17 00:00:00 2001 From: Yannick Weber Date: Thu, 17 Feb 2022 14:54:27 +0100 Subject: [PATCH 1743/4969] New Module: HiveMQ (#4797) Co-authored-by: Jochen Mader --- .github/dependabot.yml | 5 + .../strategy/MultiLogMessageWaitStrategy.java | 59 ++ docs/modules/hivemq.md | 235 +++++++ docs/modules_logos/hivemq-module.png | Bin 0 -> 165340 bytes mkdocs.yml | 1 + modules/hivemq/build.gradle | 37 ++ .../hivemq/HiveMQContainer.java | 573 ++++++++++++++++++ .../hivemq/HiveMQExtension.java | 287 +++++++++ .../org/testcontainers/hivemq/PathUtil.java | 26 + .../hivemq/ContainerWithControlCenterIT.java | 34 ++ .../hivemq/ContainerWithCustomConfigIT.java | 43 ++ ...ContainerWithExtensionFromDirectoryIT.java | 43 ++ .../hivemq/ContainerWithExtensionIT.java | 41 ++ .../ContainerWithExtensionSubclassIT.java | 35 ++ .../ContainerWithFileInExtensionHomeIT.java | 77 +++ .../hivemq/ContainerWithFileInHomeIT.java | 75 +++ .../hivemq/ContainerWithLicenseIT.java | 78 +++ .../ContainerWithoutPlatformExtensionsIT.java | 135 +++++ .../hivemq/CreateFileInCopiedDirectoryIT.java | 92 +++ .../CreateFileInExtensionDirectoryIT.java | 76 +++ ...DisableEnableExtensionFromDirectoryIT.java | 37 ++ .../hivemq/DisableEnableExtensionIT.java | 46 ++ .../hivemq/HiveMQExtensionTest.java | 13 + .../hivemq/HiveMQTestContainerCore.java | 82 +++ .../testcontainers/hivemq/PathUtilTest.java | 43 ++ .../hivemq/docs/DemoDisableExtensionsIT.java | 63 ++ .../hivemq/docs/DemoExtensionTestsIT.java | 57 ++ .../hivemq/docs/DemoFilesIT.java | 62 ++ .../hivemq/docs/DemoHiveMQContainerIT.java | 61 ++ .../hivemq/util/MyExtension.java | 37 ++ .../util/MyExtensionWithSubclasses.java | 26 + .../hivemq/util/PublishModifier.java | 16 + .../hivemq/util/TestPublishModifiedUtil.java | 48 ++ .../src/test/resources/additionalFile.txt | 0 modules/hivemq/src/test/resources/config.xml | 15 + .../src/test/resources/inMemoryConfig.xml | 6 + .../src/test/resources/logback-test.xml | 18 + .../hivemq-extension.xml | 8 + .../modifier-extension-1.0-SNAPSHOT.jar | Bin 0 -> 102179 bytes .../modifier-extension/hivemq-extension.xml | 8 + .../modifier-extension-1.0-SNAPSHOT.jar | Bin 0 -> 102179 bytes .../test/resources/myExtensionLicense.elic | 0 .../hivemq/src/test/resources/myLicense.lic | 0 43 files changed, 2598 insertions(+) create mode 100644 core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java create mode 100644 docs/modules/hivemq.md create mode 100644 docs/modules_logos/hivemq-module.png create mode 100644 modules/hivemq/build.gradle create mode 100644 modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java create mode 100644 modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java create mode 100755 modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java create mode 100755 modules/hivemq/src/test/resources/additionalFile.txt create mode 100755 modules/hivemq/src/test/resources/config.xml create mode 100644 modules/hivemq/src/test/resources/inMemoryConfig.xml create mode 100644 modules/hivemq/src/test/resources/logback-test.xml create mode 100755 modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml create mode 100644 modules/hivemq/src/test/resources/modifier-extension-wrong-name/modifier-extension-1.0-SNAPSHOT.jar create mode 100755 modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml create mode 100644 modules/hivemq/src/test/resources/modifier-extension/modifier-extension-1.0-SNAPSHOT.jar create mode 100755 modules/hivemq/src/test/resources/myExtensionLicense.elic create mode 100755 modules/hivemq/src/test/resources/myLicense.lic diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 355d44f2bb4..5d67f278219 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -57,6 +57,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/hivemq" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/influxdb" schedule: diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java new file mode 100644 index 00000000000..0d342f3050f --- /dev/null +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java @@ -0,0 +1,59 @@ +package org.testcontainers.containers.wait.strategy; + +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.WaitingConsumer; +import org.testcontainers.utility.LogUtils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; + +/** + * This is a wait strategy to wait for multiple log patterns. + * The wait strategy will continue when every log pattern is matched at least once. + */ +public class MultiLogMessageWaitStrategy extends AbstractWaitStrategy { + + private final ConcurrentHashMap regexes = new ConcurrentHashMap<>(); + + @Override + protected void waitUntilReady() { + WaitingConsumer waitingConsumer = new WaitingConsumer(); + LogUtils.followOutput(DockerClientFactory.instance().client(), waitStrategyTarget.getContainerId(), waitingConsumer); + + Predicate waitPredicate = outputFrame -> { + if (regexes.isEmpty()) { + return true; + } + regexes.entrySet().forEach(regexHasMatched -> { + final boolean matched = outputFrame.getUtf8String().matches("(?s)" + regexHasMatched.getKey()); + if (matched) { + regexHasMatched.setValue(true); + } + }); + return regexes.values().stream().reduce(Boolean::logicalAnd).orElse(true); + }; + + try { + waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, 1); + } catch (TimeoutException e) { + throw new ContainerLaunchException("Timed out waiting for log output matching '" + regexes + "'"); + } + } + + public MultiLogMessageWaitStrategy withRegEx(final String regEx) { + regexes.put(regEx, false); + return this; + } + + public MultiLogMessageWaitStrategy reset() { + for (final Map.Entry stringBooleanEntry : regexes.entrySet()) { + stringBooleanEntry.setValue(false); + } + return this; + } +} diff --git a/docs/modules/hivemq.md b/docs/modules/hivemq.md new file mode 100644 index 00000000000..1e09bac4fc0 --- /dev/null +++ b/docs/modules/hivemq.md @@ -0,0 +1,235 @@ +# HiveMQ Module + +drawing + +Automatic starting HiveMQ docker containers for JUnit4 and JUnit5 tests. +This enables testing MQTT client applications and integration testing of custom HiveMQ extensions. + +- Community forum: https://community.hivemq.com/ +- HiveMQ website: https://www.hivemq.com/ +- MQTT resources: + - [MQTT Essentials](https://www.hivemq.com/mqtt-essentials/) + - [MQTT 5 Essentials](https://www.hivemq.com/mqtt-5/) + +Please make sure to check out the hivemq-docs for the [Community Edition](https://github.com/hivemq/hivemq-community-edition/wiki/) +and the [Enterprise Edition](https://www.hivemq.com/docs/hivemq/4.7/user-guide/). + +## Using HiveMQ CE/EE + +HiveMQ provides different editions of on [Docker Hub](https://hub.docker.com/u/hivemq): + +- the open source [Community Edition](https://github.com/hivemq/hivemq-community-edition) which +is published as *hivemq/hivemq-ce*. +- the [Enterprise Edition](https://www.hivemq.com/docs/hivemq/4.7/user-guide/) which is published as *hivemq/hivemq4*. + +Both editions can be used directly: + +Using the Community Edition: + +[Community Edition HiveMQ image](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:ceVersion + + +Using the Enterprise Edition: + +[Enterprise Edition HiveMQ image](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:eeVersion + + +Using a specifc version is possible by using the tag: + +[Specific HiveMQ Version](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:specificVersion + + +## Test your MQTT 3 and MQTT 5 client application + +Using an Mqtt-client (e.g. the [HiveMQ-Mqtt-Client](https://github.com/hivemq/hivemq-mqtt-client)) you can start +testing directly. + + +[MQTT5 Client](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:mqtt5client + + +## Settings + +There are several things that can be adjusted before container setup. +The following example shows how to enable the Control Center (this is an enterprise feature), set the log level to DEBUG +and load a HiveMQ-config-file from the classpath. + + +[Config Examples](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:eeVersionWithControlCenter + + +--- +**Note:** +The Control Center of HiveMQ can be accessed via the URL presented in the output of the starting container: + +``` +2021-09-10 10:35:53,511 INFO - The HiveMQ Control Center is reachable under: http://localhost:55032 +``` + +Please be aware that the Control Center is a feature of the enterprise edition of HiveMQ and thus only available with +the enterprise image. + +--- + +## Testing HiveMQ extensions + +Using the [Extension SDK](https://github.com/hivemq/hivemq-extension-sdk) the functionality of all editions of HiveMQ +can be extended. +The HiveMQ module also supports testing your own custom extensions. + +### Wait Strategy + +The raw HiveMQ module is built to wait for certain startup log messages to signal readiness. +Since extensions are loaded dynamically they can be available a short while after the main container has started. +We therefore provide custom wait conditions for HiveMQ Extensions: + +The following will specify an extension to be loaded from **src/test/resources/modifier-extension** into the container and +wait for an extension named **'My Extension Name'** to be started: + + +[Custom Wait Strategy](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java) inside_block:waitStrategy + + +Next up we have an example for using an extension directly from the classpath and waiting directly on the extension: + + +[Extension from Classpath](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java) inside_block:extensionClasspath + + +--- +**Note** Debugging extensions + +Both examples contain ```.withDebugging()``` which enables remote debugging on the container. +With debugging enabled you can start putting breakpoints right into your extensions. + +--- + +### Testing extensions using Gradle + +In a Gradle based HiveMQ Extension project, testing is supported using the dedicated [HiveMQ Extension Gradle Plugin](https://github.com/hivemq/hivemq-extension-gradle-plugin/README.md). + +The plugin adds an `integrationTest` task which executes tests from the `integrationTest` source set. +- Integration test source files are defined in `src/integrationTest`. +- Integration test dependencies are defined via the `integrationTestImplementation`, `integrationTestRuntimeOnly`, etc. configurations. + +The `integrationTest` task builds the extension and unzips it to the `build/hivemq-extension-test` directory. +The tests can then load the built extension into the HiveMQ Testcontainer. + + +[Extension from filesystem](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:startFromFilesystem + + +### Enable/Disable an extension + +It is possible to enable and disable HiveMQ extensions during runtime. Extensions can also be disabled on startup. + +--- +**Note**: that disabling or enabling of extension during runtime is only supported in HiveMQ 4 Enterprise Edition Containers. + +--- + +The following example shows how to start a HiveMQ container with the extension called **my-extension** being disabled. + + + +[Disable Extension at startup](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:startDisabled + + +The following test then proceeds to enable and then disable the extension: + + +[Enable/Disable extension at runtime](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:runtimeEnable + + +## Enable/Disable an extension loaded from a folder + +Extensions loaded from an extension folder during runtime can also be enabled/disabled on the fly. +If the extension folder contains a DISABLED file, the extension will be disabled during startup. + +--- +**Note**: that disabling or enabling of extension during runtime is only supported in HiveMQ 4 Enterprise Edition Containers. + +--- + +We first load the extension from the filesytem: + +[Extension from filesystem](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:startFromFilesystem + + +Now we can enable/disable the extension using its name: + + +[Enable/Disable extension at runtime](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:runtimeEnableFilesystem + + +### Remove prepackaged HiveMQ Extensions + +Since HiveMQ's 4.4 release, HiveMQ Docker images come with the HiveMQ Extension for Kafka, the HiveMQ Enterprise Bridge Extension +and the HiveMQ Enterprise Security Extension. +These Extensions are disabled by default, but sometimes you my need to remove them before the container starts. + +Removing all extension is as simple as: + + +[Remove all extensions](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:noExtensions + + +A single extension (e.g. Kafka) can be removed as easily: + +[Remove a specific extension](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:noKafkaExtension + + +## Put files into the container + +### Put a file into HiveMQ home + + +[Put file into HiveMQ home](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java) inside_block:hivemqHome + + +### Put files into extension home + + +[Put file into HiveMQ-Extension home](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java) inside_block:extensionHome + + +### Put license files into the container + + +[Put license file into the HiveMQ container](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java) inside_block:withLicenses + + + +### Customize the Container further + +Since the `HiveMQContainer` extends from [Testcontainer's](https://github.com/testcontainers) `GenericContainer` the container +can be customized as desired. + +## Add to your project + +### Gradle + +Add to `build.gradle`: + +````groovy +testImplementation 'org.testcontainers:hivemq:{{latest_version}}' +```` + +Add to `build.gradle.kts`: + +````kotlin +testImplementation("org.testcontainers:hivemq:{{latest_version}}") +```` + +### Maven + +Add to `pom.xml`: + +```xml + + org.testcontainers + hivemq + {{latest_version}} + test + +``` diff --git a/docs/modules_logos/hivemq-module.png b/docs/modules_logos/hivemq-module.png new file mode 100644 index 0000000000000000000000000000000000000000..55c0ee1644ae05a5ff5b36f90ebdb1006b296f42 GIT binary patch literal 165340 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ⅈLGoj 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 E0rq9^#Q*>R literal 0 HcmV?d00001 diff --git a/mkdocs.yml b/mkdocs.yml index e4115625a7f..7ace7382e41 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,6 +67,7 @@ nav: - modules/docker_compose.md - modules/elasticsearch.md - modules/gcloud.md + - modules/hivemq.md - modules/k3s.md - modules/kafka.md - modules/localstack.md diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle new file mode 100644 index 00000000000..779ac2ec9d8 --- /dev/null +++ b/modules/hivemq/build.gradle @@ -0,0 +1,37 @@ +description = "TestContainers :: HiveMQ" + +dependencies { + api(project(":testcontainers")) + api("org.jetbrains:annotations:23.0.0") + + shaded("org.apache.commons:commons-lang3:3.12.0") + shaded("commons-io:commons-io:2.11.0") + shaded("org.javassist:javassist:3.28.0-GA") + shaded("org.jboss.shrinkwrap:shrinkwrap-api:1.2.6") + shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") + shaded("net.lingala.zip4j:zip4j:2.9.1") + + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") + testImplementation(project(":junit-jupiter")) + testImplementation("com.hivemq:hivemq-extension-sdk:4.7.3") + testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") + testImplementation("org.apache.httpcomponents:httpclient:4.5.13") + testImplementation("ch.qos.logback:logback-classic:1.2.10") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2") +} + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(11) + } +} + +compileTestJava { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(11) + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java new file mode 100644 index 00000000000..37f9a9259d1 --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -0,0 +1,573 @@ +package org.testcontainers.hivemq; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.apache.commons.io.FileUtils; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.MultiLogMessageWaitStrategy; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class HiveMQContainer extends GenericContainer { + + private static final Logger LOGGER = LoggerFactory.getLogger(HiveMQContainer.class); + + private static final DockerImageName DEFAULT_HIVEMQ_EE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq4"); + private static final DockerImageName DEFAULT_HIVEMQ_CE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq-ce"); + + private static final int DEBUGGING_PORT = 9000; + private static final int MQTT_PORT = 1883; + private static final int CONTROL_CENTER_PORT = 8080; + @SuppressWarnings("OctalInteger") + private static final int MODE = 0777; + private static final @NotNull Pattern EXTENSION_ID_PATTERN = Pattern.compile("(.+?)"); + + private final @NotNull ConcurrentHashMap containerOutputLatches = new ConcurrentHashMap<>(); + private boolean controlCenterEnabled = false; + private boolean debugging = false; + + private final @NotNull Set prepackagedExtensionsToRemove = new HashSet<>(); + private boolean removeAllPrepackagedExtensions = false; + + private final @NotNull MultiLogMessageWaitStrategy waitStrategy = new MultiLogMessageWaitStrategy(); + + public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_HIVEMQ_CE_IMAGE_NAME, DEFAULT_HIVEMQ_EE_IMAGE_NAME); + + addExposedPort(MQTT_PORT); + + waitStrategy.withRegEx("(.*)Started HiveMQ in(.*)"); + waitingFor(waitStrategy); + + withLogConsumer(outputFrame -> { + final String utf8String = outputFrame.getUtf8String(); + if (debugging && utf8String.startsWith("Listening for transport dt_socket at address:")) { + System.out.println("Listening for transport dt_socket at address: " + getMappedPort(DEBUGGING_PORT)); + } + if (!containerOutputLatches.isEmpty()) { + containerOutputLatches.forEach((regEx, latch) -> { + if (outputFrame.getUtf8String().matches("(?s)" + regEx)) { + LOGGER.debug("Container Output '{}' matched RegEx '{}'", utf8String, regEx); + latch.countDown(); + } else { + LOGGER.debug("Container Output '{}' did not match RegEx '{}'", utf8String, regEx); + } + }); + } + }); + } + + @Override + protected void configure() { + final String removeCommand; + withCreateContainerCmdModifier(it -> it.withEntrypoint("/bin/sh")); + + if (removeAllPrepackagedExtensions || !prepackagedExtensionsToRemove.isEmpty()) { + + if (removeAllPrepackagedExtensions) { + removeCommand = "rm -rf /opt/hivemq/extensions/** &&"; + } else { + removeCommand = prepackagedExtensionsToRemove.stream() + .map(extensionId -> "rm -rf /opt/hivemq/extensions/" + extensionId + "&&") + .collect(Collectors.joining()); + } + } else { + removeCommand = ""; + } + setCommand( + "-c", + removeCommand + + "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ " + + "; rm -rf /opt/hivemq/temp-extensions/** " + + "&& chmod -R 777 /opt/hivemq/extensions " + + "&& /opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" + ); + } + + protected void containerIsStarted(final @NotNull InspectContainerResponse containerInfo) { + if (controlCenterEnabled) { + LOGGER.info("The HiveMQ Control Center is reachable under: http://{}:{}", getHost(), getMappedPort(CONTROL_CENTER_PORT)); + } + } + + /** + * Adds a wait condition for the extension with this name. + *

+ * Must be called before the container is started. + * + * @param extensionName the extension to wait for + * @return self + */ + public @NotNull HiveMQContainer waitForExtension(final @NotNull String extensionName) { + final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) started successfully(.*)"; + waitStrategy.withRegEx(regEX); + return self(); + } + + /** + * Adds a wait condition for this {@link HiveMQExtension} + *

+ * Must be called before the container is started. + * + * @param extension the extension to wait for + * @return self + */ + public @NotNull HiveMQContainer waitForExtension(final @NotNull HiveMQExtension extension) { + return this.waitForExtension(extension.getName()); + } + + /** + * Enables the possibility for remote debugging clients to connect. + *

+ * Must be called before the container is started. + * + * @return self + */ + public @NotNull HiveMQContainer withDebugging() { + debugging = true; + addExposedPorts(DEBUGGING_PORT); + withEnv("JAVA_OPTS", "-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:" + DEBUGGING_PORT + ",server=y,suspend=y"); + return self(); + } + + /** + * Sets the logging {@link Level} inside the container. + *

+ * Must be called before the container is started. + * + * @param level the {@link Level} + * @return self + */ + public @NotNull HiveMQContainer withLogLevel(final @NotNull Level level) { + this.withEnv("HIVEMQ_LOG_LEVEL", level.name()); + return self(); + } + + /** + * Wraps the given class and all its subclasses into an extension + * and puts it into '/opt/hivemq/temp-extensions/{extension-id}' inside the container. + *

+ * Must be called before the container is started. + *

+ * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. + * + * @param hiveMQExtension the {@link HiveMQExtension} of the extension + * @return self + */ + public @NotNull HiveMQContainer withExtension(final @NotNull HiveMQExtension hiveMQExtension) { + try { + final File extension = hiveMQExtension.createExtension(hiveMQExtension); + final MountableFile mountableExtension = MountableFile.forHostPath(extension.getPath(), MODE); + withCopyFileToContainer(mountableExtension, "/opt/hivemq/temp-extensions/" + hiveMQExtension.getId()); + } catch (final Exception e) { + throw new ContainerLaunchException(e.getMessage() == null ? "" : e.getMessage(), e); + } + return self(); + } + + /** + * Puts the given extension folder into '/opt/hivemq/temp-extensions/{directory-name}' inside the container. + * It must at least contain a valid hivemq-extension.xml and a valid extension.jar in order to be executed. + * The directory-name is taken from the id defined in the hivemq-extension.xml. + *

+ * Must be called before the container is started. + *

+ * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. + * + * @param mountableExtension the extension folder on the host machine + * @return self + */ + public @NotNull HiveMQContainer withExtension(final @NotNull MountableFile mountableExtension) { + final File extensionDir = new File(mountableExtension.getResolvedPath()); + if (!extensionDir.exists()) { + throw new ContainerLaunchException("Extension '" + mountableExtension.getFilesystemPath() + "' could not be mounted. It does not exist."); + } + if (!extensionDir.isDirectory()) { + throw new ContainerLaunchException("Extension '" + mountableExtension.getFilesystemPath() + "' could not be mounted. It is not a directory."); + } + try { + final String extensionDirName = getExtensionDirectoryName(extensionDir); + final String containerPath = "/opt/hivemq/temp-extensions/" + extensionDirName; + withCopyFileToContainer(cloneWithFileMode(mountableExtension), containerPath); + LOGGER.info("Putting extension '{}' into '{}'", extensionDirName, containerPath); + } catch (final Exception e) { + throw new ContainerLaunchException(e.getMessage() == null ? "" : e.getMessage(), e); + } + return self(); + } + + private @NotNull String getExtensionDirectoryName(final @NotNull File extensionDirectory) throws IOException { + final File file = new File(extensionDirectory, "hivemq-extension.xml"); + final String xml = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + final Matcher matcher = EXTENSION_ID_PATTERN.matcher(xml); + + if (!matcher.find()) { + throw new IllegalStateException("Could not parse extension id from '" + file.getAbsolutePath() + "'"); + } + return matcher.group(1); + } + + /** + * Removes the specified prepackaged extension folders from '/opt/hivemq/extensions' before the container is started. + *

+ * Must be called before the container is started. + * + * @param extensionIds the prepackaged extensions to remove + * @return self + */ + public @NotNull HiveMQContainer withoutPrepackagedExtensions(final @NotNull String... extensionIds) { + Collections.addAll(prepackagedExtensionsToRemove, extensionIds); + return self(); + } + + /** + * Removes all prepackaged extension folders from '/opt/hivemq/extensions' before the container is started. + *

+ * Must be called before the container is started. + * + * @return self + */ + public @NotNull HiveMQContainer withoutPrepackagedExtensions() { + removeAllPrepackagedExtensions = true; + return self(); + } + + /** + * Puts the given license into '/opt/hivemq/license/' inside the container. + * It must end with '.lic' or '.elic'. + *

+ * Must be called before the container is started. + * + * @param mountableLicense the license file on the host machine + * @return self + */ + public @NotNull HiveMQContainer withLicense(final @NotNull MountableFile mountableLicense) { + final File licenseFile = new File(mountableLicense.getResolvedPath()); + if (!licenseFile.exists()) { + throw new ContainerLaunchException("License file '" + mountableLicense.getFilesystemPath() + "' does not exist."); + } + if (!licenseFile.getName().endsWith(".lic") && !licenseFile.getName().endsWith(".elic")) { + throw new ContainerLaunchException("License file '" + mountableLicense.getFilesystemPath() + "' does not end wit '.lic' or '.elic'."); + } + final String containerPath = "/opt/hivemq/license/" + licenseFile.getName(); + withCopyFileToContainer(cloneWithFileMode(mountableLicense), containerPath); + LOGGER.info("Putting license '{}' into '{}'.", licenseFile.getAbsolutePath(), containerPath); + return self(); + } + + /** + * Overwrites the HiveMQ configuration in '/opt/hivemq/conf/' inside the container. + *

+ * Must be called before the container is started. + * + * @param mountableConfig the config file on the host machine + * @return self + */ + public @NotNull HiveMQContainer withHiveMQConfig(final @NotNull MountableFile mountableConfig) { + final File config = new File(mountableConfig.getResolvedPath()); + if (!config.exists()) { + throw new ContainerLaunchException("HiveMQ config file '" + mountableConfig.getFilesystemPath() + "' does not exist."); + } + final String containerPath = "/opt/hivemq/conf/config.xml"; + withCopyFileToContainer(cloneWithFileMode(mountableConfig), containerPath); + LOGGER.info("Putting '{}' into '{}'.", config.getAbsolutePath(), containerPath); + return self(); + } + + /** + * Puts the given file into the root of the extension's home '/opt/hivemq/temp-extensions/{extensionId}/'. + *

+ * Must be called before the container is started. + *

+ * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. + * + * @param file the file on the host machine + * @param extensionId the extension + * @return self + */ + public @NotNull HiveMQContainer withFileInExtensionHomeFolder( + final @NotNull MountableFile file, + final @NotNull String extensionId) { + + return withFileInExtensionHomeFolder(file, extensionId, ""); + } + + /** + * Puts the given file into given subdirectory of the extensions's home '/opt/hivemq/temp-extensions/{id}/{pathInExtensionHome}/' + *

+ * Must be called before the container is started. + *

+ * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. + * + * @param file the file on the host machine + * @param extensionId the extension + * @param pathInExtensionHome the path + * @return self + */ + public @NotNull HiveMQContainer withFileInExtensionHomeFolder( + final @NotNull MountableFile file, + final @NotNull String extensionId, + final @NotNull String pathInExtensionHome) { + + return withFileInHomeFolder(file, "/temp-extensions/" + extensionId + PathUtil.prepareAppendPath(pathInExtensionHome)); + } + + /** + * Puts the given file into the given subdirectory of the HiveMQ home folder '/opt/hivemq/{pathInHomeFolder}'. + *

+ * Must be called before the container is started. + * + * @param mountableFile the file on the host machine + * @param pathInHomeFolder the path + * @return self + */ + public @NotNull HiveMQContainer withFileInHomeFolder( + final @NotNull MountableFile mountableFile, + final @NotNull String pathInHomeFolder) { + + final File file = new File(mountableFile.getResolvedPath()); + + if (pathInHomeFolder.trim().isEmpty()) { + throw new ContainerLaunchException("pathInHomeFolder must not be empty"); + } + + if (!file.exists()) { + throw new ContainerLaunchException("File '" + mountableFile.getFilesystemPath() + "‘ does not exist."); + } + final String containerPath = "/opt/hivemq" + PathUtil.prepareAppendPath(pathInHomeFolder); + withCopyFileToContainer(cloneWithFileMode(mountableFile), containerPath); + LOGGER.info("Putting file '{}' into container path '{}'.", file.getAbsolutePath(), containerPath); + return self(); + } + + /** + * Disables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after {timeOut}. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @param timeout the timeout + * @throws TimeoutException if the extension was not disabled within the configured timeout + */ + public void disableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory, + final @NotNull Duration timeout) throws TimeoutException { + + final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) stopped successfully(.*)"; + try { + final String containerPath = "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; + + final CountDownLatch latch = new CountDownLatch(1); + containerOutputLatches.put(regEX, latch); + + execInContainer("touch", containerPath); + LOGGER.info("Putting DISABLED file into container path '{}'", containerPath); + + final boolean await = latch.await(timeout.getSeconds(), TimeUnit.SECONDS); + if (!await) { + throw new TimeoutException("Extension disabling timed out after '" + timeout.getSeconds() + "' seconds. " + + "Maybe you are using a HiveMQ Community Edition image, " + + "which does not support disabling of extensions"); + } + } catch (final InterruptedException | IOException e) { + throw new RuntimeException(e); + } finally { + containerOutputLatches.remove(regEX); + } + } + + /** + * Disables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after 60 seconds. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @throws TimeoutException if the extension was not disabled within 60 seconds + */ + public void disableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory) throws TimeoutException { + disableExtension(extensionName, extensionDirectory, Duration.ofSeconds(60)); + } + + /** + * Disables the extension. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after {timeOut}. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @param timeout the timeout + * @throws TimeoutException if the extension was not disabled within the configured timeout + */ + public void disableExtension( + final @NotNull HiveMQExtension hiveMQExtension, + final @NotNull Duration timeout) throws TimeoutException { + disableExtension(hiveMQExtension.getName(), hiveMQExtension.getId(), timeout); + } + + /** + * Disables the extension. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after 60 seconds. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @throws TimeoutException if the extension was not disabled within 60 seconds + */ + public void disableExtension(final @NotNull HiveMQExtension hiveMQExtension) throws TimeoutException { + disableExtension(hiveMQExtension, Duration.ofSeconds(60)); + } + + /** + * Enables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after {timeOut}. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @param timeout the timeout + * @throws TimeoutException if the extension was not enabled within the configured timeout + */ + public void enableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory, + final @NotNull Duration timeout) throws TimeoutException { + + final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) started successfully(.*)"; + try { + final String containerPath = "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; + + final CountDownLatch latch = new CountDownLatch(1); + containerOutputLatches.put(regEX, latch); + + execInContainer("rm", "-rf", containerPath); + LOGGER.info("Removing DISABLED file in container path '{}'", containerPath); + + final boolean await = latch.await(timeout.getSeconds(), TimeUnit.SECONDS); + if (!await) { + throw new TimeoutException("Extension enabling timed out after '" + timeout.getSeconds() + "' seconds. " + + "Maybe you are using a HiveMQ Community Edition image, " + + "which does not support disabling of extensions"); + } + } catch (final InterruptedException | IOException e) { + throw new RuntimeException(e); + } finally { + containerOutputLatches.remove(regEX); + } + } + + /** + * Enables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after 60 seconds. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @throws TimeoutException if the extension was not enabled within 60 seconds + */ + public void enableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory) throws TimeoutException { + enableExtension(extensionName, extensionDirectory, Duration.ofSeconds(60)); + } + + /** + * Enables the extension. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after {timeOut}. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @param timeout the timeout + * @throws TimeoutException if the extension was not enabled within the configured timeout + */ + public void enableExtension( + final @NotNull HiveMQExtension hiveMQExtension, + final @NotNull Duration timeout) throws TimeoutException { + enableExtension(hiveMQExtension.getName(), hiveMQExtension.getId(), timeout); + } + + /** + * Enables the extension. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after {timeOut}. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @throws TimeoutException if the extension was not enabled within 60 seconds + */ + public void enableExtension(final @NotNull HiveMQExtension hiveMQExtension) throws TimeoutException { + enableExtension(hiveMQExtension, Duration.ofSeconds(60)); + } + + /** + * Enables connection to the HiveMQ Control Center on host port 8080. + * Note: the control center is a HiveMQ 4 Enterprise feature. + *

+ * Must be called before the container is started. + * + * @return self + */ + public @NotNull HiveMQContainer withControlCenter() { + addExposedPorts(CONTROL_CENTER_PORT); + controlCenterEnabled = true; + return self(); + } + + /** + * Get the mapped port for the MQTT port of the container. + *

+ * Must be called after the container is started. + * + * @return the port on the host machine for mqtt clients to connect + */ + public int getMqttPort() { + return this.getMappedPort(MQTT_PORT); + } + + @Override + protected void containerIsStopping(final @NotNull InspectContainerResponse containerInfo) { + waitStrategy.reset(); + } + + private @NotNull MountableFile cloneWithFileMode(final @NotNull MountableFile mountableFile) { + return MountableFile.forHostPath(mountableFile.getResolvedPath(), HiveMQContainer.MODE); + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java new file mode 100644 index 00000000000..a975439f4b3 --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -0,0 +1,287 @@ +package org.testcontainers.hivemq; + +import javassist.ClassPool; +import javassist.NotFoundException; +import lombok.Getter; +import org.apache.commons.io.FileUtils; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.exporter.ZipExporter; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.ContainerLaunchException; + +import java.io.File; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class HiveMQExtension { + + private static final String VALID_EXTENSION_XML = + "" + // + " %s" + // + " %s" + // + " %s" + // + " %s" + // + " %s" + // + ""; + private static final String EXTENSION_MAIN_CLASS_NAME = "com.hivemq.extension.sdk.api.ExtensionMain"; + private static final Logger LOGGER = LoggerFactory.getLogger(HiveMQExtension.class); + + @Getter + private final @NotNull String id; + + @Getter + private final @NotNull String name; + + @Getter + private final @NotNull String version; + + @Getter + private final int priority; + + @Getter + private final int startPriority; + + @Getter + private final boolean disabledOnStartup; + + @Getter + private final @NotNull Class mainClass; + + private final @NotNull List> additionalClasses; + + private HiveMQExtension( + final @NotNull String id, + final @NotNull String name, + final @NotNull String version, + final int priority, + final int startPriority, + final boolean disabledOnStartup, + final @NotNull Class mainClass, + final @NotNull List> additionalClasses) { + + this.id = id; + this.name = name; + this.version = version; + this.priority = priority; + this.startPriority = startPriority; + this.disabledOnStartup = disabledOnStartup; + this.mainClass = mainClass; + this.additionalClasses = additionalClasses; + } + + @NotNull File createExtension(final @NotNull HiveMQExtension hiveMQExtension) + throws Exception { + + final File tempDir = Files.createTempDirectory("").toFile(); + + final File extensionDir = new File(tempDir, hiveMQExtension.getId()); + FileUtils.writeStringToFile(new File(extensionDir, "hivemq-extension.xml"), + String.format( + VALID_EXTENSION_XML, + hiveMQExtension.getId(), + hiveMQExtension.getName(), + hiveMQExtension.getVersion(), + hiveMQExtension.getPriority(), + hiveMQExtension.getStartPriority()), + Charset.defaultCharset()); + + if (hiveMQExtension.isDisabledOnStartup()) { + final File disabled = new File(extensionDir, "DISABLED"); + final boolean newFile = disabled.createNewFile(); + if (!newFile) { + throw new ContainerLaunchException("Could not create DISABLED file '" + disabled.getAbsolutePath() + "' on host machine."); + } + } + + final JavaArchive javaArchive = + ShrinkWrap.create(JavaArchive.class) + .addAsServiceProvider(EXTENSION_MAIN_CLASS_NAME, hiveMQExtension.getMainClass().getName()); + + putSubclassesIntoJar(hiveMQExtension.getId(), hiveMQExtension.getMainClass(), javaArchive); + for (final Class additionalClass : hiveMQExtension.getAdditionalClasses()) { + javaArchive.addClass(additionalClass); + putSubclassesIntoJar(hiveMQExtension.getId(), additionalClass, javaArchive); + } + + javaArchive.as(ZipExporter.class).exportTo(new File(extensionDir, "extension.jar")); + + return extensionDir; + } + + private void putSubclassesIntoJar( + final @NotNull String extensionId, + final @Nullable Class clazz, + final @NotNull JavaArchive javaArchive) throws NotFoundException { + + if (clazz != null) { + final Set subClassNames = + ClassPool.getDefault().get(clazz.getName()).getClassFile().getConstPool().getClassNames(); + for (final String subClassName : subClassNames) { + final String className = subClassName.replaceAll("/", "."); + + if (!className.startsWith("[L")) { + LOGGER.debug("Trying to package subclass '{}' into extension '{}'.", className, extensionId); + javaArchive.addClass(className); + } else { + LOGGER.debug("Class '{}' will be ignored.", className); + } + } + } + } + + public @NotNull List> getAdditionalClasses() { + return Collections.unmodifiableList(additionalClasses); + } + + public static @NotNull Builder builder() { + return new Builder(); + } + + public static final class Builder { + private @Nullable String id; + private @Nullable String name; + private @Nullable String version; + private int priority = 0; + private int startPriority = 0; + private boolean disabledOnStartup = false; + private @Nullable Class mainClass; + private final @NotNull LinkedList> additionalClasses = new LinkedList<>(); + + /** + * Builds the {@link HiveMQExtension} with the provided values or default values. + * @return the HiveMQ Extension + */ + public @NotNull HiveMQExtension build() { + if (id == null || id.isEmpty()) { + throw new IllegalArgumentException("extension id must not be null or empty"); + } + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("extension name must not be null or empty"); + } + if (version == null || version.isEmpty()) { + throw new IllegalArgumentException("extension version must not be null or empty"); + } + if (mainClass == null) { + throw new IllegalArgumentException("extension main class must not be null"); + } + return new HiveMQExtension( + id, + name, + version, + priority, + startPriority, + disabledOnStartup, + mainClass, + additionalClasses + ); + } + + /** + * Sets the identifier of the {@link HiveMQExtension}. + * + * @param id the identifier, must not be empty + * @return the {@link Builder} + */ + public @NotNull Builder id(final @NotNull String id) { + this.id = id; + return this; + } + + /** + * Sets the name of the {@link HiveMQExtension}. + * + * @param name the identifier, must not be empty + * @return the {@link Builder} + */ + public @NotNull Builder name(final @NotNull String name) { + this.name = name; + return this; + } + + /** + * Sets the version of the {@link HiveMQExtension}. + * + * @param version the version, must not be empty + * @return the {@link Builder} + */ + public @NotNull Builder version(final @NotNull String version) { + this.version = version; + return this; + } + + /** + * Sets the priority of the {@link HiveMQExtension}. + * + * @param priority the priority + * @return the {@link Builder} + */ + public @NotNull Builder priority(final int priority) { + this.priority = priority; + return this; + } + + /** + * Sets the start-priority of the {@link HiveMQExtension}. + * + * @param startPriority the start-priority + * @return the {@link Builder} + */ + public @NotNull Builder startPriority(final int startPriority) { + this.startPriority = startPriority; + return this; + } + + /** + * Flag, that indicates whether the {@link HiveMQExtension} should be disabled when HiveMQ starts. + * Disabling on startup is achieved by placing a DISABLED file in the {@link HiveMQExtension}'s directory before coping it to the container. + * + * @param disabledOnStartup if the {@link HiveMQExtension} should be disabled when HiveMQ starts + * @return the {@link Builder} + */ + public @NotNull Builder disabledOnStartup(final boolean disabledOnStartup) { + this.disabledOnStartup = disabledOnStartup; + return this; + } + + /** + * The main class of the {@link HiveMQExtension}. + * This class MUST implement com.hivemq.extension.sdk.api.ExtensionMain. + * + * @param mainClass the main class + * @return the {@link Builder} + * @throws IllegalArgumentException if the provides class does not implement com.hivemq.extension.sdk.api.ExtensionMain} + * @throws IllegalStateException if com.hivemq.extension.sdk.api.ExtensionMain is not found in the classpath + */ + public @NotNull Builder mainClass(final @NotNull Class mainClass) { + try { + final Class extensionMain = Class.forName(EXTENSION_MAIN_CLASS_NAME); + if (!extensionMain.isAssignableFrom(mainClass)) { + throw new IllegalArgumentException("The provided class does not implement '" + EXTENSION_MAIN_CLASS_NAME + "'"); + } + this.mainClass = mainClass; + return this; + } catch (final ClassNotFoundException e) { + throw new IllegalStateException("The class '" + EXTENSION_MAIN_CLASS_NAME + "' was not found in the classpath."); + } + } + + /** + * Adds an additional class to the .jar file of the {@link HiveMQExtension}. + * + * @param clazz the additional class + * @return the {@link Builder} + */ + public @NotNull Builder addAdditionalClass(final @NotNull Class clazz) { + this.additionalClasses.add(clazz); + return this; + } + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java new file mode 100755 index 00000000000..245052f46b8 --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java @@ -0,0 +1,26 @@ +package org.testcontainers.hivemq; + +import org.jetbrains.annotations.NotNull; + +class PathUtil { + + static @NotNull String prepareInnerPath(@NotNull String innerPath) { + if ("/".equals(innerPath) || innerPath.isEmpty()) { + return "/"; + } + if (!innerPath.startsWith("/")) { + innerPath = "/" + innerPath; + } + if (!innerPath.endsWith("/")) { + innerPath += "/"; + } + return innerPath; + } + + static @NotNull String prepareAppendPath(@NotNull String appendPath) { + if (!appendPath.startsWith("/")) { + appendPath = "/" + appendPath; + } + return appendPath; + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java new file mode 100644 index 00000000000..f88d60b22ed --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -0,0 +1,34 @@ +package org.testcontainers.hivemq; + +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.utility.DockerImageName; + +import java.util.concurrent.TimeUnit; + +public class ContainerWithControlCenterIT { + + public static final int CONTROL_CENTER_PORT = 8080; + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void test() throws Exception { + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withControlCenter()) { + + hivemq.start(); + + try (final CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { + final HttpUriRequest request = new HttpGet("http://" + hivemq.getHost() + ":" + hivemq.getMappedPort(CONTROL_CENTER_PORT)); + httpClient.execute(request); + } + } + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java new file mode 100755 index 00000000000..17f09d86adf --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -0,0 +1,43 @@ +package org.testcontainers.hivemq; + +import com.hivemq.client.mqtt.datatypes.MqttQos; +import com.hivemq.client.mqtt.exceptions.MqttSessionExpiredException; +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ContainerWithCustomConfigIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + + try (final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withHiveMQConfig(MountableFile.forClasspathResource("/config.xml"))) { + + hivemq.start(); + + final Mqtt5BlockingClient publisher = Mqtt5Client.builder() + .identifier("publisher") + .serverPort(hivemq.getMqttPort()) + .buildBlocking(); + + publisher.connect(); + + assertThrows(MqttSessionExpiredException.class, () -> { + // this should fail since only QoS 0 is allowed by the configuration + publisher.publishWith() + .topic("test/topic") + .qos(MqttQos.EXACTLY_ONCE) + .send(); + }); + } + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java new file mode 100755 index 00000000000..7672c70925d --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -0,0 +1,43 @@ +package org.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +public class ContainerWithExtensionFromDirectoryIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + try ( + final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension") + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withLogLevel(Level.DEBUG)) { + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test_wrongDirectoryName() throws Exception { + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withExtension(MountableFile.forClasspathResource("/modifier-extension-wrong-name")) + .waitForExtension("Modifier Extension") + .withLogLevel(Level.DEBUG)) { + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java new file mode 100755 index 00000000000..3ad7b26148a --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -0,0 +1,41 @@ +package org.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.MyExtension; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +public class ContainerWithExtensionIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtension.class).build(); + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension)) { + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + hivemq.stop(); + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + hivemq.stop(); + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java new file mode 100755 index 00000000000..33880a800c9 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -0,0 +1,35 @@ +package org.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.MyExtensionWithSubclasses; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +public class ContainerWithExtensionSubclassIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtensionWithSubclasses.class).build(); + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withLogLevel(Level.DEBUG)) { + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java new file mode 100755 index 00000000000..1d2b1705eae --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -0,0 +1,77 @@ +package org.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +public class ContainerWithFileInExtensionHomeIT { + + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCheckerExtension.class).build(); + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInExtensionHomeFolder( + MountableFile.forClasspathResource("/additionalFile.txt"), + "extension-1", + "/additionalFiles/my-file.txt")) { + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + + public static class FileCheckerExtension implements ExtensionMain { + + @Override + public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File extensionHomeFolder = extensionStartInput.getExtensionInformation().getExtensionHomeFolder(); + + final File additionalFile = new File(extensionHomeFolder, "additionalFiles/my-file.txt"); + + if (additionalFile.exists()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java new file mode 100755 index 00000000000..542c54789e8 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -0,0 +1,75 @@ +package org.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +public class ContainerWithFileInHomeIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCheckerExtension.class).build(); + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInHomeFolder(MountableFile.forClasspathResource("/additionalFile.txt"), + "/additionalFiles/my-file.txt")) { + + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + + public static class FileCheckerExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); + + final File additionalFile = new File(homeFolder, "additionalFiles/my-file.txt"); + + if (additionalFile.exists()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java new file mode 100755 index 00000000000..4fc27adf8c2 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -0,0 +1,78 @@ +package org.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +public class ContainerWithLicenseIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(LicenceCheckerExtension.class).build(); + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withLicense(MountableFile.forClasspathResource("/myLicense.lic")) + .withLicense(MountableFile.forClasspathResource("/myExtensionLicense.elic"))) { + + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + + @SuppressWarnings("CodeBlock2Expr") + public static class LicenceCheckerExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); + final File myLicence = new File(homeFolder, "license/myLicense.lic"); + final File myExtensionLicence = new File(homeFolder, "license/myExtensionLicense.elic"); + + if (myLicence.exists() && myExtensionLicence.exists()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java new file mode 100644 index 00000000000..37b37dc0d59 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -0,0 +1,135 @@ +package org.testcontainers.hivemq; + +import com.hivemq.client.mqtt.MqttClient; +import com.hivemq.client.mqtt.MqttGlobalPublishFilter; +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish; +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.auth.SimpleAuthenticator; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.builder.Builders; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.utility.DockerImageName; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ContainerWithoutPlatformExtensionsIT { + + private final @NotNull HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .name("MyExtension") + .id("my-extension") + .version("1.0.0") + .mainClass(CheckerExtension.class).build(); + + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void removeAllPlatformExtensions() throws InterruptedException { + + try (final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withoutPrepackagedExtensions()) { + + hivemq.start(); + + final Mqtt5BlockingClient client = MqttClient.builder() + .serverPort(hivemq.getMqttPort()) + .useMqttVersion5() + .buildBlocking(); + + client.connect(); + final Mqtt5BlockingClient.Mqtt5Publishes publishes = client.publishes(MqttGlobalPublishFilter.ALL); + client.subscribeWith().topicFilter("extensions").send(); + + final Mqtt5Publish receive = publishes.receive(); + assertTrue(receive.getPayload().isPresent()); + final String extensionInfo = new String(receive.getPayloadAsBytes()); + + assertFalse(extensionInfo.contains("hivemq-allow-all-extension")); + assertFalse(extensionInfo.contains("hivemq-kafka-extension")); + assertFalse(extensionInfo.contains("hivemq-bridge-extension")); + assertFalse(extensionInfo.contains("hivemq-enterprise-security-extension")); + + hivemq.start(); + } + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void removeKafkaExtension() throws InterruptedException { + + try (final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withoutPrepackagedExtensions("hivemq-kafka-extension")) { + + hivemq.start(); + + final Mqtt5BlockingClient client = MqttClient.builder() + .serverPort(hivemq.getMqttPort()) + .useMqttVersion5() + .buildBlocking(); + + client.connect(); + final Mqtt5BlockingClient.Mqtt5Publishes publishes = client.publishes(MqttGlobalPublishFilter.ALL); + client.subscribeWith().topicFilter("extensions").send(); + + final Mqtt5Publish receive = publishes.receive(); + assertTrue(receive.getPayload().isPresent()); + final String extensionInfo = new String(receive.getPayloadAsBytes()); + + assertTrue(extensionInfo.contains("hivemq-allow-all-extension")); + assertFalse(extensionInfo.contains("hivemq-kafka-extension")); + assertTrue(extensionInfo.contains("hivemq-bridge-extension")); + assertTrue(extensionInfo.contains("hivemq-enterprise-security-extension")); + } + } + + public static class CheckerExtension implements ExtensionMain { + + @Override + public void extensionStart( + final @NotNull ExtensionStartInput extensionStartInput, + final @NotNull ExtensionStartOutput extensionStartOutput) { + + final String extensionFolders = Arrays.stream(extensionStartInput.getServerInformation().getExtensionsFolder().listFiles()) + .filter(File::isDirectory) + .map(File::getName) + .collect(Collectors.joining("\n")); + + final byte[] bytes = extensionFolders.getBytes(StandardCharsets.UTF_8); + Services.publishService().publish(Builders.publish() + .topic("extensions") + .retain(true) + .payload(ByteBuffer.wrap(bytes)) + .build()); + + Services.securityRegistry().setAuthenticatorProvider(authenticatorProviderInput -> + (SimpleAuthenticator) (simpleAuthInput, simpleAuthOutput) -> + simpleAuthOutput.authenticateSuccessfully()); + + } + + @Override + public void extensionStop( + final @NotNull ExtensionStopInput extensionStopInput, + final @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java new file mode 100755 index 00000000000..85089374624 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -0,0 +1,92 @@ +package org.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CreateFileInCopiedDirectoryIT { + + private @NotNull MountableFile createDirectory() throws IOException { + final File directory = new File(Files.createTempDirectory("").toFile(), "directory"); + assertTrue(directory.mkdir()); + final File subdirectory = new File(directory, "sub-directory"); + assertTrue(subdirectory.mkdir()); + return MountableFile.forHostPath(directory.getPath()); + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension extension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCreatorExtension.class).build(); + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(extension) + .waitForExtension(extension) + .withFileInHomeFolder(createDirectory(), "directory")) { + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + + public static class FileCreatorExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); + + final File dir = new File(homeFolder, "directory"); + final File dirFile = new File(dir, "file.txt"); + final File subDir = new File(dir, "sub-directory"); + final File subDirFile = new File(subDir, "file.txt"); + + try { + if (dirFile.createNewFile() && subDirFile.createNewFile()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + } catch (IOException e) { + e.printStackTrace(); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java new file mode 100755 index 00000000000..a7756c69f1d --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -0,0 +1,76 @@ +package org.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +public class CreateFileInExtensionDirectoryIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCreatorExtension.class).build(); + + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension)) { + + hivemq.start(); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + + public static class FileCreatorExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File extensionHomeFolder = extensionStartInput.getExtensionInformation().getExtensionHomeFolder(); + + final File file = new File(extensionHomeFolder, "myfile.txt"); + try { + if (file.createNewFile()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + } catch (IOException e) { + e.printStackTrace(); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java new file mode 100644 index 00000000000..2248681a769 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -0,0 +1,37 @@ +package org.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class DisableEnableExtensionFromDirectoryIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension") + .withLogLevel(Level.DEBUG)) { + + hivemq.start(); + + + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + hivemq.disableExtension("Modifier Extension", "modifier-extension"); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort())); + hivemq.enableExtension("Modifier Extension", "modifier-extension"); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java new file mode 100644 index 00000000000..7cc943c5527 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -0,0 +1,46 @@ +package org.testcontainers.hivemq; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.MyExtension; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class DisableEnableExtensionIT { + + private final @NotNull HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .disabledOnStartup(true) + .mainClass(MyExtension.class).build(); + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + try (final HiveMQContainer hivemq = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(hiveMQExtension) + .withLogLevel(Level.DEBUG)) { + + + hivemq.start(); + + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort())); + hivemq.enableExtension(hiveMQExtension); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + hivemq.disableExtension(hiveMQExtension); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort())); + hivemq.enableExtension(hiveMQExtension); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java new file mode 100644 index 00000000000..d614a59bd8c --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java @@ -0,0 +1,13 @@ +package org.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class HiveMQExtensionTest { + + @Test + void builder_classDoesNotImplementExtensionMain_exception() { + assertThrows(IllegalArgumentException.class, () -> HiveMQExtension.builder().mainClass(HiveMQExtensionTest.class)); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java new file mode 100644 index 00000000000..40820e33ded --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java @@ -0,0 +1,82 @@ +package org.testcontainers.hivemq; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class HiveMQTestContainerCore { + + final @NotNull HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")); + + @TempDir + File tempDir; + + @Test + void withExtension_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withExtension(mountableFile)); + } + + @Test + void withExtension_fileNoDirectory_Exception() throws IOException { + final File extension = new File(tempDir, "extension"); + assertTrue(extension.createNewFile()); + final MountableFile mountableFile = MountableFile.forHostPath(extension.getAbsolutePath()); + assertThrows(ContainerLaunchException.class, () -> container.withExtension(mountableFile)); + } + + @Test + void withLicense_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withLicense(mountableFile)); + } + + @Test + void withExtension_fileEndingWrong_Exception() throws IOException { + final File extension = new File(tempDir, "extension.wrong"); + assertTrue(extension.createNewFile()); + final MountableFile mountableFile = MountableFile.forHostPath(extension.getAbsolutePath()); + assertThrows(ContainerLaunchException.class, () -> container.withLicense(mountableFile)); + } + + @Test + void withHiveMQConfig_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withHiveMQConfig(mountableFile)); + } + + @Test + void withFileInHomeFolder_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withFileInHomeFolder(mountableFile, "some/path")); + } + + @Test + void withFileInHomeFolder_pathEmpty_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withFileInHomeFolder(mountableFile, "")); + } + + @Test + void withFileInExtensionHomeFolder_withPath_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withFileInExtensionHomeFolder(mountableFile, "my-extension", "some/path")); + } + + @Test + void withFileInExtensionHomeFolder_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> { + final HiveMQContainer hiveMQContainer = container.withFileInExtensionHomeFolder(mountableFile, "my-extension"); + }); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java new file mode 100755 index 00000000000..f1e060e68d9 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java @@ -0,0 +1,43 @@ +package org.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PathUtilTest { + + @Test + void prepareInnerPath_emptyString() { + assertEquals("/", PathUtil.prepareInnerPath("")); + } + + @Test + void prepareInnerPath_onlyDelimiter() { + assertEquals("/", PathUtil.prepareInnerPath("/")); + } + + @Test + void prepareInnerPath_noDelimiter() { + assertEquals("/path/", PathUtil.prepareInnerPath("path")); + } + + @Test + void prepareInnerPath_delimiterAtEnd() { + assertEquals("/path/", PathUtil.prepareInnerPath("path/")); + } + + @Test + void prepareInnerPath_delimiterAtBeginning() { + assertEquals("/path/", PathUtil.prepareInnerPath("/path")); + } + + @Test + void prepareAppendPath_delimiterAtBeginning_noChange() { + assertEquals("/path", PathUtil.prepareAppendPath("/path")); + } + + @Test + void prepareAppendPath_delimiterAtBeginning_delimiterAdded() { + assertEquals("/path", PathUtil.prepareAppendPath("path")); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java new file mode 100644 index 00000000000..e9d9463653e --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java @@ -0,0 +1,63 @@ +package org.testcontainers.hivemq.docs; + +import org.junit.jupiter.api.Test; +import org.testcontainers.hivemq.HiveMQContainer; +import org.testcontainers.hivemq.HiveMQExtension; +import org.testcontainers.hivemq.util.MyExtension; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +@Testcontainers +public class DemoDisableExtensionsIT { + + // noExtensions { + @Container + final HiveMQContainer hivemqNoExtensions = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withoutPrepackagedExtensions(); + // } + + // noKafkaExtension { + @Container + final HiveMQContainer hivemqNoKafkaExtension = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withoutPrepackagedExtensions("hivemq-kafka-extension"); + // } + + // startDisabled { + private final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .disabledOnStartup(true) + .mainClass(MyExtension.class).build(); + + @Container + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(hiveMQExtension); + // } + + + // startFromFilesystem { + @Container + final HiveMQContainer hivemqExtensionFromFilesystem = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(MountableFile.forHostPath("src/test/resources/modifier-extension")); + // } + + + // runtimeEnable { + @Test + void test_disable_enable_extension() throws Exception { + hivemq.enableExtension(hiveMQExtension); + hivemq.disableExtension(hiveMQExtension); + } + // } + + // runtimeEnableFilesystem { + @Test + void test_disable_enable_extension_from_filesystem() throws Exception { + hivemqExtensionFromFilesystem.disableExtension("Modifier Extension", "modifier-extension"); + hivemqExtensionFromFilesystem.enableExtension("Modifier Extension", "modifier-extension"); + } + // } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java new file mode 100644 index 00000000000..2627dca2028 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java @@ -0,0 +1,57 @@ +package org.testcontainers.hivemq.docs; + +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.HiveMQContainer; +import org.testcontainers.hivemq.HiveMQExtension; +import org.testcontainers.hivemq.util.MyExtensionWithSubclasses; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +@Testcontainers +public class DemoExtensionTestsIT { + + // waitStrategy { + @Container + final HiveMQContainer hivemqWithWaitStrategy = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension"); + // } + + // extensionClasspath { + final HiveMQExtension hiveMQEClasspathxtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtensionWithSubclasses.class).build(); + + @Container + final HiveMQContainer hivemqWithClasspathExtension = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .waitForExtension(hiveMQEClasspathxtension) + .withExtension(hiveMQEClasspathxtension) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")); + // } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void test() throws Exception { + + // mqtt5client { + final Mqtt5BlockingClient client = Mqtt5Client.builder() + .serverPort(hivemqWithClasspathExtension.getMqttPort()) + .buildBlocking(); + + client.connect(); + client.disconnect(); + // } + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java new file mode 100644 index 00000000000..46c24e8e51d --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java @@ -0,0 +1,62 @@ +package org.testcontainers.hivemq.docs; + +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.HiveMQContainer; +import org.testcontainers.hivemq.HiveMQExtension; +import org.testcontainers.hivemq.util.MyExtension; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +@Testcontainers +public class DemoFilesIT { + + // hivemqHome { + final HiveMQContainer hivemqFileInHome = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withFileInHomeFolder( + MountableFile.forHostPath("src/test/resources/additionalFile.txt"), + "/path/in/home/folder"); + // } + + // extensionHome { + @Container + final HiveMQContainer hivemqFileInExtensionHome = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withExtension(HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtension.class).build()) + .withFileInExtensionHomeFolder( + MountableFile.forHostPath("src/test/resources/additionalFile.txt"), + "extension-1", + "/path/in/extension/home"); + // } + + // withLicenses { + @Container + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withLicense(MountableFile.forHostPath("src/test/resources/myLicense.lic")) + .withLicense(MountableFile.forHostPath("src/test/resources/myExtensionLicense.elic")); + // } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void test() throws Exception { + + // mqtt5client { + final Mqtt5BlockingClient client = Mqtt5Client.builder() + .serverPort(hivemq.getMqttPort()) + .buildBlocking(); + + client.connect(); + client.disconnect(); + // } + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java new file mode 100644 index 00000000000..60683c8d612 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java @@ -0,0 +1,61 @@ +package org.testcontainers.hivemq.docs; + +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.HiveMQContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +@Testcontainers +public class DemoHiveMQContainerIT { + + // ceVersion { + @Container + final HiveMQContainer hivemqCe = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withLogLevel(Level.DEBUG); + // } + + // eeVersion { + @Container + final HiveMQContainer hivemqEe = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withLogLevel(Level.DEBUG); + // } + + // eeVersionWithControlCenter { + @Container + final HiveMQContainer hivemqEeWithControLCenter = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withLogLevel(Level.DEBUG) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withControlCenter(); + // } + + // specificVersion { + @Container + final HiveMQContainer hivemqSpecificVersion = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce:2021.3")); + // } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void test() throws Exception { + + // mqtt5client { + final Mqtt5BlockingClient client = Mqtt5Client.builder() + .serverPort(hivemqCe.getMqttPort()) + .buildBlocking(); + + client.connect(); + client.disconnect(); + // } + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java new file mode 100755 index 00000000000..e707859be77 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java @@ -0,0 +1,37 @@ +package org.testcontainers.hivemq.util; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import org.jetbrains.annotations.NotNull; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +@SuppressWarnings("CodeBlock2Expr") +public class MyExtension implements ExtensionMain { + + @Override + public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java new file mode 100755 index 00000000000..abc24585358 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java @@ -0,0 +1,26 @@ +package org.testcontainers.hivemq.util; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import org.jetbrains.annotations.NotNull; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; + +public class MyExtensionWithSubclasses implements ExtensionMain { + + @Override + public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(new PublishModifier()); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java new file mode 100755 index 00000000000..d33f29a9c10 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java @@ -0,0 +1,16 @@ +package org.testcontainers.hivemq.util; + +import org.jetbrains.annotations.NotNull; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundInput; +import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundOutput; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +public class PublishModifier implements PublishInboundInterceptor { + @Override + public void onInboundPublish(final @NotNull PublishInboundInput publishInboundInput, final @NotNull PublishInboundOutput publishInboundOutput) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java new file mode 100755 index 00000000000..b2712ef5a1d --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java @@ -0,0 +1,48 @@ +package org.testcontainers.hivemq.util; + +import com.hivemq.client.mqtt.MqttGlobalPublishFilter; +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class TestPublishModifiedUtil { + + public static void testPublishModified(final int mqttPort) throws InterruptedException, ExecutionException { + final CompletableFuture publishReceived = new CompletableFuture<>(); + + final Mqtt5BlockingClient publisher = Mqtt5Client.builder() + .serverPort(mqttPort) + .identifier("publisher") + .buildBlocking(); + publisher.connect(); + + final Mqtt5BlockingClient subscriber = Mqtt5Client.builder() + .serverPort(mqttPort) + .identifier("subscriber") + .buildBlocking(); + subscriber.connect(); + subscriber.subscribeWith().topicFilter("test/topic").send(); + subscriber.toAsync().publishes(MqttGlobalPublishFilter.ALL, publish -> { + if (Arrays.equals(publish.getPayloadAsBytes(), "modified".getBytes(StandardCharsets.UTF_8))) { + publishReceived.complete(null); + } else { + publishReceived.completeExceptionally(new IllegalArgumentException("unexpected payload: " + new String(publish.getPayloadAsBytes()))); + } + }); + + publisher.publishWith().topic("test/topic").payload("unmodified".getBytes(StandardCharsets.UTF_8)).send(); + + try { + publishReceived.get(); + } finally { + publisher.disconnect(); + subscriber.disconnect(); + } + } + + +} diff --git a/modules/hivemq/src/test/resources/additionalFile.txt b/modules/hivemq/src/test/resources/additionalFile.txt new file mode 100755 index 00000000000..e69de29bb2d diff --git a/modules/hivemq/src/test/resources/config.xml b/modules/hivemq/src/test/resources/config.xml new file mode 100755 index 00000000000..128015e2fee --- /dev/null +++ b/modules/hivemq/src/test/resources/config.xml @@ -0,0 +1,15 @@ + + + + + + 1883 + 0.0.0.0 + + + + + 0 + + + diff --git a/modules/hivemq/src/test/resources/inMemoryConfig.xml b/modules/hivemq/src/test/resources/inMemoryConfig.xml new file mode 100644 index 00000000000..33373359243 --- /dev/null +++ b/modules/hivemq/src/test/resources/inMemoryConfig.xml @@ -0,0 +1,6 @@ + + + + in-memory + + diff --git a/modules/hivemq/src/test/resources/logback-test.xml b/modules/hivemq/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..8a33fc398f0 --- /dev/null +++ b/modules/hivemq/src/test/resources/logback-test.xml @@ -0,0 +1,18 @@ + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + + + + + diff --git a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml new file mode 100755 index 00000000000..6ca9c899df4 --- /dev/null +++ b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml @@ -0,0 +1,8 @@ + + + modifier-extension + 1.0-SNAPSHOT + Modifier Extension + HiveMQ GmbH + 1000 + diff --git a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/modifier-extension-1.0-SNAPSHOT.jar b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/modifier-extension-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..18a7ea85f53dcf856d5280676386448b43d2d537 GIT binary patch literal 102179 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
= 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 z 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 + + modifier-extension + 1.0-SNAPSHOT + Modifier Extension + HiveMQ GmbH + 1000 + diff --git a/modules/hivemq/src/test/resources/modifier-extension/modifier-extension-1.0-SNAPSHOT.jar b/modules/hivemq/src/test/resources/modifier-extension/modifier-extension-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..18a7ea85f53dcf856d5280676386448b43d2d537 GIT binary patch literal 102179 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
= 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 z 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 Date: Thu, 17 Feb 2022 13:54:54 +0000 Subject: [PATCH 1744/4969] Bump spock-core from 2.0-groovy-3.0 to 2.1-groovy-3.0 in /modules/spock Bumps spock-core from 2.0-groovy-3.0 to 2.1-groovy-3.0. --- updated-dependencies: - dependency-name: org.spockframework:spock-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 26158b6db57..e745bc23ed6 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -6,7 +6,7 @@ description = "Testcontainers :: Spock-Extension" dependencies { api project(':testcontainers') - api 'org.spockframework:spock-core:2.0-groovy-3.0' + api 'org.spockframework:spock-core:2.1-groovy-3.0' testImplementation project(':selenium') testImplementation project(':mysql') From 40f3e3f0125e1307a6f0af844e36f4a8c783b55a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:55 +0000 Subject: [PATCH 1745/4969] Bump postgresql from 42.3.1 to 42.3.3 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.1 to 42.3.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.1...REL42.3.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index a8a6495bfc1..754d5dde289 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.3.1' + testImplementation 'org.postgresql:postgresql:42.3.3' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' From b5575455cba038b579289c18d966921835e90676 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:55 +0000 Subject: [PATCH 1746/4969] Bump postgresql from 42.3.2 to 42.3.3 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.2 to 42.3.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.2...REL42.3.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index 71011c6534b..4d15e4df1c1 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.3.2' + testImplementation 'org.postgresql:postgresql:42.3.3' } From 08d1c9c180f7fd38d0c0e3d67dd90ec36c10f81a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:55 +0000 Subject: [PATCH 1747/4969] Bump postgresql from 42.3.2 to 42.3.3 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.2 to 42.3.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.2...REL42.3.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index ba0083a25a7..749bf72690d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' - testRuntimeOnly 'org.postgresql:postgresql:42.3.2' + testRuntimeOnly 'org.postgresql:postgresql:42.3.3' testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' } From bb76a74e71b5a102cc1082b654b6a27a23872a87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:55 +0000 Subject: [PATCH 1748/4969] Bump hivemq-extension-sdk from 4.7.3 to 4.7.4 in /modules/hivemq Bumps [hivemq-extension-sdk](https://github.com/hivemq/hivemq-extension-sdk) from 4.7.3 to 4.7.4. - [Release notes](https://github.com/hivemq/hivemq-extension-sdk/releases) - [Commits](https://github.com/hivemq/hivemq-extension-sdk/compare/4.7.3...4.7.4) --- updated-dependencies: - dependency-name: com.hivemq:hivemq-extension-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 779ac2ec9d8..f0c3aaa2e69 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -13,7 +13,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") testImplementation(project(":junit-jupiter")) - testImplementation("com.hivemq:hivemq-extension-sdk:4.7.3") + testImplementation("com.hivemq:hivemq-extension-sdk:4.7.4") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.10") From 80e64855928f4a70b95fbfbc68377700aedafe53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:55 +0000 Subject: [PATCH 1749/4969] Bump mongodb-driver-sync from 4.4.1 to 4.5.0 in /modules/mongodb Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.4.1 to 4.5.0. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.4.1...r4.5.0) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/mongodb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index 95919c931d4..73dba45dbbf 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: MongoDB" dependencies { api project(':testcontainers') - testImplementation("org.mongodb:mongodb-driver-sync:4.4.1") + testImplementation("org.mongodb:mongodb-driver-sync:4.5.0") } From 30b09ba593698c1a8934bf0b6068a29839efebdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:56 +0000 Subject: [PATCH 1750/4969] Bump rest-assured from 4.4.0 to 4.5.1 in /modules/vault Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 4.4.0 to 4.5.1. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-4.4.0...rest-assured-4.5.1) --- updated-dependencies: - dependency-name: io.rest-assured:rest-assured dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 8aa0a2d689e..ce000685a10 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.bettercloud:vault-java-driver:5.1.0' - testImplementation 'io.rest-assured:rest-assured:4.4.0' + testImplementation 'io.rest-assured:rest-assured:4.5.1' testImplementation 'org.assertj:assertj-core:3.22.0' } From 232771603089399249f4436cbac505feb3232cb7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:56 +0000 Subject: [PATCH 1751/4969] Bump reactor-core from 3.4.14 to 3.4.15 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.14 to 3.4.15. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.14...v3.4.15) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 74ab1c9f7f0..2fa066c21b3 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.14' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.15' testFixturesImplementation 'org.assertj:assertj-core:3.14.0' } From ca2dbdd74ec0f61895c7af69c7af1f2731db66fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:54:57 +0000 Subject: [PATCH 1752/4969] Bump amqp-client from 5.14.1 to 5.14.2 in /modules/rabbitmq Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.14.1 to 5.14.2. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.14.1...v5.14.2) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/rabbitmq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 9b680b12968..967b9eb4ed9 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: RabbitMQ" dependencies { api project(":testcontainers") - testImplementation 'com.rabbitmq:amqp-client:5.14.1' + testImplementation 'com.rabbitmq:amqp-client:5.14.2' testImplementation 'org.assertj:assertj-core:3.22.0' compileOnly 'org.jetbrains:annotations:23.0.0' } From cd9d2b46dde52a3cf4fe42fa54ebe487dc08f124 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:55:00 +0000 Subject: [PATCH 1753/4969] Bump azure-cosmos from 4.24.0 to 4.26.0 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.24.0 to 4.26.0. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.24.0...azure-cosmos_4.26.0) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 1dbad6a6698..7e5bc336526 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':testcontainers') testImplementation 'org.assertj:assertj-core:3.22.0' - testImplementation 'com.azure:azure-cosmos:4.24.0' + testImplementation 'com.azure:azure-cosmos:4.26.0' } From 9202c67fe321c9e6ca96d9eb4cc86c157e2e1ff5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:55:01 +0000 Subject: [PATCH 1754/4969] Bump amqp-client from 5.14.1 to 5.14.2 in /core Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.14.1 to 5.14.2. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.14.1...v5.14.2) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 0d704cecd81..1b54ca4ff1b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -90,7 +90,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:4.0.1' - testImplementation 'com.rabbitmq:amqp-client:5.14.1' + testImplementation 'com.rabbitmq:amqp-client:5.14.2' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' testImplementation ('org.mockito:mockito-core:4.3.1') { From cc3e076f546c53629e62f0c3b266d705d79c4881 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:55:04 +0000 Subject: [PATCH 1755/4969] Bump release-drafter/release-drafter from 5.17.6 to 5.18.1 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.17.6 to 5.18.1. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/436492609a0c75979acf131d57f61b5321571950...2f7ebf8ab5ef7f9835ee4b0b1eebaa2a14ca1669) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index aec34acb8ff..05485ac57fa 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -12,6 +12,6 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@436492609a0c75979acf131d57f61b5321571950 # v5.15.0 + - uses: release-drafter/release-drafter@2f7ebf8ab5ef7f9835ee4b0b1eebaa2a14ca1669 # v5.15.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From a78133cc8dbe6dcd839d4d264d3d5dae647edf22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:55:08 +0000 Subject: [PATCH 1756/4969] Bump postgresql from 42.3.2 to 42.3.3 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.2 to 42.3.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.2...REL42.3.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 37fc1b71226..1cb3a0285f2 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'org.json:json:20211205' - testImplementation 'org.postgresql:postgresql:42.3.2' + testImplementation 'org.postgresql:postgresql:42.3.3' testImplementation 'ch.qos.logback:logback-classic:1.2.10' testImplementation 'org.testcontainers:postgresql' } From 5e016c9432c71f263493d144214f5fb047268d84 Mon Sep 17 00:00:00 2001 From: Yannick Weber Date: Fri, 18 Feb 2022 13:30:23 +0100 Subject: [PATCH 1757/4969] Use WaitAllStrategy for HiveMQ (#5093) Also, remove MultiLogMessageWaitStrategy. --- .../strategy/MultiLogMessageWaitStrategy.java | 59 ------------------- .../hivemq/HiveMQContainer.java | 14 ++--- 2 files changed, 5 insertions(+), 68 deletions(-) delete mode 100644 core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java deleted file mode 100644 index 0d342f3050f..00000000000 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/MultiLogMessageWaitStrategy.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.testcontainers.containers.wait.strategy; - -import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.ContainerLaunchException; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.WaitingConsumer; -import org.testcontainers.utility.LogUtils; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Predicate; - -/** - * This is a wait strategy to wait for multiple log patterns. - * The wait strategy will continue when every log pattern is matched at least once. - */ -public class MultiLogMessageWaitStrategy extends AbstractWaitStrategy { - - private final ConcurrentHashMap regexes = new ConcurrentHashMap<>(); - - @Override - protected void waitUntilReady() { - WaitingConsumer waitingConsumer = new WaitingConsumer(); - LogUtils.followOutput(DockerClientFactory.instance().client(), waitStrategyTarget.getContainerId(), waitingConsumer); - - Predicate waitPredicate = outputFrame -> { - if (regexes.isEmpty()) { - return true; - } - regexes.entrySet().forEach(regexHasMatched -> { - final boolean matched = outputFrame.getUtf8String().matches("(?s)" + regexHasMatched.getKey()); - if (matched) { - regexHasMatched.setValue(true); - } - }); - return regexes.values().stream().reduce(Boolean::logicalAnd).orElse(true); - }; - - try { - waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, 1); - } catch (TimeoutException e) { - throw new ContainerLaunchException("Timed out waiting for log output matching '" + regexes + "'"); - } - } - - public MultiLogMessageWaitStrategy withRegEx(final String regEx) { - regexes.put(regEx, false); - return this; - } - - public MultiLogMessageWaitStrategy reset() { - for (final Map.Entry stringBooleanEntry : regexes.entrySet()) { - stringBooleanEntry.setValue(false); - } - return this; - } -} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 37f9a9259d1..342903e24af 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -8,7 +8,8 @@ import org.slf4j.event.Level; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.MultiLogMessageWaitStrategy; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; @@ -48,7 +49,7 @@ public class HiveMQContainer extends GenericContainer { private final @NotNull Set prepackagedExtensionsToRemove = new HashSet<>(); private boolean removeAllPrepackagedExtensions = false; - private final @NotNull MultiLogMessageWaitStrategy waitStrategy = new MultiLogMessageWaitStrategy(); + private final @NotNull WaitAllStrategy waitStrategy = new WaitAllStrategy(); public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { super(dockerImageName); @@ -57,7 +58,7 @@ public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { addExposedPort(MQTT_PORT); - waitStrategy.withRegEx("(.*)Started HiveMQ in(.*)"); + waitStrategy.withStrategy(new LogMessageWaitStrategy().withRegEx("(.*)Started HiveMQ in(.*)")); waitingFor(waitStrategy); withLogConsumer(outputFrame -> { @@ -121,7 +122,7 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai */ public @NotNull HiveMQContainer waitForExtension(final @NotNull String extensionName) { final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) started successfully(.*)"; - waitStrategy.withRegEx(regEX); + waitStrategy.withStrategy(new LogMessageWaitStrategy().withRegEx(regEX)); return self(); } @@ -562,11 +563,6 @@ public int getMqttPort() { return this.getMappedPort(MQTT_PORT); } - @Override - protected void containerIsStopping(final @NotNull InspectContainerResponse containerInfo) { - waitStrategy.reset(); - } - private @NotNull MountableFile cloneWithFileMode(final @NotNull MountableFile mountableFile) { return MountableFile.forHostPath(mountableFile.getResolvedPath(), HiveMQContainer.MODE); } From 3ff0bb229b204c0839c256b44d15430080b55dc0 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 21 Feb 2022 07:30:16 -0500 Subject: [PATCH 1758/4969] Fix tests on Windows (#5096) * Fix tests on Windows * Fix race condition in `StartupCheckStrategyTest` --- azure-pipelines.yml | 7 +- .../DockerRegistryContainer.java | 68 +++++++++++++++++++ .../images/ImagePullPolicyTest.java | 7 +- .../utility/AuthenticatedImagePullTest.java | 40 ++--------- .../StartupCheckStrategyTest.java | 4 +- 5 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/DockerRegistryContainer.java diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0f01bb7bcd2..9279b3233f8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,7 +1,7 @@ jobs: -- job: azure_pipeline_tests - timeoutInMinutes: 120 +- job: core_tests + timeoutInMinutes: 60 steps: # Run all core tests when running the Windows CI tests @@ -19,6 +19,9 @@ jobs: publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' +- job: other_tests + timeoutInMinutes: 120 + steps: # Run all non-core tests when running the Windows CI tests - task: Gradle@2 condition: eq(variables['Agent.OS'], 'Windows_NT') diff --git a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java new file mode 100644 index 00000000000..641b1553d72 --- /dev/null +++ b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java @@ -0,0 +1,68 @@ +package org.testcontainers; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import lombok.Getter; +import lombok.NonNull; +import lombok.SneakyThrows; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.FrameConsumerResultCallback; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.WaitingConsumer; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DockerRegistryContainer extends GenericContainer { + + @Getter + String endpoint; + + public DockerRegistryContainer() { + super(TestImages.DOCKER_REGISTRY_IMAGE); + } + + public DockerRegistryContainer(@NonNull Future image) { + super(image); + } + + @Override + protected void configure() { + super.configure(); + withEnv("REGISTRY_HTTP_ADDR", "127.0.0.1:0"); + withCreateContainerCmdModifier(cmd -> { + cmd.getHostConfig().withNetworkMode("host"); + }); + } + + @Override + @SneakyThrows + protected void containerIsStarting(InspectContainerResponse containerInfo) { + AtomicInteger port = new AtomicInteger(-1); + try (FrameConsumerResultCallback resultCallback = new FrameConsumerResultCallback()) { + WaitingConsumer waitingConsumer = new WaitingConsumer(); + resultCallback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer); + + dockerClient.logContainerCmd(containerInfo.getId()) + .withStdErr(true) + .withFollowStream(true) + .exec(resultCallback); + + Pattern pattern = Pattern.compile(".*listening on .*:(\\d+).*", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + waitingConsumer.waitUntil(it -> { + String s = it.getUtf8String(); + Matcher matcher = pattern.matcher(s); + if (matcher.matches()) { + port.set(Integer.parseInt(matcher.group(1))); + return true; + } else { + return false; + } + }, 10, TimeUnit.SECONDS); + } + + endpoint = getHost() + ":" + port.get(); + } +} diff --git a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java index 9b22f5e6166..85c2e785652 100644 --- a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java @@ -12,6 +12,7 @@ import org.mockito.Mockito; import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory; +import org.testcontainers.DockerRegistryContainer; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; @@ -22,19 +23,17 @@ import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; -import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; public class ImagePullPolicyTest { @ClassRule - public static GenericContainer registry = new GenericContainer<>(DOCKER_REGISTRY_IMAGE) - .withExposedPorts(5000); + public static DockerRegistryContainer registry = new DockerRegistryContainer(); private static DockerImageName imageName; @BeforeClass public static void beforeClass() throws Exception { - String testRegistryAddress = registry.getHost() + ":" + registry.getFirstMappedPort(); + String testRegistryAddress = registry.getEndpoint(); String testImageName = testRegistryAddress + "/image-pull-policy-test"; String tag = UUID.randomUUID().toString(); imageName = DockerImageName.parse(testImageName).withTag(tag); diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 3243d219cc0..c57c1d7c0b6 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -13,12 +13,10 @@ import org.junit.Test; import org.mockito.Mockito; import org.testcontainers.DockerClientFactory; +import org.testcontainers.DockerRegistryContainer; import org.testcontainers.containers.ContainerState; import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.FrameConsumerResultCallback; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.WaitingConsumer; import org.testcontainers.images.builder.ImageFromDockerfile; import java.io.IOException; @@ -26,9 +24,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -51,18 +46,14 @@ public class AuthenticatedImagePullTest { * Containerised docker image registry, with simple hardcoded credentials */ @ClassRule - public static GenericContainer authenticatedRegistry = new GenericContainer<>(new ImageFromDockerfile() + public static DockerRegistryContainer authenticatedRegistry = new DockerRegistryContainer(new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder.from(DOCKER_REGISTRY_IMAGE.asCanonicalNameString()) .run("htpasswd -Bbn testuser notasecret > /htpasswd") .env("REGISTRY_AUTH", "htpasswd") .env("REGISTRY_AUTH_HTPASSWD_PATH", "/htpasswd") .env("REGISTRY_AUTH_HTPASSWD_REALM", "Test"); - })) - .withEnv("REGISTRY_HTTP_ADDR", "127.0.0.1:0") - .withCreateContainerCmdModifier(cmd -> { - cmd.getHostConfig().withNetworkMode("host"); - }); + })); private static RegistryAuthLocator originalAuthLocatorSingleton; private static DockerClient client; @@ -75,30 +66,7 @@ public static void setUp() throws Exception { originalAuthLocatorSingleton = RegistryAuthLocator.instance(); client = DockerClientFactory.instance().client(); - AtomicInteger port = new AtomicInteger(-1); - try (FrameConsumerResultCallback resultCallback = new FrameConsumerResultCallback()) { - WaitingConsumer waitingConsumer = new WaitingConsumer(); - resultCallback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer); - - client.logContainerCmd(authenticatedRegistry.getContainerId()) - .withStdErr(true) - .withFollowStream(true) - .exec(resultCallback); - - Pattern pattern = Pattern.compile(".*listening on .*:(\\d+).*", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); - waitingConsumer.waitUntil(it -> { - String s = it.getUtf8String(); - Matcher matcher = pattern.matcher(s); - if (matcher.matches()) { - port.set(Integer.parseInt(matcher.group(1))); - return true; - } else { - return false; - } - }, 10, TimeUnit.SECONDS); - } - - String testRegistryAddress = authenticatedRegistry.getHost() + ":" + port.get(); + String testRegistryAddress = authenticatedRegistry.getEndpoint(); testImageName = testRegistryAddress + "/alpine"; final DockerImageName expectedName = DockerImageName.parse(testImageName); diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java index 0e72efb5723..b60225010a1 100644 --- a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java +++ b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java @@ -84,9 +84,9 @@ public static class MinimumDurationStrategyTest { @SneakyThrows @Test public void testCommandIsExecuted() { - waitForHello(bboxWithMinimumDuration); - assertThat(bboxWithMinimumDuration.isRunning()).isTrue(); + + waitForHello(bboxWithMinimumDuration); } } } From 257c89bea35901e4318704e883d27c08437d8911 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 21 Feb 2022 08:39:53 -0500 Subject: [PATCH 1759/4969] Start Ryuk lazily when in the reusable mode (#4938) * Lazy Ryuk * Add `ResourceReaper#init` --- core/build.gradle | 7 +- .../testcontainers/DockerClientFactory.java | 56 +++---- .../containers/GenericContainer.java | 5 +- .../testcontainers/containers/Network.java | 2 + .../images/builder/ImageFromDockerfile.java | 2 + .../utility/JVMHookResourceReaper.java | 57 +++++++ .../utility/ResourceReaper.java | 156 +++++++----------- .../utility/RyukResourceReaper.java | 43 ++++- .../DockerClientFactoryTest.java | 20 +-- 9 files changed, 201 insertions(+), 147 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/utility/JVMHookResourceReaper.java diff --git a/core/build.gradle b/core/build.gradle index 0d704cecd81..7b014d1ad24 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -40,7 +40,12 @@ tasks.japicmp { classExcludes = [] - methodExcludes = [] + methodExcludes = [ + "org.testcontainers.utility.ResourceReaper#start(java.lang.String,com.github.dockerjava.api.DockerClient)", + "org.testcontainers.utility.ResourceReaper#start(com.github.dockerjava.api.DockerClient)", + "org.testcontainers.utility.ResourceReaper#registerNetworkForCleanup(java.lang.String)", + "org.testcontainers.utility.ResourceReaper#removeNetworks(java.lang.String)", + ] fieldExcludes = [] } diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 1ad7a0bec7e..d0a4e4a4fb3 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -31,6 +31,7 @@ import org.testcontainers.utility.ImageNameSubstitutor; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.ResourceReaper; +import org.testcontainers.utility.RyukResourceReaper; import org.testcontainers.utility.TestcontainersConfiguration; import java.io.ByteArrayOutputStream; @@ -38,6 +39,7 @@ import java.io.InputStream; import java.net.URI; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -61,8 +63,7 @@ public class DockerClientFactory { public static final String SESSION_ID = UUID.randomUUID().toString(); public static final Map DEFAULT_LABELS = ImmutableMap.of( - TESTCONTAINERS_LABEL, "true", - TESTCONTAINERS_SESSION_ID_LABEL, SESSION_ID + TESTCONTAINERS_LABEL, "true" ); private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14"); @@ -73,7 +74,7 @@ public class DockerClientFactory { DockerClientProviderStrategy strategy; @VisibleForTesting - DockerClient dockerClient; + DockerClient client; @VisibleForTesting RuntimeException cachedClientFailure; @@ -174,21 +175,20 @@ public String getRemoteDockerUnixSocketPath() { */ @Synchronized public DockerClient client() { - - if (dockerClient != null) { - return dockerClient; - } - // fail-fast if checks have failed previously if (cachedClientFailure != null) { log.debug("There is a cached checks failure - throwing", cachedClientFailure); throw cachedClientFailure; } + if (client != null) { + return client; + } + final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); - final DockerClient client = new DockerClientDelegate() { + client = new DockerClientDelegate() { @Getter final DockerClient dockerClient = strategy.getDockerClient(); @@ -209,25 +209,14 @@ public void close() { " Operating System: " + dockerInfo.getOperatingSystem() + "\n" + " Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB"); - final String ryukContainerId; - - boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); - if (useRyuk) { - log.debug("Ryuk is enabled"); - try { - //noinspection deprecation - ryukContainerId = ResourceReaper.start(client); - } catch (RuntimeException e) { - cachedClientFailure = e; - throw e; - } - log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit"); - } else { - log.debug("Ryuk is disabled"); - ryukContainerId = null; - // best-efforts cleanup at JVM shutdown, without using the Ryuk container + final ResourceReaper resourceReaper; + try { + resourceReaper = ResourceReaper.instance(); //noinspection deprecation - ResourceReaper.instance().setHook(); + resourceReaper.init(); + } catch (RuntimeException e) { + cachedClientFailure = e; + throw e; } boolean checksEnabled = !TestcontainersConfiguration.getInstance().isDisableChecks(); @@ -237,6 +226,12 @@ public void close() { try { log.info("Checking the system..."); checkDockerVersion(version.getVersion()); + + //noinspection deprecation + String ryukContainerId = resourceReaper instanceof RyukResourceReaper + ? ((RyukResourceReaper) resourceReaper).getContainerId() + : null; + if (ryukContainerId != null) { checkDiskSpace(client, ryukContainerId); } else { @@ -261,8 +256,7 @@ public void close() { log.debug("Checks are disabled"); } - dockerClient = client; - return dockerClient; + return client; } private void checkDockerVersion(String dockerVersion) { @@ -378,8 +372,10 @@ private T runInsideDocker(DockerClient client, Consumer final String tinyImage = ImageNameSubstitutor.instance().apply(TINY_IMAGE).asCanonicalNameString(); checkAndPullImage(client, tinyImage); + HashMap labels = new HashMap<>(DEFAULT_LABELS); + labels.putAll(ResourceReaper.instance().getLabels()); CreateContainerCmd createContainerCmd = client.createContainerCmd(tinyImage) - .withLabels(DEFAULT_LABELS); + .withLabels(labels); createContainerCmdConsumer.accept(createContainerCmd); String id = createContainerCmd.exec().getId(); diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 3851cf42fca..aca543ef7ec 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -364,7 +364,7 @@ private void tryStart(Instant startedAt) { CreateContainerCmd createCommand = dockerClient.createContainerCmd(dockerImageName); applyConfiguration(createCommand); - createCommand.getLabels().put(DockerClientFactory.TESTCONTAINERS_LABEL, "true"); + createCommand.getLabels().putAll(DockerClientFactory.DEFAULT_LABELS); boolean reused = false; final boolean reusable; @@ -406,7 +406,8 @@ private void tryStart(Instant startedAt) { } if (!reusable) { - createCommand.getLabels().put(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL, DockerClientFactory.SESSION_ID); + //noinspection deprecation + createCommand.getLabels().putAll(ResourceReaper.instance().getLabels()); } if (!reused) { diff --git a/core/src/main/java/org/testcontainers/containers/Network.java b/core/src/main/java/org/testcontainers/containers/Network.java index 2fda5ad1a8d..046133815b6 100644 --- a/core/src/main/java/org/testcontainers/containers/Network.java +++ b/core/src/main/java/org/testcontainers/containers/Network.java @@ -87,6 +87,8 @@ private String create() { Map labels = createNetworkCmd.getLabels(); labels = new HashMap<>(labels != null ? labels : Collections.emptyMap()); labels.putAll(DockerClientFactory.DEFAULT_LABELS); + //noinspection deprecation + labels.putAll(ResourceReaper.instance().getLabels()); createNetworkCmd.withLabels(labels); return createNetworkCmd.exec().getId(); diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 05bb6911c3e..a434dee2b41 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -112,6 +112,8 @@ public void onNext(BuildResponseItem item) { labels.putAll(buildImageCmd.getLabels()); } labels.putAll(DockerClientFactory.DEFAULT_LABELS); + //noinspection deprecation + labels.putAll(ResourceReaper.instance().getLabels()); buildImageCmd.withLabels(labels); prePullDependencyImages(dependencyImageNames); diff --git a/core/src/main/java/org/testcontainers/utility/JVMHookResourceReaper.java b/core/src/main/java/org/testcontainers/utility/JVMHookResourceReaper.java new file mode 100644 index 00000000000..173cf28f97c --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/JVMHookResourceReaper.java @@ -0,0 +1,57 @@ +package org.testcontainers.utility; + +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.PruneType; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * A {@link ResourceReaper} implementation that uses {@link Runtime#addShutdownHook(Thread)} + * to cleanup containers. + */ +class JVMHookResourceReaper extends ResourceReaper { + + @Override + public void init() { + setHook(); + } + + @Override + public synchronized void performCleanup() { + super.performCleanup(); + synchronized (DEATH_NOTE) { + DEATH_NOTE.forEach(filters -> prune(PruneType.CONTAINERS, filters)); + DEATH_NOTE.forEach(filters -> prune(PruneType.NETWORKS, filters)); + DEATH_NOTE.forEach(filters -> prune(PruneType.VOLUMES, filters)); + DEATH_NOTE.forEach(filters -> prune(PruneType.IMAGES, filters)); + } + } + + private void prune(PruneType pruneType, List> filters) { + String[] labels = filters.stream() + .filter(it -> "label".equals(it.getKey())) + .map(Map.Entry::getValue) + .toArray(String[]::new); + switch (pruneType) { + // Docker only prunes stopped containers, so we have to do it manually + case CONTAINERS: + List containers = dockerClient.listContainersCmd() + .withFilter("label", Arrays.asList(labels)) + .withShowAll(true) + .exec(); + + containers.parallelStream().forEach(container -> { + dockerClient.removeContainerCmd(container.getId()) + .withForce(true) + .withRemoveVolumes(true) + .exec(); + }); + break; + default: + dockerClient.pruneCmd(pruneType).withLabelFilter(labels).exec(); + break; + } + } +} diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 69c849b6c82..44f9456ce4c 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -3,9 +3,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; -import com.github.dockerjava.api.model.Container; import com.github.dockerjava.api.model.Network; -import com.github.dockerjava.api.model.PruneType; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; import com.google.common.collect.Sets; @@ -24,62 +22,62 @@ import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Component that responsible for container removal and automatic cleanup of dead containers at JVM shutdown. */ @Slf4j -public final class ResourceReaper { +public class ResourceReaper { private static final Logger LOGGER = LoggerFactory.getLogger(ResourceReaper.class); + private static final Map MARKER_LABELS = Collections.singletonMap( + DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL, + DockerClientFactory.SESSION_ID + ); + static final List>> DEATH_NOTE = new ArrayList<>( Arrays.asList( - DockerClientFactory.DEFAULT_LABELS.entrySet().stream() + Stream + .concat( + DockerClientFactory.DEFAULT_LABELS.entrySet().stream(), + MARKER_LABELS.entrySet().stream() + ) .>map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())) .collect(Collectors.toList()) ) ); private static ResourceReaper instance; - private static AtomicBoolean ryukStarted = new AtomicBoolean(false); - private final DockerClient dockerClient = DockerClientFactory.lazyClient(); + final DockerClient dockerClient = DockerClientFactory.lazyClient(); private Map registeredContainers = new ConcurrentHashMap<>(); private Set registeredNetworks = Sets.newConcurrentHashSet(); private Set registeredImages = Sets.newConcurrentHashSet(); private AtomicBoolean hookIsSet = new AtomicBoolean(false); - /** - * - * @deprecated internal API + * Internal constructor to avoid custom implementations */ - @Deprecated - public static String start(String hostIpAddress, DockerClient client) { - return start(client); - } - - /** - * - * @deprecated internal API - */ - @Deprecated - public static String start(DockerClient client) { - RyukResourceReaper ryuk = new RyukResourceReaper(client); - String containerId = ryuk.getContainerId(); - ryukStarted.set(true); - return containerId; + ResourceReaper() { } public synchronized static ResourceReaper instance() { if (instance == null) { - instance = new ResourceReaper(); + boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); + if (useRyuk) { + //noinspection deprecation + instance = new RyukResourceReaper(); + } else { + instance = new JVMHookResourceReaper(); + } } return instance; @@ -87,8 +85,10 @@ public synchronized static ResourceReaper instance() { /** * Perform a cleanup. + * @deprecated no longer supported API, use {@link DockerClient} directly */ - public synchronized void performCleanup() { + @Deprecated + public void performCleanup() { registeredContainers.forEach(this::removeContainer); registeredNetworks.forEach(this::removeNetwork); registeredImages.forEach(this::removeImage); @@ -126,7 +126,9 @@ public void registerLabelsFilterForCleanup(Map labels) { * * @param containerId the ID of the container * @param imageName the image name of the container (used for logging) + * @deprecated no longer supported API */ + @Deprecated public void registerContainerForCleanup(String containerId, String imageName) { setHook(); registeredContainers.put(containerId, imageName); @@ -136,7 +138,9 @@ public void registerContainerForCleanup(String containerId, String imageName) { * Stop a potentially running container and remove it, including associated volumes. * * @param containerId the ID of the container + * @deprecated use {@link DockerClient} directly */ + @Deprecated public void stopAndRemoveContainer(String containerId) { removeContainer(containerId, registeredContainers.get(containerId)); @@ -148,7 +152,9 @@ public void stopAndRemoveContainer(String containerId) { * * @param containerId the ID of the container * @param imageName the image name of the container (used for logging) + * @deprecated use {@link DockerClient} directly */ + @Deprecated public void stopAndRemoveContainer(String containerId, String imageName) { removeContainer(containerId, imageName); @@ -204,46 +210,24 @@ private void removeContainer(String containerId, String imageName) { * Register a network to be cleaned up at JVM shutdown. * * @param id the ID of the network + * @deprecated no longer supported API */ + @Deprecated public void registerNetworkIdForCleanup(String id) { setHook(); registeredNetworks.add(id); } - /** - * @param networkName the name of the network - * @deprecated see {@link ResourceReaper#registerNetworkIdForCleanup(String)} - */ - @Deprecated - public void registerNetworkForCleanup(String networkName) { - try { - // Try to find the network by name, so that we can register its ID for later deletion - dockerClient.listNetworksCmd() - .withNameFilter(networkName) - .exec() - .forEach(network -> registerNetworkIdForCleanup(network.getId())); - } catch (Exception e) { - LOGGER.trace("Error encountered when looking up network (name: {})", networkName); - } - } - /** * Removes a network by ID. * @param id + * @deprecated use {@link DockerClient} directly */ + @Deprecated public void removeNetworkById(String id) { removeNetwork(id); } - /** - * Removes a network by ID. - * @param identifier - * @deprecated see {@link ResourceReaper#removeNetworkById(String)} - */ - @Deprecated - public void removeNetworks(String identifier) { - removeNetworkById(identifier); - } private void removeNetwork(String id) { try { @@ -273,14 +257,26 @@ private void removeNetwork(String id) { } } + /** + * @deprecated no longer supported API + */ + @Deprecated public void unregisterNetwork(String identifier) { registeredNetworks.remove(identifier); } + /** + * @deprecated no longer supported API + */ + @Deprecated public void unregisterContainer(String identifier) { registeredContainers.remove(identifier); } + /** + * @deprecated no longer supported API + */ + @Deprecated public void registerImageForCleanup(String dockerImageName) { setHook(); registeredImages.add(dockerImageName); @@ -295,53 +291,27 @@ private void removeImage(String dockerImageName) { } } - private void prune(PruneType pruneType, List> filters) { - String[] labels = filters.stream() - .filter(it -> "label".equals(it.getKey())) - .map(Map.Entry::getValue) - .toArray(String[]::new); - switch (pruneType) { - // Docker only prunes stopped containers, so we have to do it manually - case CONTAINERS: - List containers = dockerClient.listContainersCmd() - .withFilter("label", Arrays.asList(labels)) - .withShowAll(true) - .exec(); - - containers.parallelStream().forEach(container -> { - removeContainer(container.getId(), container.getImage()); - }); - break; - default: - dockerClient.pruneCmd(pruneType).withLabelFilter(labels).exec(); - break; + void setHook() { + if (hookIsSet.compareAndSet(false, true)) { + // If the JVM stops without containers being stopped, try and stop the container. + Runtime.getRuntime().addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, this::performCleanup)); } } /** - * @deprecated internal API, not intended for public usage + * + * @deprecated internal API */ @Deprecated - public void setHook() { - if (hookIsSet.compareAndSet(false, true)) { - // If the JVM stops without containers being stopped, try and stop the container. - Runtime.getRuntime().addShutdownHook( - new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, - () -> { - performCleanup(); - - if (!ryukStarted.get()) { - synchronized (DEATH_NOTE) { - DEATH_NOTE.forEach(filters -> prune(PruneType.CONTAINERS, filters)); - DEATH_NOTE.forEach(filters -> prune(PruneType.NETWORKS, filters)); - DEATH_NOTE.forEach(filters -> prune(PruneType.VOLUMES, filters)); - DEATH_NOTE.forEach(filters -> prune(PruneType.IMAGES, filters)); - } - } - } - ) - ); - } + public Map getLabels() { + return MARKER_LABELS; + } + + /** + * @deprecated internal API + */ + @Deprecated + public void init() { } static class FilterRegistry { diff --git a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java index e8aed92fa9d..743b33856cf 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java @@ -29,13 +29,21 @@ import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.awaitility.Awaitility.await; +/** + * Ryuk-based {@link ResourceReaper} implementation. + * + * @see
moby-ryuk + * @deprecated internal API + */ +@Deprecated @Slf4j -class RyukResourceReaper { +public class RyukResourceReaper extends ResourceReaper { private static final RateLimiter RYUK_ACK_RATE_LIMITER = RateLimiterBuilder .newBuilder() @@ -43,11 +51,40 @@ class RyukResourceReaper { .withConstantThroughput() .build(); + private final AtomicBoolean started = new AtomicBoolean(false); + @Getter - private final String containerId; + private String containerId = null; + + @Override + public void init() { + if (!TestcontainersConfiguration.getInstance().environmentSupportsReuse()) { + log.debug("Ryuk is enabled"); + maybeStart(); + log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit"); + } else { + log.debug("Ryuk is enabled but will be started on demand"); + } + } + + @Override + public void registerLabelsFilterForCleanup(Map labels) { + maybeStart(); + super.registerLabelsFilterForCleanup(labels); + } + + @Override + public Map getLabels() { + maybeStart(); + return super.getLabels(); + } @SneakyThrows(InterruptedException.class) - RyukResourceReaper(DockerClient client) { + private synchronized void maybeStart() { + if (!started.compareAndSet(false, true)) { + return; + } + DockerClient client = DockerClientFactory.lazyClient(); String ryukImage = ImageNameSubstitutor.instance() .apply(DockerImageName.parse("testcontainers/ryuk:0.3.3")) .asCanonicalNameString(); diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index d484cc92eaf..16d25b2f625 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -4,17 +4,13 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.testcontainers.TestImages.TINY_IMAGE; -import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.NotFoundException; import org.junit.Rule; import org.junit.Test; -import org.mockito.Mockito; import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory.DiskSpaceUsage; import org.testcontainers.dockerclient.LogToStringContainerCallback; import org.testcontainers.utility.MockTestcontainersConfigurationRule; -import org.testcontainers.utility.TestcontainersConfiguration; /** * Test for {@link DockerClientFactory}. @@ -65,27 +61,15 @@ public void dockerHostIpAddress() { @Test public void failedChecksFailFast() { - Mockito.doReturn(false).when(TestcontainersConfiguration.getInstance()).isDisableChecks(); - - // Make sure that Ryuk is started - assertThat(DockerClientFactory.instance().client()).isNotNull(); - - DockerClientFactory instance = new DockerClientFactory(); - DockerClient dockerClient = instance.dockerClient; + DockerClientFactory instance = DockerClientFactory.instance(); + assertThat(instance.client()).isNotNull(); assertThat(instance.cachedClientFailure).isNull(); try { - // Remove cached client to force the initialization logic - instance.dockerClient = null; - - // Ryuk should fail to start twice due to the name conflict (equal to the session id) - assertThatThrownBy(instance::client).isInstanceOf(DockerException.class); - RuntimeException failure = new IllegalStateException("Boom!"); instance.cachedClientFailure = failure; // Fail fast assertThatThrownBy(instance::client).isEqualTo(failure); } finally { - instance.dockerClient = dockerClient; instance.cachedClientFailure = null; } } From 55a131545b758c04afa1bb0af4319d505ac3abde Mon Sep 17 00:00:00 2001 From: Yannick Weber Date: Tue, 22 Feb 2022 13:15:20 +0100 Subject: [PATCH 1760/4969] Every HiveMQ IT now uses `getHost()` (#5106) Ensures better portability across different Docker environments. --- .../hivemq/ContainerWithCustomConfigIT.java | 1 + .../ContainerWithExtensionFromDirectoryIT.java | 4 ++-- .../hivemq/ContainerWithExtensionIT.java | 6 +++--- .../ContainerWithExtensionSubclassIT.java | 2 +- .../ContainerWithFileInExtensionHomeIT.java | 2 +- .../hivemq/ContainerWithFileInHomeIT.java | 2 +- .../hivemq/ContainerWithLicenseIT.java | 2 +- .../ContainerWithoutPlatformExtensionsIT.java | 2 ++ .../hivemq/CreateFileInCopiedDirectoryIT.java | 2 +- .../CreateFileInExtensionDirectoryIT.java | 2 +- .../DisableEnableExtensionFromDirectoryIT.java | 6 +++--- .../hivemq/DisableEnableExtensionIT.java | 8 ++++---- .../hivemq/docs/DemoExtensionTestsIT.java | 1 + .../hivemq/docs/DemoFilesIT.java | 1 + .../hivemq/docs/DemoHiveMQContainerIT.java | 1 + .../hivemq/util/TestPublishModifiedUtil.java | 18 ++++++++++-------- 16 files changed, 34 insertions(+), 26 deletions(-) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java index 17f09d86adf..57d3b75bc24 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -27,6 +27,7 @@ void test() throws Exception { final Mqtt5BlockingClient publisher = Mqtt5Client.builder() .identifier("publisher") .serverPort(hivemq.getMqttPort()) + .serverHost(hivemq.getHost()) .buildBlocking(); publisher.connect(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java index 7672c70925d..4b89e418b05 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -23,7 +23,7 @@ void test() throws Exception { .withLogLevel(Level.DEBUG)) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } @@ -37,7 +37,7 @@ void test_wrongDirectoryName() throws Exception { .withLogLevel(Level.DEBUG)) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java index 3ad7b26148a..8979d2c17b0 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -27,15 +27,15 @@ void test() throws Exception { .withExtension(hiveMQExtension)) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.stop(); hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.stop(); hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java index 33880a800c9..53714123aff 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -29,7 +29,7 @@ void test() throws Exception { .withLogLevel(Level.DEBUG)) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java index 1d2b1705eae..559737c8868 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -43,7 +43,7 @@ void test() throws Exception { "/additionalFiles/my-file.txt")) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java index 542c54789e8..efdf6ad298d 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -41,7 +41,7 @@ void test() throws Exception { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java index 4fc27adf8c2..ba2dc472cdb 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -41,7 +41,7 @@ void test() throws Exception { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java index 37b37dc0d59..eaec72cb038 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -49,6 +49,7 @@ public void removeAllPlatformExtensions() throws InterruptedException { final Mqtt5BlockingClient client = MqttClient.builder() .serverPort(hivemq.getMqttPort()) + .serverHost(hivemq.getHost()) .useMqttVersion5() .buildBlocking(); @@ -82,6 +83,7 @@ public void removeKafkaExtension() throws InterruptedException { final Mqtt5BlockingClient client = MqttClient.builder() .serverPort(hivemq.getMqttPort()) + .serverHost(hivemq.getHost()) .useMqttVersion5() .buildBlocking(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java index 85089374624..58b70c3d1d9 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -51,7 +51,7 @@ void test() throws Exception { .withFileInHomeFolder(createDirectory(), "directory")) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java index a7756c69f1d..c41137f58c3 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -39,7 +39,7 @@ void test() throws Exception { .withExtension(hiveMQExtension)) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java index 2248681a769..f6b1b9b5cd7 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -26,11 +26,11 @@ void test() throws Exception { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.disableExtension("Modifier Extension", "modifier-extension"); - assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort())); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); hivemq.enableExtension("Modifier Extension", "modifier-extension"); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java index 7cc943c5527..5b3c6ab107f 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -33,13 +33,13 @@ void test() throws Exception { hivemq.start(); - assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort())); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); hivemq.enableExtension(hiveMQExtension); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.disableExtension(hiveMQExtension); - assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort())); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); hivemq.enableExtension(hiveMQExtension); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort()); + TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java index 2627dca2028..3a8ccc1bebe 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java @@ -47,6 +47,7 @@ public void test() throws Exception { // mqtt5client { final Mqtt5BlockingClient client = Mqtt5Client.builder() .serverPort(hivemqWithClasspathExtension.getMqttPort()) + .serverHost(hivemqWithClasspathExtension.getHost()) .buildBlocking(); client.connect(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java index 46c24e8e51d..7ec777d02b8 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java @@ -52,6 +52,7 @@ public void test() throws Exception { // mqtt5client { final Mqtt5BlockingClient client = Mqtt5Client.builder() .serverPort(hivemq.getMqttPort()) + .serverHost(hivemq.getHost()) .buildBlocking(); client.connect(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java index 60683c8d612..51e3a43d9e5 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java @@ -51,6 +51,7 @@ public void test() throws Exception { // mqtt5client { final Mqtt5BlockingClient client = Mqtt5Client.builder() .serverPort(hivemqCe.getMqttPort()) + .serverHost(hivemqCe.getHost()) .buildBlocking(); client.connect(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java index b2712ef5a1d..f2f1cfd692f 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java @@ -3,27 +3,29 @@ import com.hivemq.client.mqtt.MqttGlobalPublishFilter; import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import org.jetbrains.annotations.NotNull; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; public class TestPublishModifiedUtil { - public static void testPublishModified(final int mqttPort) throws InterruptedException, ExecutionException { + public static void testPublishModified(final int mqttPort, final @NotNull String host) throws Exception { final CompletableFuture publishReceived = new CompletableFuture<>(); final Mqtt5BlockingClient publisher = Mqtt5Client.builder() - .serverPort(mqttPort) - .identifier("publisher") - .buildBlocking(); + .serverPort(mqttPort) + .serverHost(host) + .identifier("publisher") + .buildBlocking(); publisher.connect(); final Mqtt5BlockingClient subscriber = Mqtt5Client.builder() - .serverPort(mqttPort) - .identifier("subscriber") - .buildBlocking(); + .serverPort(mqttPort) + .serverHost(host) + .identifier("subscriber") + .buildBlocking(); subscriber.connect(); subscriber.subscribeWith().topicFilter("test/topic").send(); subscriber.toAsync().publishes(MqttGlobalPublishFilter.ALL, publish -> { From fdb58fb3d3dd82dbbd7cf6a2be52ecbbcdbc25db Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 22 Feb 2022 08:33:06 -0500 Subject: [PATCH 1761/4969] Do not mount Selenium's SHM on Windows (#5105) It looks like mounting /dev/shm did not play well on WSL2. This change uses Docker's SHM support on Windows. --- .../containers/BrowserWebDriverContainer.java | 9 ++++++++- .../junit/BrowserWebDriverContainerTest.java | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index bd38dead8ac..e47c832e2ff 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -16,6 +16,9 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.SystemUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.openqa.selenium.Capabilities; @@ -205,7 +208,11 @@ protected void configure() { setCommand("/opt/bin/entry_point.sh"); if (getShmSize() == null) { - this.getBinds().add(new Bind("/dev/shm", new Volume("/dev/shm"), AccessMode.rw)); + if (SystemUtils.IS_OS_WINDOWS) { + withSharedMemorySize(512 * FileUtils.ONE_MB); + } else { + this.getBinds().add(new Bind("/dev/shm", new Volume("/dev/shm"), AccessMode.rw)); + } } /* diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java index 7b7d3a46733..0589d764573 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java @@ -2,6 +2,8 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.SystemUtils; +import org.junit.Assume; import org.junit.Test; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.firefox.FirefoxOptions; @@ -50,6 +52,7 @@ public void provideDefaultNoProxyEnvironmentIfNotSet() { @Test public void createContainerWithShmVolume() { + Assume.assumeFalse("SHM isn't mounted on Windows", SystemUtils.IS_OS_WINDOWS); try ( BrowserWebDriverContainer webDriverContainer = new BrowserWebDriverContainer() .withCapabilities(new FirefoxOptions()) From 14eff07a7cae8d48b07b80e309bba601f164ae66 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 22 Feb 2022 09:50:27 -0500 Subject: [PATCH 1762/4969] Update to `docker-java` 3.2.13 (#5045) * Try `docker-java` 3.2.13 * Fix imports * Update build.gradle * Update SimplePostgreSQLTest.java * Use `withCgroupnsMode` * fix `BrowserWebDriverContainer` * FML --- core/build.gradle | 10 +++------- .../java/org/testcontainers/DockerClientFactory.java | 4 ++-- .../org/testcontainers/containers/ContainerState.java | 2 +- .../containers/DockerComposeContainer.java | 4 ++-- .../testcontainers/containers/GenericContainer.java | 4 ++-- .../dockerclient/DockerClientConfigUtils.java | 2 +- .../dockerclient/DockerClientProviderStrategy.java | 2 +- .../NpipeSocketClientProviderStrategy.java | 2 +- .../RootlessDockerClientProviderStrategy.java | 4 ++-- .../dockerclient/UnixSocketClientProviderStrategy.java | 2 +- .../images/builder/ImageFromDockerfile.java | 2 +- .../images/builder/traits/StringsTrait.java | 2 +- .../java/org/testcontainers/utility/AuditLogger.java | 2 +- .../testcontainers/utility/DockerMachineClient.java | 2 +- .../java/org/testcontainers/utility/MountableFile.java | 2 +- .../testcontainers/utility/RegistryAuthLocator.java | 6 +++--- .../utility/TestcontainersConfiguration.java | 2 +- .../containers/output/ToStringConsumerTest.java | 2 +- .../dockerfile/statement/AbstractStatementTest.java | 6 +++--- .../utility/RegistryAuthLocatorTest.java | 2 +- .../main/java/org/testcontainers/ext/ScriptUtils.java | 2 +- .../testcontainers/jdbc/AbstractJDBCDriverTest.java | 2 +- .../containers/JdbcDatabaseContainer.java | 2 +- .../main/java/org/testcontainers/k3s/K3sContainer.java | 4 +--- .../junit/mariadb/SimpleMariaDBTest.java | 2 +- .../mssqlserver/CustomPasswordMSSQLServerTest.java | 2 +- .../testcontainers/junit/mysql/SimpleMySQLTest.java | 2 +- .../org/testcontainers/containers/OracleContainer.java | 10 +++++----- .../containers/BrowserWebDriverContainer.java | 2 +- .../junit/BrowserWebDriverContainerTest.java | 2 +- .../junit/LocalServerWebDriverContainerTest.java | 2 +- .../org/testcontainers/containers/SolrContainer.java | 2 +- 32 files changed, 46 insertions(+), 52 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 7b014d1ad24..a471aa4816e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -73,17 +73,13 @@ dependencies { shaded 'org.awaitility:awaitility:4.1.1' - api platform('com.github.docker-java:docker-java-bom:3.2.12') - shaded platform('com.github.docker-java:docker-java-bom:3.2.12') + api platform('com.github.docker-java:docker-java-bom:3.2.13') + shaded platform('com.github.docker-java:docker-java-bom:3.2.13') api "com.github.docker-java:docker-java-api" shaded 'com.github.docker-java:docker-java-core' - - shaded 'com.github.docker-java:docker-java-transport-okhttp', { - // TODO remove unused `net.java.dev.jna:jna-platform` from `docker-java-transport-okhttp` - exclude(group: 'net.java.dev.jna', module: 'jna-platform') - } + shaded 'com.github.docker-java:docker-java-transport-okhttp' api 'com.github.docker-java:docker-java-transport-zerodep' diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index d0a4e4a4fb3..9a6165ef55f 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -20,8 +20,8 @@ import lombok.SneakyThrows; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; import org.testcontainers.dockerclient.TransportConfig; diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 5de9ef7c566..7fe90bd57a4 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -12,7 +12,7 @@ import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.lang.math.NumberUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index b56c70cb959..b8913e8ac7c 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -12,8 +12,8 @@ import com.google.common.util.concurrent.Uninterruptibles; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.slf4j.Logger; diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index aca543ef7ec..22a4f0ba739 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -27,8 +27,8 @@ import lombok.Setter; import lombok.SneakyThrows; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.runner.Description; diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java index b494eb087f6..e393e59419f 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java @@ -2,7 +2,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.testcontainers.DockerClientFactory; import java.io.File; diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index b595ddba6ca..89383698adf 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -14,7 +14,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; import org.rnorth.ducttape.TimeoutException; import org.rnorth.ducttape.ratelimits.RateLimiter; diff --git a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java index fc3c65fd3dd..7f73e1d7675 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java @@ -1,6 +1,6 @@ package org.testcontainers.dockerclient; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import java.net.URI; diff --git a/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java index 3ee58f4910a..36d6b5f6123 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java @@ -4,8 +4,8 @@ import com.sun.jna.Native; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.Nullable; import java.net.URI; diff --git a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java index 6f030ada279..4a85394155d 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java @@ -1,6 +1,6 @@ package org.testcontainers.dockerclient; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import java.io.IOException; import java.net.URI; diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index a434dee2b41..abf13f8ef02 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -9,7 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.images.ParsedDockerfile; diff --git a/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java b/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java index 51423068ec9..2b23551ee58 100644 --- a/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java @@ -1,7 +1,7 @@ package org.testcontainers.images.builder.traits; import lombok.Getter; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.testcontainers.images.builder.Transferable; /** diff --git a/core/src/main/java/org/testcontainers/utility/AuditLogger.java b/core/src/main/java/org/testcontainers/utility/AuditLogger.java index 567132da05d..f6c4559485d 100644 --- a/core/src/main/java/org/testcontainers/utility/AuditLogger.java +++ b/core/src/main/java/org/testcontainers/utility/AuditLogger.java @@ -5,7 +5,7 @@ import com.github.dockerjava.api.command.DockerCmd; import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.MDC; diff --git a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java index 021baf270d9..6f1e2c9d50b 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java +++ b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java @@ -1,7 +1,7 @@ package org.testcontainers.utility; import lombok.NonNull; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; import java.util.List; diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 071d36631b0..19dca4c134c 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -7,7 +7,7 @@ import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarConstants; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.DockerClientFactory; import org.testcontainers.UnstableAPI; diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index b373eedaa03..d88bdccd76a 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -4,8 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.model.AuthConfig; import com.google.common.annotations.VisibleForTesting; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; import org.zeroturnaround.exec.InvalidResultException; import org.zeroturnaround.exec.ProcessExecutor; @@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.apache.commons.lang.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.slf4j.LoggerFactory.getLogger; import static org.testcontainers.utility.AuthConfigUtil.toSafeString; diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index bb3febd6b3f..c6ce7496dd9 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -8,7 +8,7 @@ import lombok.SneakyThrows; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java index 8da67e897e9..1760a8031b2 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.assertj.core.api.Assertions; import org.junit.Test; import org.testcontainers.containers.Container.ExecResult; diff --git a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java index 35d325c5f40..15c73cadb5f 100644 --- a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java @@ -1,8 +1,8 @@ package org.testcontainers.images.builder.dockerfile.statement; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.junit.Rule; import org.junit.rules.TestName; import org.rnorth.ducttape.Preconditions; @@ -31,7 +31,7 @@ protected void assertStatement(Statement statement) { IOUtils.closeQuietly(inputStream); expectedLines = StringUtils.chomp(content.replaceAll("\r\n", "\n").trim()).split("\n"); } catch (Exception e) { - fail("can't load fixture '" + testName.getMethodName() + "'\n" + ExceptionUtils.getFullStackTrace(e)); + fail("can't load fixture '" + testName.getMethodName() + "'\n" + ExceptionUtils.getStackTrace(e)); } StringBuilder builder = new StringBuilder(); diff --git a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java index a5e5ab4260d..5db2583958a 100644 --- a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java +++ b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java @@ -2,7 +2,7 @@ import com.github.dockerjava.api.model.AuthConfig; import com.google.common.io.Resources; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; import org.junit.Test; diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java index d30064af28e..76f0cb90ea0 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java @@ -17,7 +17,7 @@ package org.testcontainers.ext; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.delegate.DatabaseDelegate; diff --git a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java index 580aad513e3..4e5eb03bb49 100644 --- a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java @@ -3,7 +3,7 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.apache.commons.dbutils.QueryRunner; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.junit.AfterClass; import org.junit.Test; import org.junit.runners.Parameterized.Parameter; diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index cf5ae150575..c4bacf3c8ff 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -4,7 +4,7 @@ import java.sql.Statement; import lombok.NonNull; import lombok.SneakyThrows; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.delegate.DatabaseDelegate; diff --git a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java index 511b309e0d5..54cb2ff500f 100644 --- a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java +++ b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java @@ -27,9 +27,7 @@ public K3sContainer(DockerImageName dockerImageName) { addExposedPorts(6443, 8443); setPrivilegedMode(true); withCreateContainerCmdModifier(it -> { - DockerObjectAccessor.overrideRawValue( - it.getHostConfig(), "CgroupnsMode", "host" - ); + it.getHostConfig().withCgroupnsMode("host"); }); addFileSystemBind("/sys/fs/cgroup", "/sys/fs/cgroup", BindMode.READ_WRITE); diff --git a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index 4ea98bbe1fe..2dcdbafd9e3 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -1,6 +1,6 @@ package org.testcontainers.junit.mariadb; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.junit.Test; import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java index 3df8ff0fa3d..6ebd3624577 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java @@ -1,6 +1,6 @@ package org.testcontainers.junit.mssqlserver; -import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index 1b6143b3b34..90973bc4b56 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -1,6 +1,6 @@ package org.testcontainers.junit.mysql; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index c833689e692..689646f0006 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -1,7 +1,7 @@ package org.testcontainers.containers; import com.google.common.collect.Sets; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; @@ -34,7 +34,7 @@ public class OracleContainer extends JdbcDatabaseContainer { static final String DEFAULT_SID = "xe"; static final String DEFAULT_SYSTEM_USER = "system"; static final String DEFAULT_SYS_USER = "sys"; - + // Test container defaults static final String APP_USER = "test"; static final String APP_USER_PASSWORD = "test"; @@ -75,7 +75,7 @@ private void preconfigure() { .withRegEx(".*DATABASE IS READY TO USE!.*\\s") .withTimes(1) .withStartupTimeout(Duration.of(DEFAULT_STARTUP_TIMEOUT_SECONDS, SECONDS)); - + withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT); } @@ -98,7 +98,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return isUsingSid() ? + return isUsingSid() ? "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + ":" + getSid() : "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + "/" + getDatabaseName(); } @@ -195,7 +195,7 @@ protected void configure() { if(databaseName != DEFAULT_DATABASE_NAME) { withEnv("ORACLE_DATABASE", databaseName); } - + withEnv("APP_USER", username); withEnv("APP_USER_PASSWORD", password); } diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index e47c832e2ff..12bbbc07de5 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.openqa.selenium.Capabilities; diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java index 0589d764573..a53fa532f99 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java @@ -2,7 +2,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import org.junit.Assume; import org.junit.Test; import org.openqa.selenium.chrome.ChromeOptions; diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java index f7d626c15b5..772193e2d43 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java @@ -10,7 +10,7 @@ import org.testcontainers.containers.BrowserWebDriverContainer; import org.testcontainers.utility.TestEnvironment; -import static org.apache.commons.lang.SystemUtils.IS_OS_MAC_OSX; +import static org.apache.commons.lang3.SystemUtils.IS_OS_MAC_OSX; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; /** diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java index 4bc2f19ec86..4d0b5cd1ae1 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java @@ -2,7 +2,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import lombok.SneakyThrows; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; From 244c77c618bfdd9ba5dad464a22b4b56789550c2 Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Fri, 25 Feb 2022 12:07:11 +0100 Subject: [PATCH 1763/4969] [Neo4j] Include code from tests in docs (#5120) --- docs/modules/databases/neo4j.md | 149 ++++-------------- examples/neo4j-container/build.gradle | 14 ++ .../containers/Neo4jExampleTest.java | 77 +++++++++ examples/settings.gradle | 1 + .../Neo4jContainerJUnitIntegrationTest.java | 2 +- .../containers/Neo4jContainerTest.java | 27 +++- .../containers/Neo4jTestImages.java | 7 - 7 files changed, 143 insertions(+), 134 deletions(-) create mode 100644 examples/neo4j-container/build.gradle create mode 100644 examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java delete mode 100644 modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java diff --git a/docs/modules/databases/neo4j.md b/docs/modules/databases/neo4j.md index 17e1e154fc8..87a5d9157d1 100644 --- a/docs/modules/databases/neo4j.md +++ b/docs/modules/databases/neo4j.md @@ -6,68 +6,18 @@ Note that it's based on the [official Docker image](https://hub.docker.com/_/neo ## Usage example -Declare your Testcontainer as a `@ClassRule` or `@Rule` in a JUnit 4 test or as static or member attribute of a JUnit 5 test annotated with `@Container` as you would with other Testcontainers. -You can either use call `getHttpUrl()` or `getBoltUrl()` on the Neo4j container. -`getHttpUrl()` gives you the HTTP-address of the transactional HTTP endpoint while `getBoltUrl()` is meant to be used with one of the [official Bolt drivers](https://neo4j.com/developer/language-guides/). +Declare your Testcontainers as a `@ClassRule` or `@Rule` in a JUnit 4 test or as static or member attribute of a JUnit 5 test annotated with `@Container` as you would with other Testcontainers. +You can either use call `getBoltUrl()` or `getHttpUrl()` on the Neo4j container. +`getBoltUrl()` is meant to be used with one of the [official Bolt drivers](https://neo4j.com/developer/language-guides/) while `getHttpUrl()` gives you the HTTP-address of the transactional HTTP endpoint. On the JVM you would most likely use the [Java driver](https://github.com/neo4j/neo4j-java-driver). The following example uses the JUnit 5 extension `@Testcontainers` and demonstrates both the usage of the Java Driver and the REST endpoint: -=== "JUnit 5 example" - ```java - @Testcontainers - public class ExampleTest { - - @Container - private static Neo4jContainer neo4jContainer = new Neo4jContainer() - .withAdminPassword(null); // Disable password - - @Test - void testSomethingUsingBolt() { - - // Retrieve the Bolt URL from the container - String boltUrl = neo4jContainer.getBoltUrl(); - try ( - Driver driver = GraphDatabase.driver(boltUrl, AuthTokens.none()); - Session session = driver.session() - ) { - long one = session.run("RETURN 1", Collections.emptyMap()).next().get(0).asLong(); - assertThat(one, is(1L)); - } catch (Exception e) { - fail(e.getMessage()); - } - } - - @Test - void testSomethingUsingHttp() throws IOException { - - // Retrieve the HTTP URL from the container - String httpUrl = neo4jContainer.getHttpUrl(); - - URL url = new URL(httpUrl + "/db/data/transaction/commit"); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - - con.setRequestMethod("POST"); - con.setRequestProperty("Content-Type", "application/json"); - con.setDoOutput(true); - - try (Writer out = new OutputStreamWriter(con.getOutputStream())) { - out.write("{\"statements\":[{\"statement\":\"RETURN 1\"}]}"); - out.flush(); - } - - assertThat(con.getResponseCode(), is(HttpURLConnection.HTTP_OK)); - try (BufferedReader buffer = new BufferedReader(new InputStreamReader(con.getInputStream()))) { - String expectedResponse = - "{\"results\":[{\"columns\":[\"1\"],\"data\":[{\"row\":[1],\"meta\":[null]}]}],\"errors\":[]}"; - String response = buffer.lines().collect(Collectors.joining("\n")); - assertThat(response, is(expectedResponse)); - } - } - } - ``` + +[JUnit 5 example](../../../examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java) inside_block:junitExample + -You are not limited to Unit tests and can of course use an instance of the Neo4j Testcontainer in vanilla Java code as well. +You are not limited to Unit tests and can of course use an instance of the Neo4j Testcontainers in vanilla Java code as well. ## Additional features @@ -75,70 +25,40 @@ You are not limited to Unit tests and can of course use an instance of the Neo4j Authentication can be disabled: -```java -@Testcontainers -public class ExampleTest { - - @Container - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withoutAuthentication(); -} -``` + +[Disable authentication](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:withoutAuthentication + ### Neo4j-Configuration Neo4j's Docker image needs Neo4j configuration options in a dedicated format. -The container takes care of that and you can configure the database with standard options like the following: - -```java -@Testcontainers -public class ExampleTest { +The container takes care of that, and you can configure the database with standard options like the following: - @Container - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withNeo4jConfig("dbms.security.procedures.unrestricted", "apoc.*,algo.*"); -} -``` + +[Neo4j configuration](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:neo4jConfiguration + ### Add custom plugins Custom plugins, like APOC, can be copied over to the container from any classpath or host resource like this: -```java -@Testcontainers -public class ExampleTest { - - @Container - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withPlugins(MountableFile.forClasspathResource("/apoc-3.5.0.1-all.jar")); -} -``` + +[Plugin jar](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:registerPluginsJar + Whole directories work as well: -```java -@Testcontainers -public class ExampleTest { - - @Container - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withPlugins(MountableFile.forClasspathResource("/my-plugins")); -} -``` + +[Plugin folder](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:registerPluginsPath + ### Start the container with a predefined database If you have an existing database (`graph.db`) you want to work with, copy it over to the container like this: -```java -@Testcontainers -public class ExampleTest { - - @Container - Neo4jContainer neo4jContainer = new Neo4jContainer() - .withDatabase(MountableFile.forClasspathResource("/test-graph.db")); -} -``` + +[Copy database](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:copyDatabase + !!! note The `withDatabase` method will only work with Neo4j 3.5 and throw an exception if used in combination with a newer version. @@ -147,16 +67,11 @@ The `withDatabase` method will only work with Neo4j 3.5 and throw an exception i If you need the Neo4j enterprise license, you can declare your Neo4j container like this: -```java -@Testcontainers -public class ExampleTest { - @ClassRule - public static Neo4jContainer neo4jContainer = new Neo4jContainer() - .withEnterpriseEdition(); -} -``` + +[Enterprise edition](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:enterpriseEdition + -This creates a Testcontainer based on the Docker image build with the Enterprise version of Neo4j. +This creates a Testcontainers based on the Docker image build with the Enterprise version of Neo4j. The call to `withEnterpriseEdition` adds the required environment variable that you accepted the terms and condition of the enterprise version. You accept those by adding a file named `container-license-acceptance.txt` to the root of your classpath containing the text `neo4j:3.5.0-enterprise` in one line. You'll find more information about licensing Neo4j here: [About Neo4j Licenses](https://neo4j.com/licensing/). @@ -181,11 +96,11 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: ``` !!! hint - Add the Neo4j Java driver if you plan to access the Testcontainer via Bolt: + Add the Neo4j Java driver if you plan to access the Testcontainers via Bolt: === "Gradle" ```groovy - compile "org.neo4j.driver:neo4j-java-driver:1.7.1" + compile "org.neo4j.driver:neo4j-java-driver:4.4.3" ``` === "Maven" @@ -193,10 +108,6 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: org.neo4j.driver neo4j-java-driver - 1.7.1 + 4.4.3 ``` - - - - diff --git a/examples/neo4j-container/build.gradle b/examples/neo4j-container/build.gradle new file mode 100644 index 00000000000..718adc3183a --- /dev/null +++ b/examples/neo4j-container/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.assertj:assertj-core:3.22.0' + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.3' + testImplementation 'org.testcontainers:neo4j' + testImplementation 'org.testcontainers:junit-jupiter' +} diff --git a/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java new file mode 100644 index 00000000000..7730d4fa8d0 --- /dev/null +++ b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java @@ -0,0 +1,77 @@ +package org.testcontainers.containers; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Collections; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Session; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + +// junitExample { +@Testcontainers +public class Neo4jExampleTest { + + @Container + private static Neo4jContainer neo4jContainer = + new Neo4jContainer<>(DockerImageName.parse("neo4j:4.4")) + .withAdminPassword(null); // Disable password + + @Test + void testSomethingUsingBolt() { + + // Retrieve the Bolt URL from the container + String boltUrl = neo4jContainer.getBoltUrl(); + try ( + Driver driver = GraphDatabase.driver(boltUrl, AuthTokens.none()); + Session session = driver.session() + ) { + long one = session.run("RETURN 1", Collections.emptyMap()).next().get(0).asLong(); + assertThat(one).isEqualTo(1L); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + @Test + void testSomethingUsingHttp() throws IOException { + + // Retrieve the HTTP URL from the container + String httpUrl = neo4jContainer.getHttpUrl(); + + URL url = new URL(httpUrl + "/db/data/transaction/commit"); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + + con.setRequestMethod("POST"); + con.setRequestProperty("Content-Type", "application/json"); + con.setDoOutput(true); + + try (Writer out = new OutputStreamWriter(con.getOutputStream())) { + out.write("{\"statements\":[{\"statement\":\"RETURN 1\"}]}"); + out.flush(); + } + + assertThat(con.getResponseCode()).isEqualTo(HttpURLConnection.HTTP_OK); + try (BufferedReader buffer = new BufferedReader(new InputStreamReader(con.getInputStream()))) { + String expectedResponse = + "{\"results\":[{\"columns\":[\"1\"],\"data\":[{\"row\":[1],\"meta\":[null]}]}],\"errors\":[]}"; + String response = buffer.lines().collect(Collectors.joining("\n")); + assertThat(response).isEqualTo(expectedResponse); + } + } +} +// } diff --git a/examples/settings.gradle b/examples/settings.gradle index f58ea83fb9b..75f739e9005 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -23,6 +23,7 @@ include 'disque-job-queue' include 'kafka-cluster' include 'linked-container' include 'mongodb-container' +include 'neo4j-container' include 'redis-backed-cache' include 'redis-backed-cache-testng' include 'selenium-container' diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java index ad6ccad8281..6832dfff0c7 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java @@ -20,7 +20,7 @@ public class Neo4jContainerJUnitIntegrationTest { @ClassRule - public static Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE); + public static Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4"); @Test public void shouldStart() { diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java index fcfda6f6873..25924fdd6b4 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java @@ -9,6 +9,7 @@ import org.neo4j.driver.Record; import org.neo4j.driver.Result; import org.neo4j.driver.Session; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; import java.util.Collections; @@ -31,7 +32,10 @@ public class Neo4jContainerTest { public void shouldDisableAuthentication() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE).withoutAuthentication() + // withoutAuthentication { + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") + .withoutAuthentication() + // } ) { neo4jContainer.start(); try (Driver driver = getDriver(neo4jContainer); @@ -46,8 +50,10 @@ public void shouldDisableAuthentication() { @Test public void shouldCopyDatabase() { try ( + // copyDatabase { Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:3.5.30") .withDatabase(MountableFile.forClasspathResource("/test-graph.db")) + // } ) { neo4jContainer.start(); try ( @@ -88,8 +94,10 @@ public void shouldFailOnCopyDatabaseForCustomNonSemverNeo4j4Image() { @Test public void shouldCopyPlugins() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + // registerPluginsPath { + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") .withPlugins(MountableFile.forClasspathResource("/custom-plugins")) + // } ) { neo4jContainer.start(); try ( @@ -104,8 +112,10 @@ public void shouldCopyPlugins() { @Test public void shouldCopyPlugin() { try ( - Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + // registerPluginsJar { + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") .withPlugins(MountableFile.forClasspathResource("/custom-plugins/hello-world.jar")) + // } ) { neo4jContainer.start(); try ( @@ -131,7 +141,7 @@ public void shouldCheckEnterpriseLicense() { String expectedImageName = "neo4j:4.4-enterprise"; assertThatExceptionOfType(IllegalStateException.class) - .isThrownBy(() -> new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE).withEnterpriseEdition()) + .isThrownBy(() -> new Neo4jContainer<>("neo4j:4.4").withEnterpriseEdition()) .withMessageContaining("The image " + expectedImageName + " requires you to accept a license agreement."); } @@ -140,8 +150,10 @@ public void shouldRunEnterprise() { assumeThat(Neo4jContainerTest.class.getResource(ACCEPTANCE_FILE_LOCATION)).isNotNull(); try ( - Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + // enterpriseEdition { + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") .withEnterpriseEdition() + // } .withAdminPassword("Picard123") ) { neo4jContainer.start(); @@ -159,10 +171,11 @@ public void shouldRunEnterprise() { @Test public void shouldAddConfigToEnvironment() { - - Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jTestImages.NEO4J_TEST_IMAGE) + // neo4jConfiguration { + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") .withNeo4jConfig("dbms.security.procedures.unrestricted", "apoc.*,algo.*") .withNeo4jConfig("dbms.tx_log.rotation.size", "42M"); + // } assertThat(neo4jContainer.getEnvMap()) .containsEntry("NEO4J_dbms_security_procedures_unrestricted", "apoc.*,algo.*"); diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java deleted file mode 100644 index aee6f29fc5f..00000000000 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jTestImages.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.testcontainers.containers; - -import org.testcontainers.utility.DockerImageName; - -public interface Neo4jTestImages { - DockerImageName NEO4J_TEST_IMAGE = DockerImageName.parse("neo4j:4.4.1"); -} From cbccd499fbc9f882a8d4da0f7254796a1ea9d28f Mon Sep 17 00:00:00 2001 From: hellozepp Date: Tue, 1 Mar 2022 00:54:49 +0800 Subject: [PATCH 1764/4969] Add the using organization `Byzer` (#5125) --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 998722af50f..fdbad94b851 100644 --- a/docs/index.md +++ b/docs/index.md @@ -198,6 +198,7 @@ A huge thank you to our sponsors: * [Elastic](https://www.elastic.co) - Integration testing of the Java APM agent * [Alkira](https://www.alkira.com/) - Testing of multiple micro-services using Kafka, PostgreSQL, Apache Zookeeper, Etcd and so on. * [Togglz](https://www.togglz.org/) - Feature Flags for the Java platform +* [Byzer](https://www.byzer.org/home) - Integration tests for Data and AI platforms are based on multiple versions of Byzer, Ray and Apache Spark. ## License From d21a29e7a4de2c0d82cf2ae4b6c9eb7d85533103 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:08:33 +0000 Subject: [PATCH 1765/4969] Bump aws-java-sdk-s3 from 1.12.150 to 1.12.169 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.150 to 1.12.169. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.150...1.12.169) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8dc6dc2671f..7a076881a96 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.150' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.137' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.169' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.169' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.150' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.139' testImplementation 'software.amazon.awssdk:s3:2.17.108' From 43f807dc8ba58c5cbab61880e24c0ce2fd3595a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:08:50 +0000 Subject: [PATCH 1766/4969] Bump neo4j from 3.5.29 to 3.5.31 in /modules/neo4j Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.29 to 3.5.31. - [Release notes](https://github.com/neo4j/neo4j/releases) - [Commits](https://github.com/neo4j/neo4j/commits) --- updated-dependencies: - dependency-name: org.neo4j:neo4j dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 1d5cffc1955..27bf38b9f23 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -29,7 +29,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.29" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.31" api project(":testcontainers") From 0343dacda34bccd074700810c4f7c53d0ab74c53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:08:51 +0000 Subject: [PATCH 1767/4969] Bump aws-java-sdk-logs from 1.12.139 to 1.12.169 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.139 to 1.12.169. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.139...1.12.169) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8dc6dc2671f..fda140b12da 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.150' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.137' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.150' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.139' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.169' testImplementation 'software.amazon.awssdk:s3:2.17.108' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 7c75b0a3040721b35b592a747c2097fa1abf977b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:09:32 +0000 Subject: [PATCH 1768/4969] Bump guava from 31.0.1-jre to 31.1-jre in /modules/jdbc-test Bumps [guava](https://github.com/google/guava) from 31.0.1-jre to 31.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 98570722e6a..314b3ab6a2d 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -2,7 +2,7 @@ dependencies { api project(':jdbc') api project(':test-support') - api 'com.google.guava:guava:31.0.1-jre' + api 'com.google.guava:guava:31.1-jre' api 'org.apache.commons:commons-lang3:3.12.0' api 'com.zaxxer:HikariCP-java6:2.3.13' api 'commons-dbutils:commons-dbutils:1.7' From e17bc43e70dc3eaee7224eb1b4ace75c905194a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:09:45 +0000 Subject: [PATCH 1769/4969] Bump transport from 7.17.0 to 7.17.1 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.17.0 to 7.17.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/master/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.17.0...v7.17.1) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index fca8ecfe9fb..d669f0fbd05 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2" - testImplementation "org.elasticsearch.client:transport:7.17.0" + testImplementation "org.elasticsearch.client:transport:7.17.1" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From d7cb81c9a97deb39cd6d7c100853cb7ccb358476 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:09:46 +0000 Subject: [PATCH 1770/4969] Bump org.springframework.boot from 2.6.3 to 2.6.4 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.6.3 to 2.6.4. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.6.3...v2.6.4) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index d728c13e3c0..7677e82eefb 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.3' + id 'org.springframework.boot' version '2.6.4' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 5a9495d86bf..45cee0ec20b 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.6.3" + id("org.springframework.boot") version "2.6.4" id("org.jetbrains.kotlin.jvm") version "1.6.10" id("org.jetbrains.kotlin.plugin.spring") version "1.6.10" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index ace47d12ebe..e3b3376e28f 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.3' + id 'org.springframework.boot' version '2.6.4' } apply plugin: 'io.spring.dependency-management' From 99578c4b2a2e45b1b7efe4638eb1af4449cbb667 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:10:10 +0000 Subject: [PATCH 1771/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.150 to 1.12.169. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.150...1.12.169) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index ce09dde17e6..2fa5978772e 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.150' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.169' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.150' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 6904d8e21b5a248420c2373d0f8efcefd6a7000d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:10:28 +0000 Subject: [PATCH 1772/4969] Bump actions/setup-java from 2.5.0 to 3 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2.5.0 to 3. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2.5.0...v3) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index d7351605e6d..3fb2467a295 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -17,7 +17,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/setup-java@v3 with: java-version: '8.0.302' distribution: temurin @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/setup-java@v3 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fd59f892f0..db7232fffa8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/setup-java@v3 with: java-version: '8.0.302' distribution: temurin @@ -51,7 +51,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/setup-java@v3 with: java-version: '8.0.302' distribution: temurin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d9026eb2257..f6df0dd46f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/setup-java@v3 with: java-version: '8.0.302' distribution: temurin From 5d2806f3bc4a01660cc9f550a37a9213946e62f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:18:26 +0000 Subject: [PATCH 1773/4969] Bump google-cloud-spanner from 6.17.4 to 6.20.0 in /modules/gcloud Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.17.4 to 6.20.0. - [Release notes](https://github.com/googleapis/java-spanner/releases) - [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-spanner/compare/v6.17.4...v6.20.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-spanner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 72e304029ce..0e5ebee97dd 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.2.2' testImplementation 'com.google.cloud:google-cloud-firestore:3.0.11' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' - testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' + testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.2' testImplementation 'org.assertj:assertj-core:3.22.0' } From 03b5a75d391600f716c5a514d58eb79c985baa42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:18:30 +0000 Subject: [PATCH 1774/4969] Bump google-cloud-firestore from 3.0.11 to 3.0.14 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.0.11 to 3.0.14. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.0.11...v3.0.14) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 72e304029ce..7d17a689ecf 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.2.2' - testImplementation 'com.google.cloud:google-cloud-firestore:3.0.11' + testImplementation 'com.google.cloud:google-cloud-firestore:3.0.14' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.17.4' testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.2' From 30e8635e7e5b8160e66f014d4055a20b628e8499 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 3 Mar 2022 06:55:50 -0500 Subject: [PATCH 1775/4969] Add the session header to every Docker request (#5145) To improve tracing and other operations, we add current session's id to every Docker request that we are making. --- .../DockerClientProviderStrategy.java | 7 ++++- .../HeadersAddingDockerHttpClient.java | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 89383698adf..c65887b6af6 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -20,10 +20,12 @@ import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.DockerClientFactory; import org.testcontainers.utility.TestcontainersConfiguration; import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -282,7 +284,10 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) { .withDockerHost(transportConfig.getDockerHost().toString()) .build() ), - dockerHttpClient + new HeadersAddingDockerHttpClient( + dockerHttpClient, + Collections.singletonMap("x-tc-sid", DockerClientFactory.SESSION_ID) + ) ); } diff --git a/core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java b/core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java new file mode 100644 index 00000000000..59a51e19a80 --- /dev/null +++ b/core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java @@ -0,0 +1,27 @@ +package org.testcontainers.dockerclient; + +import com.github.dockerjava.transport.DockerHttpClient; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.experimental.Delegate; + +import java.io.Closeable; +import java.util.Map; + +@RequiredArgsConstructor +@ToString +class HeadersAddingDockerHttpClient implements DockerHttpClient { + + @Delegate(types = Closeable.class) + final DockerHttpClient delegate; + + final Map headers; + + @Override + public Response execute(Request request) { + request = Request.builder().from(request) + .putAllHeaders(headers) + .build(); + return delegate.execute(request); + } +} From 71a0679a675f5474f8f6c869827de6402d1819b9 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 3 Mar 2022 14:45:15 -0500 Subject: [PATCH 1776/4969] Run tests using shaded dependencies (#5146) * Test shaded JARs * Find shaded projects recursively * Add missing space * fix core tests * fix HiveMQ module * Simplify the HiveMQ workaround * Add a comment that explains why we pin Jackson version in k3s --- ...temPropertyClientProviderStrategyTest.java | 26 +++++++++---------- gradle/shading.gradle | 12 +++++++++ .../hivemq/HiveMQExtension.java | 16 +++++++++--- modules/k3s/build.gradle | 5 +++- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java index c8eec1d38d8..a6bd68be745 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java @@ -1,8 +1,8 @@ package org.testcontainers.dockerclient; import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.LocalDirectorySSLConfig; import com.github.dockerjava.transport.SSLConfig; +import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -16,15 +16,12 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.Properties; 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.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -93,21 +90,24 @@ public void testWhenDockerHostAndSSLConfigPresent() throws IOException { assertEquals("tcp://1.2.3.4:2375", transportConfig.getDockerHost().toString()); SSLConfig sslConfig = transportConfig.getSslConfig(); - assertNotNull(sslConfig); - assertTrue(sslConfig instanceof LocalDirectorySSLConfig); - assertEquals(tempDirPath, ((LocalDirectorySSLConfig) sslConfig).getDockerCertPath()); + Assertions.assertThat(sslConfig) + .extracting("dockerCertPath") + .isEqualTo(tempDirPath); } @Test public void applicableWhenIgnoringUserPropertiesAndConfigured() { Mockito.doReturn("autoIgnoringUserProperties").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); - DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost("tcp://1.2.3.4:2375"); + Properties oldProperties = System.getProperties(); + try { + System.setProperty("DOCKER_HOST", "tcp://1.2.3.4:2375"); + EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); - EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(configBuilder); - - assertTrue(strategy.isApplicable()); + assertTrue(strategy.isApplicable()); + } finally { + System.setProperties(oldProperties); + } } @Test diff --git a/gradle/shading.gradle b/gradle/shading.gradle index 909989caf84..fc7f6587b3e 100644 --- a/gradle/shading.gradle +++ b/gradle/shading.gradle @@ -55,4 +55,16 @@ project.afterEvaluate { tasks.shadowJar.relocate(pkg, "org.testcontainers.shaded.${pkg}") } + + // Add shaded JARs first + tasks.test.classpath = findShadedProjects(project) + .plus(project) + .sum { it.tasks.findByName("shadowJar").outputs.files } + .plus(sourceSets.test.runtimeClasspath) +} + +static Set findShadedProjects(Project project) { + Set dependencies = project.configurations.api.dependencies.withType(ProjectDependency)*.dependencyProject + + return dependencies + dependencies.collectMany { it -> findShadedProjects(it) } } diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java index a975439f4b3..934dfd0c29c 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -4,9 +4,12 @@ import javassist.NotFoundException; import lombok.Getter; import org.apache.commons.io.FileUtils; +import org.jboss.shrinkwrap.api.ExtensionLoader; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.exporter.ZipExporter; import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.impl.base.exporter.zip.ZipExporterImpl; +import org.jboss.shrinkwrap.impl.base.spec.JavaArchiveImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -101,9 +104,16 @@ private HiveMQExtension( } } - final JavaArchive javaArchive = - ShrinkWrap.create(JavaArchive.class) - .addAsServiceProvider(EXTENSION_MAIN_CLASS_NAME, hiveMQExtension.getMainClass().getName()); + // Shadow Gradle plugin doesn't know how to handle ShrinkWrap's SPI definitions + // This workaround creates the mappings programmatically + // TODO write a custom Gradle Shadow transformer? + ExtensionLoader extensionLoader = ShrinkWrap.getDefaultDomain().getConfiguration().getExtensionLoader(); + extensionLoader.addOverride(JavaArchive.class, JavaArchiveImpl.class); + extensionLoader.addOverride(ZipExporter.class, ZipExporterImpl.class); + + final JavaArchive javaArchive = ShrinkWrap + .create(JavaArchive.class) + .addAsServiceProvider(EXTENSION_MAIN_CLASS_NAME, hiveMQExtension.getMainClass().getName()); putSubclassesIntoJar(hiveMQExtension.getId(), hiveMQExtension.getMainClass(), javaArchive); for (final Class additionalClass : hiveMQExtension.getAdditionalClasses()) { diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index e36dc67bd9c..5007c832e7f 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -3,7 +3,10 @@ description = "Testcontainers :: K3S" dependencies { api project(":testcontainers") - shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1' + // https://youtu.be/otCpCn0l4Wo + // The core module depends on jackson-databind 2.8.x for backward compatibility. + // Any >2.8 version here is not compatible with jackson-databind 2.8.x. + shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' testImplementation 'io.fabric8:kubernetes-client:5.11.0' testImplementation 'io.kubernetes:client-java:14.0.0' From 947b37e296e883a6eaf62423eb6981aa5c7cfa6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 19:46:16 +0000 Subject: [PATCH 1777/4969] Bump kubernetes-client from 5.11.0 to 5.12.1 in /modules/k3s Bumps [kubernetes-client](https://github.com/fabric8io/kubernetes-client) from 5.11.0 to 5.12.1. - [Release notes](https://github.com/fabric8io/kubernetes-client/releases) - [Changelog](https://github.com/fabric8io/kubernetes-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/fabric8io/kubernetes-client/compare/v5.11.0...v5.12.1) --- updated-dependencies: - dependency-name: io.fabric8:kubernetes-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 5007c832e7f..075078f36d9 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -8,7 +8,7 @@ dependencies { // Any >2.8 version here is not compatible with jackson-databind 2.8.x. shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' - testImplementation 'io.fabric8:kubernetes-client:5.11.0' + testImplementation 'io.fabric8:kubernetes-client:5.12.1' testImplementation 'io.kubernetes:client-java:14.0.0' testImplementation 'org.assertj:assertj-core:3.22.0' } From 6dea9789db1f970da20fc04d11eb3c5323a8bd4f Mon Sep 17 00:00:00 2001 From: Richard North Date: Fri, 4 Mar 2022 10:51:32 +0000 Subject: [PATCH 1778/4969] Fix formatting in docs for image override configuration (#5147) --- docs/features/image_name_substitution.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/features/image_name_substitution.md b/docs/features/image_name_substitution.md index 7ead811a250..f3c78c1f309 100644 --- a/docs/features/image_name_substitution.md +++ b/docs/features/image_name_substitution.md @@ -112,9 +112,10 @@ To do this, create or modify a file on the classpath named `testcontainers.prope For example: -```text tab="src/test/resources/testcontainers.properties" -image.substitutor=com.mycompany.testcontainers.ExampleImageNameSubstitutor -``` +=== "`src/test/resources/testcontainers.properties`" + ```text + image.substitutor=com.mycompany.testcontainers.ExampleImageNameSubstitutor + ``` Note that it is also possible to provide this same configuration property: @@ -130,7 +131,7 @@ Please see [the documentation on configuration mechanisms](./configuration.md) f !!! note This approach is discouraged and deprecated, but is documented for completeness. Please consider one of the other approaches outlined in this page instead. - Overriding individual image names via configuration may be removed in 2021. + Overriding individual image names via configuration may be removed in the future. Consider this if: From e12b63692d9f3922b53705041d81a9f529bc479f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Mar 2022 13:59:20 +0000 Subject: [PATCH 1779/4969] Bump actions/checkout from 2 to 3 Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-docker-wormhole.yml | 2 +- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci-rootless.yml | 2 +- .github/workflows/ci.yml | 6 +++--- .github/workflows/release.yml | 2 +- .github/workflows/update-docs-version.yml | 2 +- .github/workflows/update-gradle-wrapper.yml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index d750d8b39e0..b93d26d98bb 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -8,7 +8,7 @@ jobs: in-docker_test: runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build with Gradle run: | docker run -i --rm \ diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 3fb2467a295..a594f936a84 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -16,7 +16,7 @@ jobs: outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: java-version: '8.0.302' @@ -44,7 +44,7 @@ jobs: matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: java-version: '8.0.302' diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index 71ded85cf53..45c58c5e2d0 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -16,7 +16,7 @@ jobs: env: XDG_RUNTIME_DIR: ${{ matrix.XDG_RUNTIME_DIR }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: debug run: id -u; whoami - name: uninstall rootful Docker diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db7232fffa8..d0f57d88667 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: outputs: thundra_agent_testrun_id: ${{ steps.thundra_test_initializer.outputs.thundra_agent_testrun_id }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - id: thundra_test_initializer uses: thundra-io/thundra-test-init-action@v1 find_gradle_jobs: @@ -24,7 +24,7 @@ jobs: outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: java-version: '8.0.302' @@ -50,7 +50,7 @@ jobs: matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: java-version: '8.0.302' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f6df0dd46f4..5c786d440c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: release: runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: java-version: '8.0.302' diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 2c7626c7ec7..ef039182317 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -9,7 +9,7 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: master - name: Update latest_version property in mkdocs.yml diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 253e37c23eb..e2013d0f1b7 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Update Gradle Wrapper uses: gradle-update/update-gradle-wrapper-action@5b865a8b4d09fdf6afaaa20397ba68455bb48f0d # v1.0.13 From 5f7ded3ac202fd379f5b92bbf196b2c4e30cc6b4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 8 Mar 2022 09:08:19 -0500 Subject: [PATCH 1780/4969] Deprecate `getTestHostIpAddress` and `getContainerIpAddress()` (#5149) * Deprecate `getTestHostIpAddress` * Update docs/modules/webdriver_containers.md Co-authored-by: Richard North Co-authored-by: Richard North --- .../testcontainers/containers/Container.java | 2 ++ .../containers/ContainerState.java | 1 + .../containers/GenericContainer.java | 1 + docs/modules/webdriver_containers.md | 3 +-- .../LocalServerWebDriverContainerTest.java | 20 ++++++------------- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index 9c1cb7f8034..d9291fc9fc8 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -365,7 +365,9 @@ default SELF withClasspathResourceMapping(final String resourcePath, final Strin * from inside the container is not going to work, since the container has its own IP address. * * @return the IP address of the host machine + * @deprecated use {@link org.testcontainers.Testcontainers#exposeHostPorts(int...)} */ + @Deprecated String getTestHostIpAddress(); /** diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 7fe90bd57a4..e5903b0b806 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -44,6 +44,7 @@ public interface ContainerState { * Get the IP address that this container may be reached on (may not be the local machine). * * @return an IP address + * @deprecated use {@link #getHost()} * @see #getHost() */ default String getContainerIpAddress() { diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 22a4f0ba739..70e080711a7 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -1332,6 +1332,7 @@ public String getDockerImageName() { * {@inheritDoc} */ @Override + @Deprecated public String getTestHostIpAddress() { if (DockerMachineClient.instance().isInstalled()) { try { diff --git a/docs/modules/webdriver_containers.md b/docs/modules/webdriver_containers.md index d589aa18098..ec1dc2a407f 100644 --- a/docs/modules/webdriver_containers.md +++ b/docs/modules/webdriver_containers.md @@ -36,8 +36,7 @@ test methods: You can then use this driver instance like a regular WebDriver. Note that, if you want to test a **web application running on the host machine** (the machine the JUnit tests are -running on - which is quite likely), you'll need to replace any references to `localhost` with an IP address that the -Docker container can reach. Use the `getTestHostIpAddress()` method, e.g.: +running on - which is quite likely), you'll need to use [the host exposing](../features/networking.md#exposing-host-ports-to-the-container) feature of Testcontainers, e.g.: [Open Web Page](../../modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java) inside_block:getPage diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java index 772193e2d43..3c071984dfb 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java @@ -7,10 +7,9 @@ import org.openqa.selenium.By; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; +import org.testcontainers.Testcontainers; import org.testcontainers.containers.BrowserWebDriverContainer; -import org.testcontainers.utility.TestEnvironment; -import static org.apache.commons.lang3.SystemUtils.IS_OS_MAC_OSX; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; /** @@ -20,18 +19,11 @@ public class LocalServerWebDriverContainerTest { @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer().withCapabilities(new ChromeOptions()); + public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() + .withAccessToHost(true) + .withCapabilities(new ChromeOptions()); private int localPort; - /** - * The getTestHostIpAddress() method is only implemented for OS X running docker-machine. Skip JUnit execution elsewhere. - */ - @BeforeClass - public static void checkOS() { - Assume.assumeTrue("These tests are currently only applicable to OS X", IS_OS_MAC_OSX); - Assume.assumeTrue("These tests are only applicable to docker machine", TestEnvironment.dockerIsDockerMachine()); - } - @Before public void setupLocalServer() throws Exception { @@ -55,8 +47,8 @@ public void testConnection() { // Construct a URL that the browser container can access // getPage { - String hostIpAddress = chrome.getTestHostIpAddress(); - driver.get("http://" + hostIpAddress + ":" + localPort); + Testcontainers.exposeHostPorts(localPort); + driver.get("http://host.testcontainers.internal:" + localPort); // } String headingText = driver.findElement(By.cssSelector("h1")).getText().trim(); From affaf194f08bb1409e23996f03ad05cb3eabe943 Mon Sep 17 00:00:00 2001 From: Yannick Weber Date: Tue, 8 Mar 2022 16:24:15 +0100 Subject: [PATCH 1781/4969] replaced non-ascii single quote with ascii single quote (#5102) --- .../main/java/org/testcontainers/hivemq/HiveMQContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 342903e24af..996caad1eb8 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -354,7 +354,7 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai } if (!file.exists()) { - throw new ContainerLaunchException("File '" + mountableFile.getFilesystemPath() + "‘ does not exist."); + throw new ContainerLaunchException("File '" + mountableFile.getFilesystemPath() + "' does not exist."); } final String containerPath = "/opt/hivemq" + PathUtil.prepareAppendPath(pathInHomeFolder); withCopyFileToContainer(cloneWithFileMode(mountableFile), containerPath); From 40341d3912a2fe623adb83651c52a490734f3ab9 Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Fri, 11 Mar 2022 14:16:15 +0100 Subject: [PATCH 1782/4969] Mention that Spring Data Neo4j uses Testcontainers in the docs (#5169) * Fix Neo4j-OGM usage description. * Add Spring Data Neo4j to the "who is using"-part. --- docs/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index fdbad94b851..8749e3678cf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -176,7 +176,8 @@ A huge thank you to our sponsors: * [Instana](https://www.instana.com) - Testing agents and stream processing backends * [eBay Marketing](https://www.ebay.com) - Testing for MySQL, Cassandra, Redis, Couchbase, Kafka, etc. * [Skyscanner](https://www.skyscanner.net/) - Integration testing against HTTP service mocks and various data stores -* [Neo4j-OGM](https://neo4j.com/developer/neo4j-ogm/) - Testing new, reactive client implementations +* [Neo4j-OGM](https://neo4j.com/developer/neo4j-ogm/) - Testing with Neo4j +* [Spring Data Neo4j](https://github.com/spring-projects/spring-data-neo4j/) - Testing imperative and reactive implementations with Neo4j * [Lightbend](https://www.lightbend.com/) - Testing [Alpakka Kafka](https://doc.akka.io/docs/alpakka-kafka/current/) and support in [Alpakka Kafka Testkit](https://doc.akka.io/docs/alpakka-kafka/current/testing.html#testing-with-kafka-in-docker) * [Zalando SE](https://corporate.zalando.com/en) - Testing core business services * [Europace AG](https://tech.europace.de/) - Integration testing for databases and micro services From eea61bd9a794842aae7865e505be72a938e2a7e0 Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Thu, 17 Mar 2022 12:48:25 +0100 Subject: [PATCH 1783/4969] Use collapse-after for dependencies category (#5157) Bump release-drafter.yml --- .github/release-drafter.yml | 1 + .github/workflows/release-drafter.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 4da341055c2..07376824bf7 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -23,3 +23,4 @@ categories: - type/test-improvement - title: 📦 Dependency updates label: dependencies + collapse-after: 5 diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 05485ac57fa..839fb43df4d 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -12,6 +12,6 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@2f7ebf8ab5ef7f9835ee4b0b1eebaa2a14ca1669 # v5.15.0 + - uses: release-drafter/release-drafter@e9ee02fbac03d922bac6212003695e8358dd88b0 # v5.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e450586648f613abae00e29cb8d290a987e43a25 Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Fri, 25 Mar 2022 13:28:48 +0100 Subject: [PATCH 1784/4969] Enable Neo4j labs plugin definition. (#5035) --- docs/modules/databases/neo4j.md | 17 +++++- .../containers/Neo4jContainer.java | 41 +++++++++++++ .../containers/Neo4jLabsPlugin.java | 21 +++++++ .../containers/Neo4jContainerTest.java | 58 ++++++++++++++++++- 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jLabsPlugin.java diff --git a/docs/modules/databases/neo4j.md b/docs/modules/databases/neo4j.md index 87a5d9157d1..b6a04d2195c 100644 --- a/docs/modules/databases/neo4j.md +++ b/docs/modules/databases/neo4j.md @@ -52,6 +52,21 @@ Whole directories work as well: [Plugin folder](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:registerPluginsPath +### Add Neo4j Docker Labs plugins + +Add any Neo4j Labs plugin from the [Neo4j Docker Labs plugin list](https://neo4j.com/docs/operations-manual/4.4/docker/operations/#docker-neo4jlabs-plugins). + +!!! note + At the moment only the plugins available from the list Neo4j Docker 4.4 are supported by type. + If you want to register another supported Neo4j Labs plugin, you have to add it manually + by using the method `withLabsPlugins(String... neo4jLabsPlugins)`. + Please refer to the list of [supported Docker image plugins](https://neo4j.com/docs/operations-manual/current/docker/operations/#docker-neo4jlabs-plugins). + + +[Configure Neo4j Labs Plugins](../../../modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java) inside_block:configureLabsPlugins + + + ### Start the container with a predefined database If you have an existing database (`graph.db`) you want to work with, copy it over to the container like this: @@ -61,7 +76,7 @@ If you have an existing database (`graph.db`) you want to work with, copy it ove !!! note -The `withDatabase` method will only work with Neo4j 3.5 and throw an exception if used in combination with a newer version. + The `withDatabase` method will only work with Neo4j 3.5 and throw an exception if used in combination with a newer version. ## Choose your Neo4j license diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index f844df3f945..6f0cf10ded7 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -4,7 +4,11 @@ import static java.util.stream.Collectors.toSet; import java.time.Duration; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; @@ -60,6 +64,8 @@ public class Neo4jContainer> extends GenericContaine private String adminPassword = DEFAULT_ADMIN_PASSWORD; + private final Set labsPlugins = new HashSet<>(); + /** * Creates a Neo4jContainer using the official Neo4j docker image. * @deprecated use {@link Neo4jContainer(DockerImageName)} instead @@ -119,6 +125,15 @@ protected void configure() { boolean emptyAdminPassword = this.adminPassword == null || this.adminPassword.isEmpty(); String neo4jAuth = emptyAdminPassword ? "none" : String.format(AUTH_FORMAT, this.adminPassword); addEnv("NEO4J_AUTH", neo4jAuth); + + if (!this.labsPlugins.isEmpty()) { + String enabledPlugins = this.labsPlugins.stream() + .map(pluginName -> "\"" + pluginName + "\"") + .collect(Collectors.joining(",")); + + addEnv("NEO4JLABS_PLUGINS", "[" + enabledPlugins + "]"); + } + } /** @@ -251,6 +266,32 @@ public String getAdminPassword() { return adminPassword; } + /** + * Registers one or more {@link Neo4jLabsPlugin} for download and server startup. + + * @param neo4jLabsPlugins The Neo4j plugins that should get started with the server. + * @return This container. + */ + public S withLabsPlugins(Neo4jLabsPlugin... neo4jLabsPlugins) { + List pluginNames = Arrays.stream(neo4jLabsPlugins) + .map(plugin -> plugin.pluginName) + .collect(Collectors.toList()); + + this.labsPlugins.addAll(pluginNames); + return self(); + } + + /** + * Registers one or more {@link Neo4jLabsPlugin} for download and server startup. + + * @param neo4jLabsPlugins The Neo4j plugins that should get started with the server. + * @return This container. + */ + public S withLabsPlugins(String... neo4jLabsPlugins) { + this.labsPlugins.addAll(Arrays.asList(neo4jLabsPlugins)); + return self(); + } + private static String formatConfigurationKey(String plainConfigKey) { final String prefix = "NEO4J_"; diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jLabsPlugin.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jLabsPlugin.java new file mode 100644 index 00000000000..96c8e987c85 --- /dev/null +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jLabsPlugin.java @@ -0,0 +1,21 @@ +package org.testcontainers.containers; + +/** + * Reflects a plugin from the official Neo4j 4.4. + * Neo4j Labs Plugin list. + * There might be plugins not supported by your selected version of Neo4j. + */ +public enum Neo4jLabsPlugin { + APOC("apoc"), + APOC_CORE("apoc-core"), + BLOOM("bloom"), + STREAMS("streams"), + GRAPH_DATA_SCIENCE("graph-data-science"), + NEO_SEMANTICS("n10s"); + + final String pluginName; + + Neo4jLabsPlugin(String pluginName) { + this.pluginName = pluginName; + } +} diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java index 25924fdd6b4..0d3f04ef570 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java @@ -9,7 +9,6 @@ import org.neo4j.driver.Record; import org.neo4j.driver.Result; import org.neo4j.driver.Session; -import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; import java.util.Collections; @@ -183,6 +182,63 @@ public void shouldAddConfigToEnvironment() { .containsEntry("NEO4J_dbms_tx__log_rotation_size", "42M"); } + @Test + public void shouldConfigureSingleLabsPlugin() { + try (Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") + .withLabsPlugins(Neo4jLabsPlugin.APOC)) { + + + // needs to get called explicitly for setup + neo4jContainer.configure(); + + assertThat(neo4jContainer.getEnvMap()) + .containsEntry("NEO4JLABS_PLUGINS", "[\"apoc\"]"); + } + } + + @Test + public void shouldConfigureMultipleLabsPlugins() { + try( + // configureLabsPlugins { + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") + .withLabsPlugins(Neo4jLabsPlugin.APOC, Neo4jLabsPlugin.BLOOM); + // } + ) { + // needs to get called explicitly for setup + neo4jContainer.configure(); + + assertThat(neo4jContainer.getEnvMap().get("NEO4JLABS_PLUGINS")) + .containsAnyOf("[\"apoc\",\"bloom\"]", "[\"bloom\",\"apoc\"]"); + } + } + + @Test + public void shouldConfigureSingleLabsPluginWithString() { + try (Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") + .withLabsPlugins("myApoc")) { + + // needs to get called explicitly for setup + neo4jContainer.configure(); + + assertThat(neo4jContainer.getEnvMap()) + .containsEntry("NEO4JLABS_PLUGINS", "[\"myApoc\"]"); + } + } + + @Test + public void shouldConfigureMultipleLabsPluginsWithString() { + + try (Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") + .withLabsPlugins("myApoc", "myBloom")) { + + // needs to get called explicitly for setup + neo4jContainer.configure(); + + assertThat(neo4jContainer.getEnvMap().get("NEO4JLABS_PLUGINS")) + .containsAnyOf("[\"myApoc\",\"myBloom\"]", "[\"myBloom\",\"myApoc\"]"); + } + } + private static Driver getDriver(Neo4jContainer container) { AuthToken authToken = AuthTokens.none(); From 0545c0e1c61ba87d7bf7350ab4f9d719c46150d4 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 28 Mar 2022 11:01:43 -0400 Subject: [PATCH 1785/4969] Remove OkHttp transport (#5113) * Remove OkHttp transport * Fix OkHttp dependencies --- core/build.gradle | 1 - .../dockerclient/DockerClientProviderStrategy.java | 7 ------- modules/azure/build.gradle | 2 ++ modules/couchbase/build.gradle | 2 ++ modules/solr/build.gradle | 3 +++ 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 89028d0f9c3..558584a0d7c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -79,7 +79,6 @@ dependencies { api "com.github.docker-java:docker-java-api" shaded 'com.github.docker-java:docker-java-core' - shaded 'com.github.docker-java:docker-java-transport-okhttp' api 'com.github.docker-java:docker-java-transport-zerodep' diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index c65887b6af6..2ae066d897d 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -6,7 +6,6 @@ import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; import com.github.dockerjava.core.RemoteApiVersion; -import com.github.dockerjava.okhttp.OkDockerHttpClient; import com.github.dockerjava.transport.DockerHttpClient; import com.github.dockerjava.zerodep.ZerodepDockerHttpClient; import com.google.common.annotations.VisibleForTesting; @@ -257,12 +256,6 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) { String transportType = TestcontainersConfiguration.getInstance().getTransportType(); switch (transportType) { - case "okhttp": - dockerHttpClient = new OkDockerHttpClient.Builder() - .dockerHost(transportConfig.getDockerHost()) - .sslConfig(transportConfig.getSslConfig()) - .build(); - break; case "httpclient5": dockerHttpClient = new ZerodepDockerHttpClient.Builder() .dockerHost(transportConfig.getDockerHost()) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 7e5bc336526..b4dab636eb9 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -2,6 +2,8 @@ description = "Testcontainers :: Azure" dependencies { api project(':testcontainers') + // TODO use JDK's HTTP client and/or Apache HttpClient5 + shaded 'com.squareup.okhttp3:okhttp:3.14.9' testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'com.azure:azure-cosmos:4.26.0' diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 2c68f163a57..0245a5935cb 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -2,6 +2,8 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') + // TODO use JDK's HTTP client and/or Apache HttpClient5 + shaded 'com.squareup.okhttp3:okhttp:3.14.9' testImplementation 'com.couchbase.client:java-client:3.2.5' testImplementation 'org.awaitility:awaitility:4.1.1' diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index b3dfc9b3f92..49b2a9970f3 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -2,6 +2,9 @@ description = "Testcontainers :: Solr" dependencies { api project(':testcontainers') + // TODO use JDK's HTTP client and/or Apache HttpClient5 + shaded 'com.squareup.okhttp3:okhttp:3.14.9' + testImplementation 'org.apache.solr:solr-solrj:8.11.1' } From 6414df1288b0ec9c1e707aeb34c200a191cca74e Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 28 Mar 2022 17:12:09 +0200 Subject: [PATCH 1786/4969] Update mkdocs to 1.3.0 (#5186) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8f4a1a5f100..f77d057b599 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -mkdocs==1.2.3 +mkdocs==1.3.0 mkdocs-codeinclude-plugin==0.2.0 mkdocs-material==8.1.3 mkdocs-markdownextradata-plugin==0.2.5 From 02782d9cb711baebaa504bc00669acdd84e10e51 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 28 Mar 2022 11:13:47 -0400 Subject: [PATCH 1787/4969] Replace deprecated `checkAndPullImage` with `RemoteDockerImage` (#5148) * Replace deprecated `checkAndPullImage` with `RemoteDockerImage` * fix `runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally` * Remove `LoggerFactory` usage * avoid name substitution in `DockerComposeContainer`/`ImageFromDockerfile` * fix `AuthenticatedImagePullTest` * remove accidential `@Ignore` * fix indentation * put `clearCache` after `catch()` --- .../testcontainers/DockerClientFactory.java | 22 +++++++++---------- .../containers/DockerComposeContainer.java | 6 ++++- .../images/LocalImagesCache.java | 3 ++- .../images/RemoteDockerImage.java | 9 +++++--- .../images/builder/ImageFromDockerfile.java | 7 +++++- .../utility/ImageNameSubstitutor.java | 17 ++++++++++++++ .../utility/RyukResourceReaper.java | 8 +++---- .../DockerClientFactoryTest.java | 10 +++++++-- .../images/LocalImagesCacheAccessor.java | 9 ++++++++ .../utility/AuthenticatedImagePullTest.java | 2 ++ .../containers/localstack/LegacyModeTest.java | 9 ++------ 11 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/images/LocalImagesCacheAccessor.java diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 9a6165ef55f..4cbe81f9e2d 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -25,10 +25,10 @@ import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; import org.testcontainers.dockerclient.TransportConfig; +import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.ImageNameSubstitutor; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.ResourceReaper; import org.testcontainers.utility.RyukResourceReaper; @@ -236,7 +236,6 @@ public void close() { checkDiskSpace(client, ryukContainerId); } else { runInsideDocker( - client, createContainerCmd -> { createContainerCmd.withName("testcontainers-checks-" + SESSION_ID); createContainerCmd.getHostConfig().withAutoRemove(true); @@ -335,9 +334,12 @@ private boolean checkMountableFile() { } /** - * Check whether the image is available locally and pull it otherwise - */ + * Check whether the image is available locally and pull it otherwise + * + * @deprecated use {@link RemoteDockerImage} + */ @SneakyThrows + @Deprecated public void checkAndPullImage(DockerClient client, String image) { try { client.inspectImageCmd(image).exec(); @@ -363,18 +365,14 @@ public String dockerHostIpAddress() { } public T runInsideDocker(Consumer createContainerCmdConsumer, BiFunction block) { - // We can't use client() here because it might create an infinite loop - return runInsideDocker(getOrInitializeStrategy().getDockerClient(), createContainerCmdConsumer, block); + return runInsideDocker(TINY_IMAGE, createContainerCmdConsumer, block); } - private T runInsideDocker(DockerClient client, Consumer createContainerCmdConsumer, BiFunction block) { - - final String tinyImage = ImageNameSubstitutor.instance().apply(TINY_IMAGE).asCanonicalNameString(); - - checkAndPullImage(client, tinyImage); + T runInsideDocker(DockerImageName imageName, Consumer createContainerCmdConsumer, BiFunction block) { + RemoteDockerImage dockerImage = new RemoteDockerImage(imageName); HashMap labels = new HashMap<>(DEFAULT_LABELS); labels.putAll(ResourceReaper.instance().getLabels()); - CreateContainerCmd createContainerCmd = client.createContainerCmd(tinyImage) + CreateContainerCmd createContainerCmd = client.createContainerCmd(dockerImage.get()) .withLabels(labels); createContainerCmdConsumer.accept(createContainerCmd); String id = createContainerCmd.exec().getId(); diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index b8913e8ac7c..4db9361a618 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -25,12 +25,14 @@ import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.dockerclient.TransportConfig; +import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.lifecycle.Startable; import org.testcontainers.utility.AuditLogger; import org.testcontainers.utility.Base58; import org.testcontainers.utility.CommandLine; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.DockerLoggerFactory; +import org.testcontainers.utility.ImageNameSubstitutor; import org.testcontainers.utility.LogUtils; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.PathUtils; @@ -186,7 +188,9 @@ private void pullImages() { .forEach(imageName -> { try { log.info("Preemptively checking local images for '{}', referenced via a compose file or transitive Dockerfile. If not available, it will be pulled.", imageName); - DockerClientFactory.instance().checkAndPullImage(dockerClient, imageName); + new RemoteDockerImage(DockerImageName.parse(imageName)) + .withImageNameSubstitutor(ImageNameSubstitutor.noop()) + .get(); } catch (Exception e) { log.warn("Unable to pre-fetch an image ({}) depended upon by Docker Compose build - startup will continue but may fail. Exception message was: {}", imageName, e.getMessage()); } diff --git a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java index ec371ef830e..ec38721a229 100644 --- a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java +++ b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java @@ -21,7 +21,8 @@ enum LocalImagesCache { INSTANCE; - private final AtomicBoolean initialized = new AtomicBoolean(false); + @VisibleForTesting + final AtomicBoolean initialized = new AtomicBoolean(false); @VisibleForTesting final Map cache = new ConcurrentHashMap<>(); diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index 4ce38124fe7..3bf2243549a 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -10,7 +10,7 @@ import lombok.NonNull; import lombok.SneakyThrows; import lombok.ToString; -import lombok.experimental.Wither; +import lombok.With; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.ContainerFetchException; @@ -34,9 +34,12 @@ public class RemoteDockerImage extends LazyFuture { @ToString.Exclude private Future imageNameFuture; - @Wither + @With private ImagePullPolicy imagePullPolicy = PullPolicy.defaultPolicy(); + @With + private ImageNameSubstitutor imageNameSubstitutor = ImageNameSubstitutor.instance(); + @ToString.Exclude private DockerClient dockerClient = DockerClientFactory.lazyClient(); @@ -115,7 +118,7 @@ private DockerImageName getImageName() throws InterruptedException, ExecutionExc final DockerImageName specifiedImageName = imageNameFuture.get(); // Allow the image name to be substituted - return ImageNameSubstitutor.instance().apply(specifiedImageName); + return imageNameSubstitutor.apply(specifiedImageName); } @ToString.Include(name = "imageName", rank = 1) diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index abf13f8ef02..281a74feaba 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -13,13 +13,16 @@ import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.images.ParsedDockerfile; +import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.images.builder.traits.BuildContextBuilderTrait; import org.testcontainers.images.builder.traits.ClasspathTrait; import org.testcontainers.images.builder.traits.DockerfileTrait; import org.testcontainers.images.builder.traits.FilesTrait; import org.testcontainers.images.builder.traits.StringsTrait; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.DockerLoggerFactory; +import org.testcontainers.utility.ImageNameSubstitutor; import org.testcontainers.utility.LazyFuture; import org.testcontainers.utility.ResourceReaper; @@ -172,7 +175,9 @@ private void prePullDependencyImages(Set imagesToPull) { imagesToPull.forEach(imageName -> { try { log.info("Pre-emptively checking local images for '{}', referenced via a Dockerfile. If not available, it will be pulled.", imageName); - DockerClientFactory.instance().checkAndPullImage(dockerClient, imageName); + new RemoteDockerImage(DockerImageName.parse(imageName)) + .withImageNameSubstitutor(ImageNameSubstitutor.noop()) + .get(); } catch (Exception e) { log.warn("Unable to pre-fetch an image ({}) depended upon by Dockerfile - image build will continue but may fail. Exception message was: {}", imageName, e.getMessage()); } diff --git a/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java index 645b717a562..a1cb2492204 100644 --- a/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java +++ b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java @@ -53,6 +53,10 @@ public synchronized static ImageNameSubstitutor instance() { return instance; } + public static ImageNameSubstitutor noop() { + return new NoopImageNameSubstitutor(); + } + private static ImageNameSubstitutor wrapWithLogging(final ImageNameSubstitutor wrappedInstance) { return new LogWrappedImageNameSubstitutor(wrappedInstance); } @@ -127,4 +131,17 @@ protected String getDescription() { ); } } + + private static class NoopImageNameSubstitutor extends ImageNameSubstitutor { + + @Override + public DockerImageName apply(DockerImageName original) { + return original; + } + + @Override + protected String getDescription() { + return "No-op substitutor"; + } + } } diff --git a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java index 743b33856cf..9efbf5ed972 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java @@ -17,6 +17,7 @@ import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.ContainerState; +import org.testcontainers.images.RemoteDockerImage; import java.io.IOException; import java.net.InetSocketAddress; @@ -85,16 +86,13 @@ private synchronized void maybeStart() { return; } DockerClient client = DockerClientFactory.lazyClient(); - String ryukImage = ImageNameSubstitutor.instance() - .apply(DockerImageName.parse("testcontainers/ryuk:0.3.3")) - .asCanonicalNameString(); - DockerClientFactory.instance().checkAndPullImage(client, ryukImage); + RemoteDockerImage ryukImage = new RemoteDockerImage(DockerImageName.parse("testcontainers/ryuk:0.3.3")); List binds = new ArrayList<>(); binds.add(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); ExposedPort ryukExposedPort = ExposedPort.tcp(8080); - containerId = client.createContainerCmd(ryukImage) + containerId = client.createContainerCmd(ryukImage.get()) .withHostConfig( new HostConfig() .withAutoRemove(true) diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index 16d25b2f625..4dcfc26349f 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.testcontainers.TestImages.TINY_IMAGE; import com.github.dockerjava.api.exception.NotFoundException; import org.junit.Rule; @@ -10,6 +9,8 @@ import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory.DiskSpaceUsage; import org.testcontainers.dockerclient.LogToStringContainerCallback; +import org.testcontainers.images.LocalImagesCacheAccessor; +import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MockTestcontainersConfigurationRule; /** @@ -24,16 +25,21 @@ public class DockerClientFactoryTest { public void runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally() { final DockerClientFactory dockFactory = DockerClientFactory.instance(); + + DockerImageName imageName = DockerImageName.parse("testcontainers/helloworld:1.1.0"); + try { //remove tiny image, so it will be pulled during next command run dockFactory.client() - .removeImageCmd(TINY_IMAGE.asCanonicalNameString()) + .removeImageCmd(imageName.asCanonicalNameString()) .withForce(true).exec(); } catch (NotFoundException ignored) { // Do not fail if it's not pulled yet } + LocalImagesCacheAccessor.clearCache(); dockFactory.runInsideDocker( + imageName, cmd -> cmd.withCmd("sh", "-c", "echo 'SUCCESS'"), (client, id) -> client.logContainerCmd(id) diff --git a/core/src/test/java/org/testcontainers/images/LocalImagesCacheAccessor.java b/core/src/test/java/org/testcontainers/images/LocalImagesCacheAccessor.java new file mode 100644 index 00000000000..4e7a28c535a --- /dev/null +++ b/core/src/test/java/org/testcontainers/images/LocalImagesCacheAccessor.java @@ -0,0 +1,9 @@ +package org.testcontainers.images; + +public final class LocalImagesCacheAccessor { + + public static synchronized void clearCache() { + LocalImagesCache.INSTANCE.cache.clear(); + LocalImagesCache.INSTANCE.initialized.set(false); + } +} diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index c57c1d7c0b6..412a945b204 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -17,6 +17,7 @@ import org.testcontainers.containers.ContainerState; import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.images.LocalImagesCacheAccessor; import org.testcontainers.images.builder.ImageFromDockerfile; import java.io.IOException; @@ -93,6 +94,7 @@ public void removeImageFromLocalDocker() { } catch (NotFoundException ignored) { } + LocalImagesCacheAccessor.clearCache(); } @AfterClass diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java index b8f2ec1aae0..b34f43f79ed 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java @@ -8,6 +8,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.DockerClientFactory; +import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.utility.DockerImageName; import java.util.Arrays; @@ -72,15 +73,9 @@ public static class On { @BeforeClass public static void createCustomTag() { DockerClient dockerClient = DockerClientFactory.instance().client(); - DockerClientFactory - .instance() - .checkAndPullImage( - dockerClient, - LOCALSTACK_0_12_IMAGE.asCanonicalNameString() - ); dockerClient .tagImageCmd( - LOCALSTACK_0_12_IMAGE.asCanonicalNameString(), + new RemoteDockerImage(LOCALSTACK_0_12_IMAGE).get(), LOCALSTACK_CUSTOM_TAG.getRepository(), LOCALSTACK_CUSTOM_TAG.getVersionPart() ) From 5bbffb6c9962807fc0c54180d29f2aa4d3deaa86 Mon Sep 17 00:00:00 2001 From: Yannick Weber Date: Tue, 29 Mar 2022 14:08:46 +0200 Subject: [PATCH 1788/4969] Improved jitpack dependencies page (#5189) --- docs/jitpack_dependencies.md | 61 ++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/docs/jitpack_dependencies.md b/docs/jitpack_dependencies.md index 7689772de92..23a4c7353ad 100644 --- a/docs/jitpack_dependencies.md +++ b/docs/jitpack_dependencies.md @@ -3,22 +3,51 @@ If you like to live on the bleeding edge, [jitpack.io](https://jitpack.io) can be used to obtain SNAPSHOT versions. Use the following dependency description instead: -```xml - - com.github.testcontainers.testcontainers-java - --artifact name-- - -SNAPSHOT - -``` +=== "Gradle" + ```groovy + testImplementation "com.github.testcontainers.testcontainers-java:--artifact name--:master-SNAPSHOT" + ``` +=== "Maven" + ```xml + + com.github.testcontainers.testcontainers-java + --artifact name-- + master-SNAPSHOT + + ``` -A specific git revision (such as `093a3a4628`) can be used as a fixed version instead. The JitPack maven repository must also be declared, e.g.: +A specific git revision (such as `02782d9`) can be used as a fixed version instead: -```xml - - - jitpack.io - https://jitpack.io - - -``` +=== "Gradle" + ```groovy + testImplementation "com.github.testcontainers.testcontainers-java:--artifact name--:02782d9" + ``` +=== "Maven" + ```xml + + com.github.testcontainers.testcontainers-java + --artifact name-- + 02782d9 + + ``` + +The JitPack maven repository must also be declared, e.g.: + +=== "Gradle" + ```groovy + repositories { + maven { + url "https://jitpack.io" + } + } + ``` +=== "Maven" + ```xml + + + jitpack.io + https://jitpack.io + + + ``` From 04ecb68363596d8feb37fd2d4fcf3233031582eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Prinet?= Date: Wed, 30 Mar 2022 19:36:41 +0200 Subject: [PATCH 1789/4969] Improve Gradle build cacheability (#5188) * Bump up Gradle plugins version * Allow cache relocatability for Delombok task * Declare Delombok task inputs/outputs inside DelombokArgumentProvider --- build.gradle | 12 +++------ .../build/DelombokArgumentProvider.groovy | 26 +++++++++++++++++++ settings.gradle | 4 +-- 3 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 buildSrc/src/main/groovy/org/testcontainers/build/DelombokArgumentProvider.groovy diff --git a/build.gradle b/build.gradle index 8fb15a6566f..309743477c1 100644 --- a/build.gradle +++ b/build.gradle @@ -43,18 +43,14 @@ subprojects { version = '1.18.20' } + task delombok(type: io.franzbecker.gradle.lombok.task.DelombokTask) { - def outputDir = file("$buildDir/delombok") - outputs.dir(outputDir) outputs.cacheIf { true } - for (srcDir in project.sourceSets.main.java.srcDirs) { - // TODO: named input and relative path for `srcDir` to make task more cacheable - inputs.dir(srcDir) - // TODO: `outputDir` as relative path to make task more cacheable - args(srcDir, "-d", outputDir, "-f", "generateDelombokComment:skip") - } + argumentProviders.addAll( + new org.testcontainers.build.DelombokArgumentProvider(srcDirs: project.sourceSets.main.java.srcDirs, outputDir: file("$buildDir/delombok")) + ) } delombok.onlyIf { project.sourceSets.main.java.srcDirs.find { it.exists() } diff --git a/buildSrc/src/main/groovy/org/testcontainers/build/DelombokArgumentProvider.groovy b/buildSrc/src/main/groovy/org/testcontainers/build/DelombokArgumentProvider.groovy new file mode 100644 index 00000000000..2cb4931eb58 --- /dev/null +++ b/buildSrc/src/main/groovy/org/testcontainers/build/DelombokArgumentProvider.groovy @@ -0,0 +1,26 @@ +package org.testcontainers.build + +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity +import org.gradle.process.CommandLineArgumentProvider + +/** + * Allows build cache relocatability for Delombok task + */ +class DelombokArgumentProvider implements CommandLineArgumentProvider { + + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + Set srcDirs + + @OutputDirectory + File outputDir + + @Override + Iterable asArguments() { + return [srcDirs.collect { it.absolutePath }.join(" "), "-d", outputDir.absolutePath, "-f", "generateDelombokComment:skip"] + } + +} diff --git a/settings.gradle b/settings.gradle index e4c65186fb8..64f2aa5d70a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,8 +5,8 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.2" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.9" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.5" } } From 457b583df82bc5e778b95276aaf6ad1fc0297dfe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 11:29:13 +0200 Subject: [PATCH 1790/4969] Update Gradle Wrapper to 7.4.1 (#5168) Signed-off-by: gradle-update-robot Co-authored-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 1debed0d8fd..ffe61b45c92 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=8cc27038d5dbd815759851ba53e70cf62e481b87494cc97cfd97982ada5ba634 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionSha256Sum=e5444a57cda4a95f90b0c9446a9e1b47d3d7f69057765bfb54bd4f482542d548 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index dcf5e2cb7b3..db3bccc1f9b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=cd5c2958a107ee7f0722004a12d0f8559b4564c34daad7df06cffd4d12a426d0 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionSha256Sum=a9a7b7baba105f6557c9dcf9c3c6e8f7e57e6b49889c5f1d133f015d0727e4be +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 0408db806f6d57b8117881adcd10b6bd6c9dcd9c Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Thu, 31 Mar 2022 11:30:10 +0200 Subject: [PATCH 1791/4969] Add virtual environment to git ignore (#5156) GitHub Codespaces auto detects Pipfile and starts installing dependencies into .venv/ Signed-off-by: Joseph Petersen --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d6a9a697796..95fc6e52000 100644 --- a/.gitignore +++ b/.gitignore @@ -66,4 +66,7 @@ src/pip-delete-this-directory.txt .DS_Store # Codespaces / VSCode -/.vscode/ \ No newline at end of file +/.vscode/ + +# Python virtual environment +/.venv/ From 9712d25aa899bc306287daffe77bdf28b64c57b4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 08:47:22 +0200 Subject: [PATCH 1792/4969] Update Gradle Wrapper to 7.4.2 (#5193) Signed-off-by: gradle-update-robot Co-authored-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index ffe61b45c92..5c51a4acc9d 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=e5444a57cda4a95f90b0c9446a9e1b47d3d7f69057765bfb54bd4f482542d548 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip +distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index db3bccc1f9b..e1e0c8dc42b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=a9a7b7baba105f6557c9dcf9c3c6e8f7e57e6b49889c5f1d133f015d0727e4be -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip +distributionSha256Sum=e6d864e3b5bc05cc62041842b306383fc1fefcec359e70cebb1d470a6094ca82 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 297621fe4ab0a775d8dc2bf4f869fbed61dac95e Mon Sep 17 00:00:00 2001 From: Yannick Weber Date: Fri, 1 Apr 2022 13:50:18 +0200 Subject: [PATCH 1793/4969] Added tmpFs usage for HiveMQ module (#5109) Improves performance for IO heavy operations --- .../org/testcontainers/hivemq/HiveMQContainer.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 996caad1eb8..5bb8935c39e 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -18,6 +18,7 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -77,6 +78,16 @@ public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { }); } }); + + final HashMap tmpFs = new HashMap<>(); + if (dockerImageName.isCompatibleWith(DEFAULT_HIVEMQ_EE_IMAGE_NAME)) { + tmpFs.put("/opt/hivemq/audit", "rw"); + tmpFs.put("/opt/hivemq/backup", "rw"); + } + + tmpFs.put("/opt/hivemq/log", "rw"); + tmpFs.put("/opt/hivemq/data", "rw"); + withTmpFs(tmpFs); } @Override From 498dac062d628a63c9755492bcdbc13afbddc040 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:38 +0000 Subject: [PATCH 1794/4969] Bump tomcat-jdbc from 10.0.16 to 10.0.20 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.16 to 10.0.20. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index bf90d9603a2..5c10742b7f7 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.16' + api 'org.apache.tomcat:tomcat-jdbc:10.0.20' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.28' } From 913efe9e73ecf7a7a332e4f1ef33cd6214b56ced Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:39 +0000 Subject: [PATCH 1795/4969] Bump tomcat-jdbc from 10.0.16 to 10.0.20 in /modules/jdbc Bumps tomcat-jdbc from 10.0.16 to 10.0.20. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 71940e0026a..84b927ac4a9 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.16' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.20' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 95fec38a2cac0f4fe9e5cbdfdad6dbb46e68e6d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:41 +0000 Subject: [PATCH 1796/4969] Bump aws-java-sdk-s3 from 1.12.169 to 1.12.191 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.169 to 1.12.191. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.169...1.12.191) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c16baad9a22..ccd322f0952 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.169' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.191' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.169' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.150' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.169' From a4587abe04ce78e3f54abe28b95927d69ceb23de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:41 +0000 Subject: [PATCH 1797/4969] Bump neo4j-java-driver from 4.4.3 to 4.4.5 in /modules/neo4j Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 4.4.3 to 4.4.5. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/4.4.3...4.4.5) --- updated-dependencies: - dependency-name: org.neo4j.driver:neo4j-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 27bf38b9f23..6187d665098 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -33,6 +33,6 @@ dependencies { api project(":testcontainers") - testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.3' + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.5' testImplementation 'org.assertj:assertj-core:3.22.0' } From 9216980323e5fbc4bd81f82058025a876d4240c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:42 +0000 Subject: [PATCH 1798/4969] Bump rest-assured from 4.5.1 to 5.0.0 in /modules/vault Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 4.5.1 to 5.0.0. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-4.5.1...rest-assured-5.0.0) --- updated-dependencies: - dependency-name: io.rest-assured:rest-assured dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index ce000685a10..68daf4ed26f 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.bettercloud:vault-java-driver:5.1.0' - testImplementation 'io.rest-assured:rest-assured:4.5.1' + testImplementation 'io.rest-assured:rest-assured:5.0.0' testImplementation 'org.assertj:assertj-core:3.22.0' } From e7afcec5a09789bade7e4a808edf6f6eaf1dbc5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:43 +0000 Subject: [PATCH 1799/4969] Bump java-client from 3.2.5 to 3.2.6 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.2.5 to 3.2.6. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.2.5...java-client-3.2.6) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 0245a5935cb..a3cb0fcbc70 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:3.14.9' - testImplementation 'com.couchbase.client:java-client:3.2.5' + testImplementation 'com.couchbase.client:java-client:3.2.6' testImplementation 'org.awaitility:awaitility:4.1.1' } From 3ff87f5bdeee8256195fb7b87a801a3eef7a35c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:44 +0000 Subject: [PATCH 1800/4969] Bump jedis from 4.1.1 to 4.2.1 in /examples Bumps [jedis](https://github.com/redis/jedis) from 4.1.1 to 4.2.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v4.1.1...v4.2.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index ec3d0bd134c..38a8715364a 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:4.1.1' + implementation 'redis.clients:jedis:4.2.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 32e35f07766..9583fe99147 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:4.1.1' + implementation 'redis.clients:jedis:4.2.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 2ebaba5be50..e8d470f0f23 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:4.1.1' + implementation 'redis.clients:jedis:4.2.1' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From cce236c67ff09ca88aacf4435bd740ebac4f166b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:45 +0000 Subject: [PATCH 1801/4969] Bump mockito-core from 4.3.1 to 4.4.0 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 4.3.1 to 4.4.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.3.1...v4.4.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 749bf72690d..89882481dc1 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:4.1.1' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:4.3.1') { + testImplementation ('org.mockito:mockito-core:4.4.0') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.22.0' From 156971e69538d73d6a3d4ec1c0bd992b636ee3ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:46 +0000 Subject: [PATCH 1802/4969] Bump transport from 7.17.1 to 7.17.2 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.17.1 to 7.17.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/master/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.17.1...v7.17.2) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index d669f0fbd05..a8d718af3c4 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2" - testImplementation "org.elasticsearch.client:transport:7.17.1" + testImplementation "org.elasticsearch.client:transport:7.17.2" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 03fa998e2ea9cfabe5d9921f76c96dc82c0be2e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:47 +0000 Subject: [PATCH 1803/4969] Bump logback-classic from 1.2.10 to 1.2.11 in /examples Bumps logback-classic from 1.2.10 to 1.2.11. --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 1639a091e91..2352eace899 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.10' + testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 2e37410bcea..7ba974d3a6d 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:3.1.0' testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.10' + testImplementation 'ch.qos.logback:logback-classic:1.2.11' } diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 1cb3a0285f2..c61ce36e473 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'org.json:json:20211205' testImplementation 'org.postgresql:postgresql:42.3.3' - testImplementation 'ch.qos.logback:logback-classic:1.2.10' + testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:postgresql' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index ec3d0bd134c..bc1d30d9599 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'ch.qos.logback:logback-classic:1.2.10' + testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testng:testng:7.5' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 32e35f07766..f2d5830404d 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -13,6 +13,6 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testImplementation 'ch.qos.logback:logback-classic:1.2.10' + testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 2ebaba5be50..2879ddb4fdd 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' - testImplementation 'ch.qos.logback:logback-classic:1.2.10' + testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From cb58298c4ef96968ce6e0f654d9f87d2a7b56126 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:47 +0000 Subject: [PATCH 1804/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.6.10 to 1.6.20. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 45cee0ec20b..1d98c3e3eff 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.6.4" id("org.jetbrains.kotlin.jvm") version "1.6.10" - id("org.jetbrains.kotlin.plugin.spring") version "1.6.10" + id("org.jetbrains.kotlin.plugin.spring") version "1.6.20" } apply plugin: 'io.spring.dependency-management' From 58f70290f0a77c11fa3538cab671dd94b149afdb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:48 +0000 Subject: [PATCH 1805/4969] Bump awaitility from 4.1.1 to 4.2.0 in /core Bumps [awaitility](https://github.com/awaitility/awaitility) from 4.1.1 to 4.2.0. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.1.1...awaitility-4.2.0) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 558584a0d7c..c17169977cc 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -71,7 +71,7 @@ dependencies { exclude(group: 'org.jetbrains', module: 'annotations') } - shaded 'org.awaitility:awaitility:4.1.1' + shaded 'org.awaitility:awaitility:4.2.0' api platform('com.github.docker-java:docker-java-bom:3.2.13') shaded platform('com.github.docker-java:docker-java-bom:3.2.13') From 02dec3edf4408a43e5060ce0a639f5ab0043dc54 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:51 +0000 Subject: [PATCH 1806/4969] Bump s3 from 2.17.108 to 2.17.162 in /modules/localstack Bumps s3 from 2.17.108 to 2.17.162. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c16baad9a22..401230dbb61 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.169' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.150' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.169' - testImplementation 'software.amazon.awssdk:s3:2.17.108' + testImplementation 'software.amazon.awssdk:s3:2.17.162' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 285ce0efe024f2c33d62069d2e89eeb277b7a272 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:00:52 +0000 Subject: [PATCH 1807/4969] Bump neo4j-java-driver from 4.4.3 to 4.4.5 in /examples Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 4.4.3 to 4.4.5. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/4.4.3...4.4.5) --- updated-dependencies: - dependency-name: org.neo4j.driver:neo4j-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/neo4j-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/neo4j-container/build.gradle b/examples/neo4j-container/build.gradle index 718adc3183a..652937d8b33 100644 --- a/examples/neo4j-container/build.gradle +++ b/examples/neo4j-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { testImplementation 'org.assertj:assertj-core:3.22.0' - testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.3' + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.5' testImplementation 'org.testcontainers:neo4j' testImplementation 'org.testcontainers:junit-jupiter' } From 16fb27f651a7d1cd66881238cfa99e2433e483eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:01:23 +0000 Subject: [PATCH 1808/4969] Bump actions/cache from 2.1.7 to 3.0.1 Bumps [actions/cache](https://github.com/actions/cache) from 2.1.7 to 3.0.1. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v2.1.7...v3.0.1) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 3fb2467a295..7b9a9e5c3a1 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -22,7 +22,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.1 continue-on-error: true with: path: ~/.gradle/caches @@ -50,7 +50,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.1 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db7232fffa8..4fad892230d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.1 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -56,7 +56,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.1 continue-on-error: true with: path: ~/.gradle/caches From 6f2eb5c6105d2cf5fb9b0e927223f594fdcf9ab8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:01:29 +0000 Subject: [PATCH 1809/4969] Bump peter-evans/create-pull-request from 3.12.1 to 4.0.1 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 3.12.1 to 4.0.1. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/f22a7da129c901513876a2380e2dae9f8e145330...f1a7646cead32c950d90344a4fb5d4e926972a8f) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 2c7626c7ec7..ceb2385e986 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -17,7 +17,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@f22a7da129c901513876a2380e2dae9f8e145330 # v3.10.1 + uses: peter-evans/create-pull-request@f1a7646cead32c950d90344a4fb5d4e926972a8f # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From a4695120eb1c3f49a030f686e5747c7506251e69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:04:58 +0000 Subject: [PATCH 1810/4969] Bump r2dbc-postgresql in /modules/r2dbc Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.11.RELEASE to 0.8.12.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.12.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.11.RELEASE...v0.8.12.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 2fa066c21b3..ee5f5844e56 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -12,7 +12,7 @@ dependencies { api 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE' testImplementation 'org.assertj:assertj-core:3.22.0' - testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' + testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' testImplementation project(':postgresql') testFixturesImplementation 'io.projectreactor:reactor-core:3.4.15' From b00d7c2ced538f9b1ff004a4f67e6a01ac25a32d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:04:59 +0000 Subject: [PATCH 1811/4969] Bump trino-jdbc from 369 to 375 in /modules/trino Bumps trino-jdbc from 369 to 375. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index 9bf0e24f06b..f99951dc7fa 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:369' + testImplementation 'io.trino:trino-jdbc:375' compileOnly 'org.jetbrains:annotations:23.0.0' } From 0bc42f61c149e5d79cdbccec95ad19638cc056d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:04:59 +0000 Subject: [PATCH 1812/4969] Bump okhttp from 3.14.9 to 4.9.3 in /modules/solr Bumps [okhttp](https://github.com/square/okhttp) from 3.14.9 to 4.9.3. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-3.14.9...parent-4.9.3) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/solr/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index 49b2a9970f3..5a6326f3844 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Solr" dependencies { api project(':testcontainers') // TODO use JDK's HTTP client and/or Apache HttpClient5 - shaded 'com.squareup.okhttp3:okhttp:3.14.9' + shaded 'com.squareup.okhttp3:okhttp:4.9.3' testImplementation 'org.apache.solr:solr-solrj:8.11.1' From 1cdac6a748e3a80802d3c0432efc512c45491b77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:05:00 +0000 Subject: [PATCH 1813/4969] Bump client-java from 14.0.0 to 15.0.0 in /modules/k3s Bumps [client-java](https://github.com/kubernetes-client/java) from 14.0.0 to 15.0.0. - [Release notes](https://github.com/kubernetes-client/java/releases) - [Changelog](https://github.com/kubernetes-client/java/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes-client/java/compare/client-java-parent-14.0.0...v15.0.0) --- updated-dependencies: - dependency-name: io.kubernetes:client-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 075078f36d9..a373d8115d7 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -9,6 +9,6 @@ dependencies { shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' testImplementation 'io.fabric8:kubernetes-client:5.12.1' - testImplementation 'io.kubernetes:client-java:14.0.0' + testImplementation 'io.kubernetes:client-java:15.0.0' testImplementation 'org.assertj:assertj-core:3.22.0' } From 5a3881995369330b216773af9fcc1ebf9d98e9ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:05:01 +0000 Subject: [PATCH 1814/4969] Bump google-cloud-bigtable from 2.5.2 to 2.6.1 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.5.2 to 2.6.1. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.5.2...v2.6.1) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index e0b232ac949..93111ef3f16 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.0.14' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.2' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.6.1' testImplementation 'org.assertj:assertj-core:3.22.0' } From 0cc5b67ef8ce32ec0978eaffbf94628824fd7476 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:05:01 +0000 Subject: [PATCH 1815/4969] Bump mongodb-driver-sync from 4.5.0 to 4.5.1 in /modules/mongodb Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.5.0 to 4.5.1. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.5.0...r4.5.1) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mongodb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index 73dba45dbbf..6bca2cb892b 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: MongoDB" dependencies { api project(':testcontainers') - testImplementation("org.mongodb:mongodb-driver-sync:4.5.0") + testImplementation("org.mongodb:mongodb-driver-sync:4.5.1") } From b9adf8717210a5bc42e850f03722970fbe692409 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:05:02 +0000 Subject: [PATCH 1816/4969] Bump reactor-core from 3.4.15 to 3.4.16 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.15 to 3.4.16. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.15...v3.4.16) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 2fa066c21b3..56e910910d1 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.15' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.16' testFixturesImplementation 'org.assertj:assertj-core:3.14.0' } From 8973288c81fb249f80c308e1ec6fbe466b52d237 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:05:12 +0000 Subject: [PATCH 1817/4969] Bump google-cloud-firestore from 3.0.14 to 3.0.21 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.0.14 to 3.0.21. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.0.14...v3.0.21) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index e0b232ac949..cdc07d77c37 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.2.2' - testImplementation 'com.google.cloud:google-cloud-firestore:3.0.14' + testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.5.2' From fe7782c028875eb166982387a2011520aae5ebf7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:05:33 +0000 Subject: [PATCH 1818/4969] Bump hivemq-extension-sdk from 4.7.4 to 4.7.5 in /modules/hivemq Bumps [hivemq-extension-sdk](https://github.com/hivemq/hivemq-extension-sdk) from 4.7.4 to 4.7.5. - [Release notes](https://github.com/hivemq/hivemq-extension-sdk/releases) - [Commits](https://github.com/hivemq/hivemq-extension-sdk/compare/4.7.4...4.7.5) --- updated-dependencies: - dependency-name: com.hivemq:hivemq-extension-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index f0c3aaa2e69..17be5658992 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -13,7 +13,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") testImplementation(project(":junit-jupiter")) - testImplementation("com.hivemq:hivemq-extension-sdk:4.7.4") + testImplementation("com.hivemq:hivemq-extension-sdk:4.7.5") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.10") From 64f96781c518b75fddc98bbad05b234faec7169f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:05:35 +0000 Subject: [PATCH 1819/4969] Bump zip4j from 2.9.1 to 2.10.0 in /modules/hivemq Bumps [zip4j](https://github.com/srikanth-lingala/zip4j) from 2.9.1 to 2.10.0. - [Release notes](https://github.com/srikanth-lingala/zip4j/releases) - [Commits](https://github.com/srikanth-lingala/zip4j/compare/v2.9.1...v2.10.0) --- updated-dependencies: - dependency-name: net.lingala.zip4j:zip4j dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index f0c3aaa2e69..79c59bba0d2 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -9,7 +9,7 @@ dependencies { shaded("org.javassist:javassist:3.28.0-GA") shaded("org.jboss.shrinkwrap:shrinkwrap-api:1.2.6") shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") - shaded("net.lingala.zip4j:zip4j:2.9.1") + shaded("net.lingala.zip4j:zip4j:2.10.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") testImplementation(project(":junit-jupiter")) From 06fc95f5233b0c11d2ba319b4b02587db0b5028b Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 6 Apr 2022 17:01:03 +0200 Subject: [PATCH 1820/4969] Fix ScriptUtils.runInitScript() in hierarchical classloader setup by using TCCL (#5167) --- .../main/java/org/testcontainers/ext/ScriptUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java index 76f0cb90ea0..1b94b84f368 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java @@ -293,10 +293,13 @@ public static boolean containsSqlScriptDelimiters(String script, String delim) { */ public static void runInitScript(DatabaseDelegate databaseDelegate, String initScriptPath) { try { - URL resource = ScriptUtils.class.getClassLoader().getResource(initScriptPath); + URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath); if (resource == null) { - LOGGER.warn("Could not load classpath init script: {}", initScriptPath); - throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath + ". Resource not found."); + resource = ScriptUtils.class.getClassLoader().getResource(initScriptPath); + if (resource == null) { + LOGGER.warn("Could not load classpath init script: {}", initScriptPath); + throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath + ". Resource not found."); + } } String scripts = IOUtils.toString(resource, StandardCharsets.UTF_8); executeDatabaseScript(databaseDelegate, initScriptPath, scripts); From 734678f4be9e9a439b4391265d5f369ed1bab4b5 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 7 Apr 2022 09:29:04 +0200 Subject: [PATCH 1821/4969] Deperecate `getContainerIpAddress` (#5247) --- .../main/java/org/testcontainers/containers/ContainerState.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index e5903b0b806..ef2c19a06c9 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -47,6 +47,7 @@ public interface ContainerState { * @deprecated use {@link #getHost()} * @see #getHost() */ + @Deprecated default String getContainerIpAddress() { return getHost(); } From 53e80aa4115b60eee11823b5aa7d3616065a9421 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Thu, 7 Apr 2022 18:03:27 +0200 Subject: [PATCH 1822/4969] Fix incorrect path for RABBITMQ_CONFIG_FILE (#5184) Co-authored-by: Kevin Wittek --- .../containers/RabbitMQContainer.java | 2 +- .../containers/RabbitMQContainerTest.java | 24 +++++++------------ .../src/test/resources/logback-test.xml | 16 +++++++++++++ .../src/test/resources/rabbitmq-custom.conf | 3 +-- .../src/test/resources/rabbitmq-custom.config | 18 ++++++-------- 5 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 modules/rabbitmq/src/test/resources/logback-test.xml diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index edbffcf3174..37dc2fbe7ca 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -396,7 +396,7 @@ public RabbitMQContainer withRabbitMQConfig(MountableFile rabbitMQConf) { * @return This container. */ public RabbitMQContainer withRabbitMQConfigSysctl(MountableFile rabbitMQConf) { - withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom"); + withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom.conf"); return withCopyFileToContainer(rabbitMQConf, "/etc/rabbitmq/rabbitmq-custom.conf"); } diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index 8be97deb710..474d613cb8b 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -14,6 +14,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -21,6 +22,8 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Collections; +import java.util.Objects; +import java.util.Scanner; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; @@ -115,43 +118,34 @@ public void shouldCreateRabbitMQContainerWithQueues() throws IOException, Interr } @Test - public void shouldMountConfigurationFile() - { + public void shouldMountConfigurationFile() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { - container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); container.start(); - assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.conf"); - assertThat(container.getLogs()).doesNotContain(" (not found)"); + assertThat(container.getLogs()).contains("debug"); // config file changes log level to `debug` } } @Test - public void shouldMountConfigurationFileErlang() - { + public void shouldMountConfigurationFileErlang() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { - container.withRabbitMQConfigErlang(MountableFile.forClasspathResource("/rabbitmq-custom.config")); container.start(); - assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.config"); - assertThat(container.getLogs()).doesNotContain(" (not found)"); + assertThat(container.getLogs()).contains("debug"); // config file changes log level to `debug` } } @Test - public void shouldMountConfigurationFileSysctl() - { + public void shouldMountConfigurationFileSysctl() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { - container.withRabbitMQConfigSysctl(MountableFile.forClasspathResource("/rabbitmq-custom.conf")); container.start(); - assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.conf"); - assertThat(container.getLogs()).doesNotContain(" (not found)"); + assertThat(container.getLogs()).contains("debug"); // config file changes log level to `debug` } } diff --git a/modules/rabbitmq/src/test/resources/logback-test.xml b/modules/rabbitmq/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/rabbitmq/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf b/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf index 293829a353b..a2994c78602 100644 --- a/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf +++ b/modules/rabbitmq/src/test/resources/rabbitmq-custom.conf @@ -1,2 +1 @@ -loopback_users.guest = false -listeners.tcp.default = 5555 +log.console.level = debug diff --git a/modules/rabbitmq/src/test/resources/rabbitmq-custom.config b/modules/rabbitmq/src/test/resources/rabbitmq-custom.config index a1c581542ce..353a854fc42 100644 --- a/modules/rabbitmq/src/test/resources/rabbitmq-custom.config +++ b/modules/rabbitmq/src/test/resources/rabbitmq-custom.config @@ -1,13 +1,9 @@ [ -{ rabbit, [ -{ loopback_users, [ ] }, - { tcp_listeners, [ 5555 ] }, - { ssl_listeners, [ ] }, - { default_vhost, <<"vhost">> }, - { hipe_compile, false } - ] }, - { rabbitmq_management, [ { listener, [ - { port, 15672 }, - { ssl, false } - ] } ] } +{rabbit, + [ + {log, + [{console, [{level, debug}]}] + } + ] +} ]. From c7449edda49ff780921067c4a03014ce68b2aa41 Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Fri, 8 Apr 2022 09:16:53 +0200 Subject: [PATCH 1823/4969] Elasticsearch: Ensure Elasticsearch 8 works OOTB secure as default (#5099) Since Elasticsearch 8.0 the default is to enable security, meaning TLS and authentication. This adds a check for Elasticsearch 8.0 to change the default behaviour to properly support this change, but you can still run Elasticsearch with security features disabled, if you want. Co-authored-by: Kevin Wittek Co-authored-by: Sergei Egorov --- .../elasticsearch/ElasticsearchContainer.java | 96 +++++++++++++++---- .../ElasticsearchContainerTest.java | 38 ++++++-- 2 files changed, 111 insertions(+), 23 deletions(-) diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index acbca15aaf5..84881b2e87d 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -1,21 +1,33 @@ package org.testcontainers.elasticsearch; -import static java.net.HttpURLConnection.HTTP_OK; -import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; - -import java.net.InetSocketAddress; -import java.time.Duration; +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.apache.commons.io.IOUtils; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.ByteArrayInputStream; +import java.net.InetSocketAddress; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.Optional; + /** * Represents an elasticsearch docker instance which exposes by default port 9200 and 9300 (transport.tcp.port) * The docker image is by default fetched from docker.elastic.co/elasticsearch/elasticsearch */ public class ElasticsearchContainer extends GenericContainer { + /** + * Elasticsearch Default Password for Elasticsearch >= 8 + */ + public static final String ELASTICSEARCH_DEFAULT_PASSWORD = "changeme"; + /** * Elasticsearch Default HTTP port */ @@ -39,7 +51,10 @@ public class ElasticsearchContainer extends GenericContainer caCertAsBytes = Optional.empty(); /** * @deprecated use {@link ElasticsearchContainer(DockerImageName)} instead @@ -65,23 +80,67 @@ public ElasticsearchContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, DEFAULT_OSS_IMAGE_NAME); - - if (dockerImageName.isCompatibleWith(DEFAULT_OSS_IMAGE_NAME)) { - this.isOss = true; - } + this.isOss = dockerImageName.isCompatibleWith(DEFAULT_OSS_IMAGE_NAME); logger().info("Starting an elasticsearch container using [{}]", dockerImageName); withNetworkAliases("elasticsearch-" + Base58.randomString(6)); withEnv("discovery.type", "single-node"); addExposedPorts(ELASTICSEARCH_DEFAULT_PORT, ELASTICSEARCH_DEFAULT_TCP_PORT); - setWaitStrategy(new HttpWaitStrategy() - .forPort(ELASTICSEARCH_DEFAULT_PORT) - .forStatusCodeMatching(response -> response == HTTP_OK || response == HTTP_UNAUTHORIZED) - .withStartupTimeout(Duration.ofMinutes(2))); + this.isAtLeastMajorVersion8 = new ComparableVersion(dockerImageName.getVersionPart()).isGreaterThanOrEqualTo("8.0.0"); + // regex that + // matches 8.0 JSON logging with no whitespace between message field and content + // matches 7.x JSON logging with whitespace between message field and content + // matches 6.x text logging with node name in brackets and just a 'started' message till the end of the line + String regex = ".*(\"message\":\\s?\"started\".*|] started\n$)"; + setWaitStrategy(new LogMessageWaitStrategy().withRegEx(regex)); + if (isAtLeastMajorVersion8) { + withPassword(ELASTICSEARCH_DEFAULT_PASSWORD); + } + } + + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + if (isAtLeastMajorVersion8) { + byte[] bytes = copyFileFromContainer("/usr/share/elasticsearch/config/certs/http_ca.crt", IOUtils::toByteArray); + if (bytes.length > 0) { + this.caCertAsBytes = Optional.of(bytes); + } + } + } + + /** + * If this is running above Elasticsearch 8, this will return the probably self-signed CA cert that has been extracted + * + * @return byte array optional containing the CA cert extracted from the docker container + */ + public Optional caCertAsBytes() { + return caCertAsBytes; } /** - * Define the Elasticsearch password to set. It enables security behind the scene. + * A SSL context based on the self signed CA, so that using this SSL Context allows to connect to the Elasticsearch service + * @return a customized SSL Context + */ + public SSLContext createSslContextFromCa() { + try { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + Certificate trustedCa = factory.generateCertificate(new ByteArrayInputStream(caCertAsBytes.get())); + KeyStore trustStore = KeyStore.getInstance("pkcs12"); + trustStore.load(null, null); + trustStore.setCertificateEntry("ca", trustedCa); + + final SSLContext sslContext = SSLContext.getInstance("TLSv1.3"); + TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmfactory.init(trustStore); + sslContext.init(null, tmfactory.getTrustManagers(), null); + return sslContext; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Define the Elasticsearch password to set. It enables security behind the scene for major version below 8.0.0. * It's not possible to use security with the oss image. * @param password Password to set * @return this @@ -92,7 +151,10 @@ public ElasticsearchContainer withPassword(String password) { "Please switch to the default distribution"); } withEnv("ELASTIC_PASSWORD", password); - withEnv("xpack.security.enabled", "true"); + if (!isAtLeastMajorVersion8) { + // major version 8 is secure by default and does not need this to enable authentication + withEnv("xpack.security.enabled", "true"); + } return this; } diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 859587645d7..956c794135b 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -1,11 +1,5 @@ package org.testcontainers.elasticsearch; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; - -import java.io.IOException; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -25,6 +19,13 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import java.io.IOException; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; + public class ElasticsearchContainerTest { /** @@ -249,6 +250,31 @@ public void incompatibleSettingsTest() { ); } + @Test + public void testElasticsearch8SecureByDefault() throws Exception { + try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.0.0")) { + // Start the container. This step might take some time... + container.start(); + + // Create the secured client. + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)); + + client = RestClient.builder(HttpHost.create("https://" + container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> { + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + httpClientBuilder.setSSLContext(container.createSslContextFromCa()); + return httpClientBuilder; + }) + .build(); + + Response response = client.performRequest(new Request("GET", "/_cluster/health")); + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + } + } + private RestClient getClient(ElasticsearchContainer container) { if (client == null) { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); From d93dceae969b63645b07881e80a61c57e3ca564b Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Fri, 8 Apr 2022 16:02:00 +0200 Subject: [PATCH 1824/4969] Allow to create a file in container from a Transferable (#3814) (#3815) Co-authored-by: Alex Stockinger Co-authored-by: Sergei Egorov Co-authored-by: Kevin Wittek --- core/build.gradle | 2 + .../testcontainers/containers/Container.java | 15 +++- .../containers/GenericContainer.java | 53 ++++++----- .../images/builder/Transferable.java | 15 ++++ .../testcontainers/utility/MountableFile.java | 26 ++++++ .../containers/GenericContainerTest.java | 36 ++++++++ .../containers/ReusabilityUnitTests.java | 87 +++++++++++++++---- 7 files changed, 193 insertions(+), 41 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index c17169977cc..3f1ad71731d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -45,6 +45,8 @@ tasks.japicmp { "org.testcontainers.utility.ResourceReaper#start(com.github.dockerjava.api.DockerClient)", "org.testcontainers.utility.ResourceReaper#registerNetworkForCleanup(java.lang.String)", "org.testcontainers.utility.ResourceReaper#removeNetworks(java.lang.String)", + "org.testcontainers.images.builder.Transferable#of(java.lang.String)", + "org.testcontainers.images.builder.Transferable#updateChecksum(java.util.zip.Checksum)" ] fieldExcludes = [] diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index d9291fc9fc8..8fd53fc5a0e 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -12,6 +12,7 @@ import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.LogUtils; import org.testcontainers.utility.MountableFile; @@ -169,11 +170,23 @@ default SELF withFileSystemBind(String hostPath, String containerPath) { * Set the file to be copied before starting a created container * * @param mountableFile a Mountable file with path of source file / folder on host machine - * @param containerPath a destination path on conatiner to which the files / folders to be copied + * @param containerPath a destination path on container to which the files / folders to be copied * @return this + * + * @deprecated Use {@link #withCopyToContainer(Transferable, String)} instead */ + @Deprecated SELF withCopyFileToContainer(MountableFile mountableFile, String containerPath); + /** + * Set the content to be copied before starting a created container + * + * @param transferable a Transferable + * @param containerPath a destination path on container to which the files / folders to be copied + * @return this + */ + SELF withCopyToContainer(Transferable transferable, String containerPath); + /** * Add an environment variable to be passed to the container. * diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 70e080711a7..d47bc6cfc5e 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -23,6 +23,7 @@ import com.google.common.hash.Hashing; import lombok.AccessLevel; import lombok.Data; +import lombok.Getter; import lombok.NonNull; import lombok.Setter; import lombok.SneakyThrows; @@ -49,6 +50,7 @@ import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.images.RemoteDockerImage; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.lifecycle.Startable; import org.testcontainers.lifecycle.Startables; import org.testcontainers.lifecycle.TestDescription; @@ -186,8 +188,15 @@ public class GenericContainer> private Long shmSize; // Maintain order in which entries are added, as earlier target location may be a prefix of a later location. + @Deprecated private Map copyToFileContainerPathMap = new LinkedHashMap<>(); + // Maintain order in which entries are added, as earlier target location may be a prefix of a later location. + @Setter(AccessLevel.NONE) + @Getter(AccessLevel.MODULE) + @VisibleForTesting + private Map copyToTransferableContainerPathMap = new LinkedHashMap<>(); + protected final Set dependencies = new HashSet<>(); /** @@ -415,6 +424,8 @@ private void tryStart(Instant startedAt) { // TODO use single "copy" invocation (and calculate an hash of the resulting tar archive) copyToFileContainerPathMap.forEach(this::copyFileToContainer); + + copyToTransferableContainerPathMap.forEach(this::copyFileToContainer); } connectToPortForwardingNetwork(createCommand.getNetworkMode()); @@ -530,33 +541,18 @@ private void tryStart(Instant startedAt) { @VisibleForTesting Checksum hashCopiedFiles() { Checksum checksum = new Adler32(); - copyToFileContainerPathMap.entrySet().stream().sorted(Entry.comparingByValue()).forEach(entry -> { - byte[] pathBytes = entry.getValue().getBytes(); - // Add path to the hash - checksum.update(pathBytes, 0, pathBytes.length); - - File file = new File(entry.getKey().getResolvedPath()); - checksumFile(file, checksum); - }); + Stream.of(copyToFileContainerPathMap, copyToTransferableContainerPathMap) + .flatMap(it -> it.entrySet().stream()) + .sorted(Entry.comparingByValue()).forEach(entry -> { + byte[] pathBytes = entry.getValue().getBytes(); + // Add path to the hash + checksum.update(pathBytes, 0, pathBytes.length); + + entry.getKey().updateChecksum(checksum); + }); return checksum; } - @VisibleForTesting - @SneakyThrows(IOException.class) - void checksumFile(File file, Checksum checksum) { - Path path = file.toPath(); - checksum.update(MountableFile.getUnixFileMode(path)); - if (file.isDirectory()) { - try (Stream stream = Files.walk(path)) { - stream.filter(it -> it != path).forEach(it -> { - checksumFile(it.toFile(), checksum); - }); - } - } else { - FileUtils.checksum(file, checksum); - } - } - @UnstableAPI @SneakyThrows(JsonProcessingException.class) final String hash(CreateContainerCmd createCommand) { @@ -1296,6 +1292,15 @@ public SELF withCopyFileToContainer(MountableFile mountableFile, String containe return self(); } + /** + * {@inheritDoc} + */ + @Override + public SELF withCopyToContainer(Transferable transferable, String containerPath) { + copyToTransferableContainerPathMap.put(transferable, containerPath); + return self(); + } + /** * Get the IP address that this container may be reached on (may not be the local machine). * diff --git a/core/src/main/java/org/testcontainers/images/builder/Transferable.java b/core/src/main/java/org/testcontainers/images/builder/Transferable.java index 3f068f98a18..8ec26c8c3da 100644 --- a/core/src/main/java/org/testcontainers/images/builder/Transferable.java +++ b/core/src/main/java/org/testcontainers/images/builder/Transferable.java @@ -5,12 +5,18 @@ import org.apache.commons.io.IOUtils; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.zip.Checksum; public interface Transferable { int DEFAULT_FILE_MODE = 0100644; int DEFAULT_DIR_MODE = 040755; + static Transferable of(String string) { + return of(string.getBytes(StandardCharsets.UTF_8)); + } + static Transferable of(byte[] bytes) { return of(bytes, DEFAULT_FILE_MODE); } @@ -27,6 +33,11 @@ public byte[] getBytes() { return bytes; } + @Override + public void updateChecksum(Checksum checksum) { + checksum.update(bytes, 0, bytes.length); + } + @Override public int getFileMode() { return fileMode; @@ -78,4 +89,8 @@ default byte[] getBytes() { default String getDescription() { return ""; } + + default void updateChecksum(Checksum checksum) { + throw new UnsupportedOperationException("Provide implementation in subclass"); + } } diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 19dca4c134c..81cc37adeab 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -1,12 +1,15 @@ package org.testcontainers.utility; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarConstants; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.DockerClientFactory; @@ -28,6 +31,8 @@ import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.stream.Stream; +import java.util.zip.Checksum; import static lombok.AccessLevel.PACKAGE; import static org.testcontainers.utility.PathUtils.recursiveDeleteDir; @@ -361,6 +366,27 @@ public String getDescription() { return this.getResolvedPath(); } + @Override + public void updateChecksum(Checksum checksum) { + File file = new File(getResolvedPath()); + checksumFile(file, checksum); + } + + @SneakyThrows(IOException.class) + private void checksumFile(File file, Checksum checksum) { + Path path = file.toPath(); + checksum.update(MountableFile.getUnixFileMode(path)); + if (file.isDirectory()) { + try (Stream stream = Files.walk(path)) { + stream.filter(it -> it != path).forEach(it -> { + checksumFile(it.toFile(), checksum); + }); + } + } else { + FileUtils.checksum(file, checksum); + } + } + @Override public int getFileMode() { return getUnixFileMode(this.getResolvedPath()); diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 93a9cd96479..0c30d522cd9 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -20,7 +20,11 @@ import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; +import org.testcontainers.images.builder.Transferable; + +import java.nio.charset.StandardCharsets; import org.testcontainers.images.builder.ImageFromDockerfile; +import org.testcontainers.utility.MountableFile; import java.util.Arrays; import java.util.List; @@ -75,6 +79,38 @@ public void shouldReportErrorAfterWait() { } } + @Test + public void shouldCopyTransferableAsFile() { + try ( + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) + .withStartupCheckStrategy(new NoopStartupCheckStrategy()) + .withCopyToContainer(Transferable.of("test"), "/tmp/test") + .waitingFor(new WaitForExitedState(state -> state.getExitCodeLong() > 0)) + .withCommand("sh", "-c", "grep -q test /tmp/test && exit 100") + ) { + assertThatThrownBy(container::start) + .hasStackTraceContaining("Container exited with code 100"); + } + } + + @Test + public void shouldCopyTransferableAfterMountableFile() { + try ( + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) + .withStartupCheckStrategy(new NoopStartupCheckStrategy()) + .withCopyFileToContainer( + MountableFile.forClasspathResource("test_copy_to_container.txt"), + "/tmp/test" + ) + .withCopyToContainer(Transferable.of("test"), "/tmp/test") + .waitingFor(new WaitForExitedState(state -> state.getExitCodeLong() > 0)) + .withCommand("sh", "-c", "grep -q test /tmp/test && exit 100") + ) { + assertThatThrownBy(container::start) + .hasStackTraceContaining("Container exited with code 100"); + } + } + @Test public void shouldOnlyPublishExposedPorts() { ImageFromDockerfile image = new ImageFromDockerfile("publish-multiple") diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 0540fcdba9d..9aad97d7e7b 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -10,7 +10,6 @@ import com.github.dockerjava.api.command.ListContainersCmd; import com.github.dockerjava.api.command.StartContainerCmd; import com.github.dockerjava.api.model.Container; -import com.github.dockerjava.api.model.NetworkSettings; import com.github.dockerjava.core.command.CreateContainerCmdImpl; import com.github.dockerjava.core.command.InspectContainerCmdImpl; import com.github.dockerjava.core.command.ListContainersCmdImpl; @@ -24,13 +23,13 @@ import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.Parameterized; import org.mockito.Answers; -import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.MockTestcontainersConfigurationRule; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.TestcontainersConfiguration; @@ -39,12 +38,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -297,11 +298,65 @@ public void shouldHashCopiedFiles() { } } - @RunWith(BlockJUnit4ClassRunner.class) + @RunWith(Parameterized.class) @FieldDefaults(makeFinal = true) public static class CopyFilesHashTest { + private final TestStrategy strategy; + + interface TestStrategy { + void withCopyFileToContainer(MountableFile mountableFile, String path); + + void clear(); + } + + private static class MountableFileTestStrategy implements TestStrategy { + private final GenericContainer container; + + private MountableFileTestStrategy(GenericContainer container) { + this.container = container; + } + + @Override + public void withCopyFileToContainer(MountableFile mountableFile, String path) { + container.withCopyFileToContainer(mountableFile, path); + } + + @Override + public void clear() { + container.getCopyToFileContainerPathMap().clear(); + } + } + + private static class TransferableTestStrategy implements TestStrategy { + private final GenericContainer container; + + private TransferableTestStrategy(GenericContainer container) { + this.container = container; + } + + @Override + public void withCopyFileToContainer(MountableFile mountableFile, String path) { + container.withCopyToContainer(mountableFile, path); + } + + @Override + public void clear() { + container.getCopyToTransferableContainerPathMap().clear(); + } + } + + @Parameterized.Parameters + public static List, TestStrategy>> strategies() { + return Arrays.asList(MountableFileTestStrategy::new, TransferableTestStrategy::new); + } + + GenericContainer container = new GenericContainer<>(TINY_IMAGE); + public CopyFilesHashTest(Function, TestStrategy> strategyFactory) { + this.strategy = strategyFactory.apply(container); + } + @Test public void empty() { assertThat(container.hashCopiedFiles()).isNotNull(); @@ -311,7 +366,7 @@ public void empty() { public void oneFile() { long emptyHash = container.hashCopiedFiles().getValue(); - container.withCopyFileToContainer( + strategy.withCopyFileToContainer( MountableFile.forClasspathResource("test_copy_to_container.txt"), "/foo/bar" ); @@ -322,13 +377,13 @@ public void oneFile() { @Test public void differentPath() { MountableFile mountableFile = MountableFile.forClasspathResource("test_copy_to_container.txt"); - container.withCopyFileToContainer(mountableFile, "/foo/bar"); + strategy.withCopyFileToContainer(mountableFile, "/foo/bar"); long hash1 = container.hashCopiedFiles().getValue(); - container.getCopyToFileContainerPathMap().clear(); + strategy.clear(); - container.withCopyFileToContainer(mountableFile, "/foo/baz"); + strategy.withCopyFileToContainer(mountableFile, "/foo/baz"); assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(hash1); } @@ -337,7 +392,7 @@ public void differentPath() { public void detectsChangesInFile() throws Exception { Path path = File.createTempFile("reusable_test", ".txt").toPath(); MountableFile mountableFile = MountableFile.forHostPath(path); - container.withCopyFileToContainer(mountableFile, "/foo/bar"); + strategy.withCopyFileToContainer(mountableFile, "/foo/bar"); long hash1 = container.hashCopiedFiles().getValue(); @@ -348,13 +403,13 @@ public void detectsChangesInFile() throws Exception { @Test public void multipleFiles() { - container.withCopyFileToContainer( + strategy.withCopyFileToContainer( MountableFile.forClasspathResource("test_copy_to_container.txt"), "/foo/bar" ); long hash1 = container.hashCopiedFiles().getValue(); - container.withCopyFileToContainer( + strategy.withCopyFileToContainer( MountableFile.forClasspathResource("mappable-resource/test-resource.txt"), "/foo/baz" ); @@ -368,7 +423,7 @@ public void folder() throws Exception { Path tempDirectory = Files.createTempDirectory("reusable_test"); MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); - container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + strategy.withCopyFileToContainer(mountableFile, "/foo/bar/"); assertThat(container.hashCopiedFiles().getValue()).isNotEqualTo(emptyHash); } @@ -378,7 +433,7 @@ public void changesInFolder() throws Exception { Path tempDirectory = Files.createTempDirectory("reusable_test"); MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); - container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + strategy.withCopyFileToContainer(mountableFile, "/foo/bar/"); long hash1 = container.hashCopiedFiles().getValue(); @@ -397,11 +452,11 @@ public void folderAndFile() throws Exception { Path tempDirectory = Files.createTempDirectory("reusable_test"); MountableFile mountableFile = MountableFile.forHostPath(tempDirectory); assertThat(new File(mountableFile.getResolvedPath())).isDirectory(); - container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + strategy.withCopyFileToContainer(mountableFile, "/foo/bar/"); long hash1 = container.hashCopiedFiles().getValue(); - container.withCopyFileToContainer( + strategy.withCopyFileToContainer( MountableFile.forClasspathResource("test_copy_to_container.txt"), "/foo/baz" ); @@ -414,7 +469,7 @@ public void filePermissions() throws Exception { Path path = File.createTempFile("reusable_test", ".txt").toPath(); path.toFile().setExecutable(false); MountableFile mountableFile = MountableFile.forHostPath(path); - container.withCopyFileToContainer(mountableFile, "/foo/bar"); + strategy.withCopyFileToContainer(mountableFile, "/foo/bar"); long hash1 = container.hashCopiedFiles().getValue(); @@ -432,7 +487,7 @@ public void folderPermissions() throws Exception { Path subDir = Files.createDirectory(tempDirectory.resolve("sub")); subDir.toFile().setWritable(false); assumeThat(subDir.toFile().canWrite()).isFalse(); - container.withCopyFileToContainer(mountableFile, "/foo/bar/"); + strategy.withCopyFileToContainer(mountableFile, "/foo/bar/"); long hash1 = container.hashCopiedFiles().getValue(); From 17407eff6ef3343ee0c2d52e9306d40708909c43 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 8 Apr 2022 16:45:17 +0200 Subject: [PATCH 1825/4969] Increase default client ping timeout from 5 to 10 seconds (#5254) --- .../org/testcontainers/utility/TestcontainersConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index c6ce7496dd9..c9dfd543ad6 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -198,7 +198,7 @@ public String getImageSubstitutorClassName() { } public Integer getClientPingTimeout() { - return Integer.parseInt(getEnvVarOrProperty("client.ping.timeout", "5")); + return Integer.parseInt(getEnvVarOrProperty("client.ping.timeout", "10")); } @Nullable From af835694bb617fb1ef8d5eb1aa438ced68bcab7b Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 12 Apr 2022 19:27:32 +0200 Subject: [PATCH 1826/4969] Update images and theme for testcontainers.org (#5258) --- docs/css/extra.css | 14 +++---- docs/favicon.ico | Bin 15086 -> 15406 bytes docs/logo.png | Bin 51964 -> 84934 bytes docs/logo.svg | 99 +++++++++++++++++++++++++++++++++++++++++---- mkdocs.yml | 7 ++-- 5 files changed, 102 insertions(+), 18 deletions(-) diff --git a/docs/css/extra.css b/docs/css/extra.css index d7e7e6b68a3..4c11e3df748 100644 --- a/docs/css/extra.css +++ b/docs/css/extra.css @@ -1,10 +1,10 @@ -@import url('https://fonts.googleapis.com/css?family=Inconsolata|Lato|Merriweather+Sans|Open+Sans|Source+Sans+Pro'); -body { - font-family: 'Lato', sans-serif; +@import url('https://fonts.googleapis.com/css?family=Rubik'); +h1, h2, h3, h4, h5, h6 { + font-family: 'Rubik', sans-serif; } -.md-typeset pre { - font-family: 'Inconsolata', monospace; - font-size: 100%; -} \ No newline at end of file +[data-md-color-scheme="testcontainers"] { + --md-primary-fg-color: #291A3F; + --md-accent-fg-color: #291A3F; +} diff --git a/docs/favicon.ico b/docs/favicon.ico index 004282385c3e9b51ece573d194b64693145dc2e1..311a0acaa373f197360673f8ac6bc1b3c38c7e7f 100644 GIT binary patch literal 15406 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 EAH!e_G5`Po diff --git a/docs/logo.png b/docs/logo.png index 696e03ad6ff360ce03647928910996169e329b4f..3d8f03fa0cf0fb98578e83d9b2ff71de3ead11c0 100644 GIT binary patch literal 84934 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 Gg8vr^t7`)Q diff --git a/docs/logo.svg b/docs/logo.svg index 3a8db707fc8..bac0c391a59 100644 --- a/docs/logo.svg +++ b/docs/logo.svg @@ -1,9 +1,92 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mkdocs.yml b/mkdocs.yml index 7ace7382e41..16b2106bb3f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,9 +7,10 @@ theme: name: 'material' custom_dir: 'docs/theme' palette: - primary: 'blue' - accent: 'teal' - font: false + scheme: testcontainers + font: + text: Roboto + code: Roboto Mono logo: 'logo.svg' favicon: 'favicon.ico' extra_css: From cec49348c70615a3a0b5243d10b8f5c30d3b5697 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 13 Apr 2022 13:07:28 +0200 Subject: [PATCH 1827/4969] Update release docs to contain milestone rename step --- RELEASING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASING.md b/RELEASING.md index 4ad91b56477..f04839d9d41 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -16,7 +16,8 @@ Testcontainers' release process is semi-automated through GitHub Actions. This d 7. Close the release in Sonatype. This will evaluate the release based on given Sonatype rules. 8. After successful closing, the release button needs to be clicked and afterwards it is automatically synced to Maven Central. 9. Handcraft and polish some of the release notes (e.g. substitute combinded dependency PRs and highlight certain features). -10. When available through Maven Central, poke [Richard North](https://github.com/rnorth) to announce the release on Twitter! +10. Rename existing milestone corresponding to new release and close it. Then create a new `next` milstestone. +11. When available through Maven Central, poke [Richard North](https://github.com/rnorth) to announce the release on Twitter! ## Internal details From 66e4be2817f82aa80490c21e8df9e8f8a87fa792 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Wed, 13 Apr 2022 07:27:38 -0400 Subject: [PATCH 1828/4969] Fix `StackOverflowError` in `DockerClientFactory#client` (#5262) --- core/src/main/java/org/testcontainers/DockerClientFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 4cbe81f9e2d..6cf8f716704 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -187,7 +187,6 @@ public DockerClient client() { final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); - log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); client = new DockerClientDelegate() { @Getter @@ -198,6 +197,7 @@ public void close() { throw new IllegalStateException("You should never close the global DockerClient!"); } }; + log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); Info dockerInfo = client.infoCmd().exec(); Version version = client.versionCmd().exec(); From 1113cd4cd4a7356c6e745a59c4a6b6711ac55458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 19 Apr 2022 18:02:53 -0500 Subject: [PATCH 1829/4969] Rely on `TransportConfig` to read `DOCKER_HOST` env variable for `DockerComposeContainer` (#5276) `TransportConfig` is already aware of `DOCKER_HOST`. --- .../containers/DockerComposeContainer.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 4db9361a618..c0f84307c88 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -726,20 +726,17 @@ public void invoke() { final Map environment = Maps.newHashMap(env); environment.put(ENV_PROJECT_NAME, identifier); - String dockerHost = System.getenv("DOCKER_HOST"); - if (dockerHost == null) { - TransportConfig transportConfig = DockerClientFactory.instance().getTransportConfig(); - SSLConfig sslConfig = transportConfig.getSslConfig(); - if (sslConfig != null) { - if (sslConfig instanceof LocalDirectorySSLConfig) { - environment.put("DOCKER_CERT_PATH", ((LocalDirectorySSLConfig) sslConfig).getDockerCertPath()); - environment.put("DOCKER_TLS_VERIFY", "true"); - } else { - logger().warn("Couldn't set DOCKER_CERT_PATH. `sslConfig` is present but it's not LocalDirectorySSLConfig."); - } + TransportConfig transportConfig = DockerClientFactory.instance().getTransportConfig(); + SSLConfig sslConfig = transportConfig.getSslConfig(); + if (sslConfig != null) { + if (sslConfig instanceof LocalDirectorySSLConfig) { + environment.put("DOCKER_CERT_PATH", ((LocalDirectorySSLConfig) sslConfig).getDockerCertPath()); + environment.put("DOCKER_TLS_VERIFY", "true"); + } else { + logger().warn("Couldn't set DOCKER_CERT_PATH. `sslConfig` is present but it's not LocalDirectorySSLConfig."); } - dockerHost = transportConfig.getDockerHost().toString(); } + String dockerHost = transportConfig.getDockerHost().toString(); environment.put("DOCKER_HOST", dockerHost); final Stream absoluteDockerComposeFilePaths = composeFiles.stream() From bb6b5c5489825398461bf9e0e8d180fde9c15eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 20 Apr 2022 08:13:04 -0500 Subject: [PATCH 1830/4969] Use `getHost` instead of `getContainerIpAddress()` (#5277) `getContainerIpAddress` is deprecated. --- .../src/test/java/DisqueBackedMailSenderTest.java | 2 +- .../src/test/java/SingleDisqueInstanceTest.java | 2 +- .../java/com/example/linkedcontainer/RedmineContainer.java | 2 +- .../org/testcontainers/containers/MongoDbContainerTest.java | 2 +- .../src/test/java/RedisBackedCacheTest.java | 2 +- .../src/test/java/RedisBackedCacheTest.java | 2 +- .../src/test/java/com/example/BarConcreteTestClass.java | 2 +- .../src/test/java/com/example/FooConcreteTestClass.java | 2 +- .../src/test/java/com/example/SolrQueryTest.java | 2 +- .../testcontainers/containers/DatastoreEmulatorContainer.java | 2 +- .../testcontainers/containers/FirestoreEmulatorContainer.java | 2 +- .../testcontainers/containers/PubSubEmulatorContainer.java | 2 +- .../testcontainers/containers/SpannerEmulatorContainer.java | 4 ++-- .../java/org/testcontainers/containers/MongoDBContainer.java | 2 +- .../org/testcontainers/containers/PostgreSQLContainer.java | 2 +- .../java/org/testcontainers/containers/SolrContainer.java | 4 ++-- .../java/org/testcontainers/containers/SolrContainerTest.java | 4 ++-- 17 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java b/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java index add59fd15ba..4da6201eecb 100644 --- a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java +++ b/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java @@ -36,7 +36,7 @@ public class DisqueBackedMailSenderTest { @Before public void setup() { context(""); - disqueClient = new DisqueClient(DisqueURI.create(container.getContainerIpAddress(), container.getMappedPort(7711))); + disqueClient = new DisqueClient(DisqueURI.create(container.getHost(), container.getMappedPort(7711))); mockMailApiClient = mock(MailApiClient.class); service = new DisqueBackedMailSenderService(disqueClient, mockMailApiClient); diff --git a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java b/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java index 3fa115bea20..7ded5d8da43 100644 --- a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java +++ b/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java @@ -30,7 +30,7 @@ public class SingleDisqueInstanceTest { @Before public void setup() { context(""); - DisqueClient client = new DisqueClient(DisqueURI.create(container.getContainerIpAddress(), container.getMappedPort(7711))); + DisqueClient client = new DisqueClient(DisqueURI.create(container.getHost(), container.getMappedPort(7711))); connection = client.connect().sync(); retryAfter1Second = AddJobArgs.builder().retry(1, TimeUnit.SECONDS).build(); diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java index a75867205ab..4303bbee682 100644 --- a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java @@ -29,7 +29,7 @@ public RedmineContainer withLinkToContainer(LinkableContainer otherContainer, St public String getRedmineUrl() { return String.format("http://%s:%d", - this.getContainerIpAddress(), + this.getHost(), this.getMappedPort(REDMINE_PORT)); } } diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java index 7c87e46bccd..5581c76e675 100644 --- a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java +++ b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java @@ -19,7 +19,7 @@ public void containerStartsAndPublicPortIsAvailable() { private void assertThatPortIsAvailable(MongoDbContainer container) { try { - new Socket(container.getContainerIpAddress(), container.getPort()); + new Socket(container.getHost(), container.getPort()); } catch (IOException e) { throw new AssertionError("The expected port " + container.getPort() + " is not available!"); } diff --git a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java index 5d204cf99c4..927f097aa5f 100644 --- a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java @@ -35,7 +35,7 @@ public static void stopContainer() { @BeforeMethod public void setUp() { - Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getMappedPort(6379)); + Jedis jedis = new Jedis(redis.getHost(), redis.getMappedPort(6379)); cache = new RedisBackedCache(jedis, "test"); } diff --git a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java index d9d93b8255e..aa4199684e8 100644 --- a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java @@ -25,7 +25,7 @@ public class RedisBackedCacheTest { @Before public void setUp() throws Exception { - Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getMappedPort(6379)); + Jedis jedis = new Jedis(redis.getHost(), redis.getMappedPort(6379)); cache = new RedisBackedCache(jedis, "test"); } diff --git a/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java b/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java index 9923b08f1e0..0f4e6d672d8 100644 --- a/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java +++ b/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java @@ -17,7 +17,7 @@ public class BarConcreteTestClass extends AbstractIntegrationTest { @Before public void setUp() { - Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getMappedPort(6379)); + Jedis jedis = new Jedis(redis.getHost(), redis.getMappedPort(6379)); cache = new RedisBackedCache(jedis, "bar"); } diff --git a/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java b/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java index a57b0d5d4a0..3a9e4e84f04 100644 --- a/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java +++ b/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java @@ -17,7 +17,7 @@ public class FooConcreteTestClass extends AbstractIntegrationTest { @Before public void setUp() throws Exception { - Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getMappedPort(6379)); + Jedis jedis = new Jedis(redis.getHost(), redis.getMappedPort(6379)); cache = new RedisBackedCache(jedis, "foo"); } diff --git a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java index 63ac67ac1cd..49f8cf99f33 100644 --- a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java +++ b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java @@ -30,7 +30,7 @@ public class SolrQueryTest { @BeforeClass public static void setUp() throws IOException, SolrServerException { solrContainer.start(); - solrClient = new Http2SolrClient.Builder("http://" + solrContainer.getContainerIpAddress() + ":" + solrContainer.getSolrPort() + "/solr").build(); + solrClient = new Http2SolrClient.Builder("http://" + solrContainer.getHost() + ":" + solrContainer.getSolrPort() + "/solr").build(); // Add Sample Data solrClient.add(COLLECTION_NAME, Collections.singletonList( diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java index fe0a9959f2d..58e5c023a0e 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java @@ -33,6 +33,6 @@ public DatastoreEmulatorContainer(final DockerImageName dockerImageName) { * com.google.cloud.ServiceOptions.Builder#setHost(java.lang.String) method. */ public String getEmulatorEndpoint() { - return getContainerIpAddress() + ":" + getMappedPort(8081); + return getHost() + ":" + getMappedPort(8081); } } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java index 6353a679130..c36082dfeb6 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java @@ -34,6 +34,6 @@ public FirestoreEmulatorContainer(final DockerImageName dockerImageName) { * com.google.cloud.ServiceOptions.Builder#setHost(java.lang.String) method. */ public String getEmulatorEndpoint() { - return getContainerIpAddress() + ":" + getMappedPort(8080); + return getHost() + ":" + getMappedPort(8080); } } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java index 90d77c837cf..231f7626044 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java @@ -34,6 +34,6 @@ public PubSubEmulatorContainer(final DockerImageName dockerImageName) { * io.grpc.ManagedChannelBuilder#forTarget(java.lang.String) method. */ public String getEmulatorEndpoint() { - return getContainerIpAddress() + ":" + getMappedPort(PORT); + return getHost() + ":" + getMappedPort(PORT); } } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java index 8603b1f3437..0ae8e89dc06 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java @@ -31,7 +31,7 @@ public SpannerEmulatorContainer(final DockerImageName dockerImageName) { * com.google.cloud.spanner.SpannerOptions.Builder#setEmulatorHost(java.lang.String) method. */ public String getEmulatorGrpcEndpoint() { - return getContainerIpAddress() + ":" + getMappedPort(GRPC_PORT); + return getHost() + ":" + getMappedPort(GRPC_PORT); } /** @@ -39,6 +39,6 @@ public String getEmulatorGrpcEndpoint() { * HTTP REST endpoint is reachable from the test host machine. */ public String getEmulatorHttpEndpoint() { - return getContainerIpAddress() + ":" + getMappedPort(HTTP_PORT); + return getHost() + ":" + getMappedPort(HTTP_PORT); } } diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 662c4b575f7..53336d4fbec 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -69,7 +69,7 @@ public String getReplicaSetUrl(final String databaseName) { } return String.format( "mongodb://%s:%d/%s", - getContainerIpAddress(), + getHost(), getMappedPort(MONGODB_INTERNAL_PORT), databaseName ); diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 3bfb508aa47..741a8c4139a 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -81,7 +81,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { String additionalUrlParams = constructUrlParameters("?", "&"); - return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + return "jdbc:postgresql://" + getHost() + ":" + getMappedPort(POSTGRESQL_PORT) + "/" + databaseName + additionalUrlParams; } diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java index 4d0b5cd1ae1..e583c1f54ee 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java @@ -136,7 +136,7 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { if (StringUtils.isNotEmpty(configuration.getConfigurationName())) { SolrClientUtils.uploadConfiguration( - getContainerIpAddress(), + getHost(), getSolrPort(), configuration.getConfigurationName(), configuration.getSolrConfiguration(), @@ -144,7 +144,7 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { } SolrClientUtils.createCollection( - getContainerIpAddress(), + getHost(), getSolrPort(), configuration.getCollectionName(), configuration.getConfigurationName()); diff --git a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java index c2d19a3e61c..9f82e2c3af9 100644 --- a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java +++ b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java @@ -60,7 +60,7 @@ public void solrCloudPingTest() throws IOException, SolrServerException { container.start(); // Do whatever you want with the client ... - SolrClient client = new Http2SolrClient.Builder("http://" + container.getContainerIpAddress() + ":" + container.getSolrPort() + "/solr").build(); + SolrClient client = new Http2SolrClient.Builder("http://" + container.getHost() + ":" + container.getSolrPort() + "/solr").build(); SolrPingResponse response = client.ping("dummy"); // Stop the container. @@ -70,7 +70,7 @@ public void solrCloudPingTest() throws IOException, SolrServerException { private SolrClient getClient(SolrContainer container) { if (client == null) { - client = new Http2SolrClient.Builder("http://" + container.getContainerIpAddress() + ":" + container.getSolrPort() + "/solr").build(); + client = new Http2SolrClient.Builder("http://" + container.getHost() + ":" + container.getSolrPort() + "/solr").build(); } return client; } From 600d235d220d5e507405921b4e241aa73c067a2a Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 21 Apr 2022 06:45:04 -0600 Subject: [PATCH 1831/4969] Use latest version of alpine/socat container image (#5280) --- .../main/java/org/testcontainers/containers/SocatContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/SocatContainer.java b/core/src/main/java/org/testcontainers/containers/SocatContainer.java index 7592d9f4d1f..bc9ced57845 100644 --- a/core/src/main/java/org/testcontainers/containers/SocatContainer.java +++ b/core/src/main/java/org/testcontainers/containers/SocatContainer.java @@ -15,7 +15,7 @@ public class SocatContainer extends GenericContainer { private final Map targets = new HashMap<>(); public SocatContainer() { - this(DockerImageName.parse("alpine/socat:1.7.3.4-r0")); + this(DockerImageName.parse("alpine/socat:1.7.4.3-r0")); } public SocatContainer(final DockerImageName dockerImageName) { From 96601379e0d1e01ab9743566545e8413e7155e81 Mon Sep 17 00:00:00 2001 From: Roman Pylypaka Date: Mon, 25 Apr 2022 08:24:22 +0100 Subject: [PATCH 1832/4969] Fix connection leak in JDBC waitUntilContainerStarted (#5281) Only the Statement was auto-closed, but not the Connection from which the Statement was created. Aside from resources leaking, this can cause problems when database rename transactions are executed by clients. --- .../org/testcontainers/containers/JdbcDatabaseContainer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index c4bacf3c8ff..5e5342f1ee1 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -1,7 +1,6 @@ package org.testcontainers.containers; import com.github.dockerjava.api.command.InspectContainerResponse; -import java.sql.Statement; import lombok.NonNull; import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; @@ -16,6 +15,7 @@ import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; +import java.sql.Statement; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -144,7 +144,8 @@ protected void waitUntilContainerStarted() { if (!isRunning()) { Thread.sleep(100L); } else { - try (Statement statement = createConnection("").createStatement()) { + try (Connection connection = createConnection(""); + Statement statement = connection.createStatement()) { boolean testQuerySucceeded = statement.execute(this.getTestQueryString()); if (testQuerySucceeded) { logger().info("Container is started (JDBC URL: {})", this.getJdbcUrl()); From 42fa611a18d3433b820c60a1274ccc7217026016 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:44 +0000 Subject: [PATCH 1833/4969] Bump mssql-jdbc in /modules/mssqlserver Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 10.2.0.jre8 to 11.1.1.jre8-preview. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) --- updated-dependencies: - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 1f754303ae1..dfa15ed1c2a 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:10.2.0.jre8' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.1.1.jre8-preview' testImplementation project(':r2dbc') testImplementation 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' From 52cf6a3505e13607a98e512f032a5ea436c2438a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:44 +0000 Subject: [PATCH 1834/4969] Bump postgresql from 42.3.3 to 42.3.4 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.3.4. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.3.4) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 89882481dc1..009f62a8a16 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' - testRuntimeOnly 'org.postgresql:postgresql:42.3.3' + testRuntimeOnly 'org.postgresql:postgresql:42.3.4' testRuntimeOnly 'mysql:mysql-connector-java:8.0.27' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' } From a43ff9b9be66b1131638801083f7ca017c71a332 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:44 +0000 Subject: [PATCH 1835/4969] Bump s3 from 2.17.162 to 2.17.181 in /modules/localstack Bumps s3 from 2.17.162 to 2.17.181. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c3f2374e23f..59a5173fe73 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.169' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.150' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.169' - testImplementation 'software.amazon.awssdk:s3:2.17.162' + testImplementation 'software.amazon.awssdk:s3:2.17.181' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 244159750e6ba3da0fd59c61b352ea627915bead Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:44 +0000 Subject: [PATCH 1836/4969] Bump neo4j from 3.5.31 to 3.5.32 in /modules/neo4j Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.31 to 3.5.32. - [Release notes](https://github.com/neo4j/neo4j/releases) - [Commits](https://github.com/neo4j/neo4j/compare/3.5.31...3.5.32) --- updated-dependencies: - dependency-name: org.neo4j:neo4j dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 6187d665098..0bdd9ba960c 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -29,7 +29,7 @@ task customNeo4jPluginJar(type: Jar) { test.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.31" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.32" api project(":testcontainers") From bda535fa419cd6abf7891af00932b58f46b87dc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:44 +0000 Subject: [PATCH 1837/4969] Bump mysql-connector-java from 8.0.28 to 8.0.29 in /modules/mysql Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.28 to 8.0.29. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.28...8.0.29) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 1796ff17ef0..e23920eaae9 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.28' + testImplementation 'mysql:mysql-connector-java:8.0.29' testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' From 6eddddb462011a1b178726c74798d55c495d498f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:45 +0000 Subject: [PATCH 1838/4969] Bump postgresql from 42.3.3 to 42.3.4 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.3.4. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.3.4) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 754d5dde289..f2c50c30754 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.3.3' + testImplementation 'org.postgresql:postgresql:42.3.4' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' From 00e366f4eb27425b3e37012f341c55efb828f365 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:46 +0000 Subject: [PATCH 1839/4969] Bump java-client from 3.2.6 to 3.3.0 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.2.6 to 3.3.0. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.2.6...java-client-3.3.0) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index a3cb0fcbc70..f1e41fcbe11 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:3.14.9' - testImplementation 'com.couchbase.client:java-client:3.2.6' + testImplementation 'com.couchbase.client:java-client:3.3.0' testImplementation 'org.awaitility:awaitility:4.1.1' } From 6b52e87ca78f61bd996391b4cbafa50917ee25a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:46 +0000 Subject: [PATCH 1840/4969] Bump mysql-connector-java from 8.0.28 to 8.0.29 in /modules/spock Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.28 to 8.0.29. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.28...8.0.29) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index e745bc23ed6..396c0071042 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.3.1' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.28' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.29' testCompileClasspath 'org.jetbrains:annotations:23.0.0' } From 92d1b1b29377a18c8c7652bd39589463b27d8a4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:47 +0000 Subject: [PATCH 1841/4969] Bump jedis from 4.2.1 to 4.2.2 in /examples Bumps [jedis](https://github.com/redis/jedis) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v4.2.1...v4.2.2) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 9092cc86903..4faead13f3a 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:4.2.1' + implementation 'redis.clients:jedis:4.2.2' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 2df4ba7e6d6..b0d64f0524b 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' - implementation 'redis.clients:jedis:4.2.1' + implementation 'redis.clients:jedis:4.2.2' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 9a0af108840..2b7c3b7dda4 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:4.2.1' + implementation 'redis.clients:jedis:4.2.2' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From f4ef7e7d28e6bc8d62c732325fa7ad76c71edfc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:47 +0000 Subject: [PATCH 1842/4969] Bump testcontainers from 1.16.3 to 1.17.1 in /core Bumps [testcontainers](https://github.com/testcontainers/testcontainers-java) from 1.16.3 to 1.17.1. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.16.3...1.17.1) --- updated-dependencies: - dependency-name: org.testcontainers:testcontainers dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 3f1ad71731d..91ee725184f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -60,7 +60,7 @@ configurations.all { } dependencies { - baseline 'org.testcontainers:testcontainers:1.16.3', { + baseline 'org.testcontainers:testcontainers:1.17.1', { exclude group: "*", module: "*" } From 338e9bde40b3b857b5403c42c59cfb583670ce08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:47 +0000 Subject: [PATCH 1843/4969] Bump rest-assured from 5.0.0 to 5.0.1 in /modules/vault Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-5.0.0...rest-assured-5.0.1) --- updated-dependencies: - dependency-name: io.rest-assured:rest-assured dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 68daf4ed26f..80b416ce235 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.bettercloud:vault-java-driver:5.1.0' - testImplementation 'io.rest-assured:rest-assured:5.0.0' + testImplementation 'io.rest-assured:rest-assured:5.0.1' testImplementation 'org.assertj:assertj-core:3.22.0' } From c3583f45bb5931e21cff1a51409b82deeddc2a00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:48 +0000 Subject: [PATCH 1844/4969] Bump mysql-connector-java from 8.0.28 to 8.0.29 in /modules/jdbc-test Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.28 to 8.0.29. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.28...8.0.29) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 5c10742b7f7..d77465c5616 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -16,5 +16,5 @@ dependencies { api 'org.apache.tomcat:tomcat-jdbc:10.0.20' api 'org.vibur:vibur-dbcp:25.0' - api 'mysql:mysql-connector-java:8.0.28' + api 'mysql:mysql-connector-java:8.0.29' } From dd899533f03c4f7b1df821833e3504cf22c6f559 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:49 +0000 Subject: [PATCH 1845/4969] Bump transport from 7.17.2 to 7.17.3 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.17.2 to 7.17.3. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/master/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.17.2...v7.17.3) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index a8d718af3c4..3d8f7bff12d 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2" - testImplementation "org.elasticsearch.client:transport:7.17.2" + testImplementation "org.elasticsearch.client:transport:7.17.3" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From e70ca03da3577b8cefc52d3a06b88c2dcd057276 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:50 +0000 Subject: [PATCH 1846/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.169 to 1.12.210. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.169...1.12.210) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 2fa5978772e..6dabdec119b 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.169' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.150' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.210' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.210' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 7425a05dbec152c741e2e35b16018f08bc998c36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:51 +0000 Subject: [PATCH 1847/4969] Bump jedis from 4.1.1 to 4.2.2 in /modules/junit-jupiter Bumps [jedis](https://github.com/redis/jedis) from 4.1.1 to 4.2.2. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v4.1.1...v4.2.2) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 89882481dc1..2685e7b7e40 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:4.1.1' + testImplementation 'redis.clients:jedis:4.2.2' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testImplementation ('org.mockito:mockito-core:4.4.0') { exclude(module: 'hamcrest-core') From e62826489090b6485e4668797eda3ffddf8075c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:55 +0000 Subject: [PATCH 1848/4969] Bump jedis from 4.0.1 to 4.2.2 in /core Bumps [jedis](https://github.com/redis/jedis) from 4.0.1 to 4.2.2. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v4.0.1...v4.2.2) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 3f1ad71731d..527d8bd6153 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -91,7 +91,7 @@ dependencies { shaded 'org.zeroturnaround:zt-exec:1.12' testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' - testImplementation 'redis.clients:jedis:4.0.1' + testImplementation 'redis.clients:jedis:4.2.2' testImplementation 'com.rabbitmq:amqp-client:5.14.2' testImplementation 'org.mongodb:mongo-java-driver:3.12.10' From 93504fdbef0d27cec7b7810704c99270ecf3e743 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:55 +0000 Subject: [PATCH 1849/4969] Bump toxiproxy-java from 2.1.5 to 2.1.7 in /modules/toxiproxy Bumps [toxiproxy-java](https://github.com/trekawek/toxiproxy-java) from 2.1.5 to 2.1.7. - [Release notes](https://github.com/trekawek/toxiproxy-java/releases) - [Changelog](https://github.com/trekawek/toxiproxy-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/trekawek/toxiproxy-java/compare/toxiproxy-java-2.1.5...toxiproxy-java-2.1.7) --- updated-dependencies: - dependency-name: eu.rekawek.toxiproxy:toxiproxy-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/toxiproxy/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index cad4b6b71f3..a1e5f58551a 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: Toxiproxy" dependencies { api project(':testcontainers') - api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.5' + api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.7' testImplementation 'redis.clients:jedis:3.0.1' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From e54b4a3db1f8de8b80cfb0f3aed494ff21ba900e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:56 +0000 Subject: [PATCH 1850/4969] Bump com.gradle.enterprise.gradle.plugin from 3.8.1 to 3.10 in /examples Bumps com.gradle.enterprise.gradle.plugin from 3.8.1 to 3.10. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 75f739e9005..ceb39498854 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.8.1" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.2" } } From ef3e752393d1720352bd72ad4c0e8b7064f6538f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:59 +0000 Subject: [PATCH 1851/4969] Bump aws-java-sdk-sqs from 1.12.150 to 1.12.210 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.150 to 1.12.210. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.150...1.12.210) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c3f2374e23f..704a16204ae 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.191' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.169' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.150' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.210' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.169' testImplementation 'software.amazon.awssdk:s3:2.17.162' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From dcdad30f9e91cb87ab3c45a73b5fb9e264405399 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:00:59 +0000 Subject: [PATCH 1852/4969] Bump lombok from 1.18.22 to 1.18.24 in /examples Bumps [lombok](https://github.com/projectlombok/lombok) from 1.18.22 to 1.18.24. - [Release notes](https://github.com/projectlombok/lombok/releases) - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.22...v1.18.24) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 4 ++-- examples/kafka-cluster/build.gradle | 2 +- examples/solr-container/build.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 2352eace899..bfb89f9cef2 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -7,8 +7,8 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.22" - annotationProcessor "org.projectlombok:lombok:1.18.20" + compileOnly "org.projectlombok:lombok:1.18.24" + annotationProcessor "org.projectlombok:lombok:1.18.24" implementation 'biz.paluch.redis:spinach:0.3' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 7ba974d3a6d..ee8035ea51c 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - testCompileOnly "org.projectlombok:lombok:1.18.22" + testCompileOnly "org.projectlombok:lombok:1.18.24" testAnnotationProcessor "org.projectlombok:lombok:1.18.22" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:3.1.0' diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index cec4f59625b..3f3366f9d46 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly "org.projectlombok:lombok:1.18.22" + compileOnly "org.projectlombok:lombok:1.18.24" annotationProcessor "org.projectlombok:lombok:1.18.22" implementation 'org.apache.solr:solr-solrj:8.11.1' From d3350c2e9de0a19d56a8d24e3750167e379d4ff9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:01:06 +0000 Subject: [PATCH 1853/4969] Bump actions/cache from 3.0.1 to 3.0.2 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.1...v3.0.2) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index c1b4ac7148e..90b493df481 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -22,7 +22,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.1 + uses: actions/cache@v3.0.2 continue-on-error: true with: path: ~/.gradle/caches @@ -50,7 +50,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.1 + uses: actions/cache@v3.0.2 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16397815990..0c0e5eaf601 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.1 + uses: actions/cache@v3.0.2 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -56,7 +56,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.1 + uses: actions/cache@v3.0.2 continue-on-error: true with: path: ~/.gradle/caches From 0bce9aac0621ab988552698a8c6111cc99a0e358 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:02:21 +0000 Subject: [PATCH 1854/4969] Bump peter-evans/create-pull-request from 4.0.1 to 4.0.2 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/f1a7646cead32c950d90344a4fb5d4e926972a8f...bd72e1b7922d417764d27d30768117ad7da78a0e) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 3fbbda7153c..b5d672c092d 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -17,7 +17,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@f1a7646cead32c950d90344a4fb5d4e926972a8f # v3.10.1 + uses: peter-evans/create-pull-request@bd72e1b7922d417764d27d30768117ad7da78a0e # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From 69c73c20274055ce92f39e3f29ffba41bddccf5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:02:29 +0000 Subject: [PATCH 1855/4969] Bump org.jetbrains.kotlin.jvm from 1.6.10 to 1.6.21 in /examples Bumps org.jetbrains.kotlin.jvm from 1.6.10 to 1.6.21. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 1d98c3e3eff..b6dd68b33cd 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.6.4" - id("org.jetbrains.kotlin.jvm") version "1.6.10" + id("org.jetbrains.kotlin.jvm") version "1.6.21" id("org.jetbrains.kotlin.plugin.spring") version "1.6.20" } From 9ecd399cb1c23d3130f4613ca6888d3e67dca9ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:03:47 +0000 Subject: [PATCH 1856/4969] Bump trino-jdbc from 375 to 379 in /modules/trino Bumps trino-jdbc from 375 to 379. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index f99951dc7fa..d0b56af633f 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:375' + testImplementation 'io.trino:trino-jdbc:379' compileOnly 'org.jetbrains:annotations:23.0.0' } From b353a96a8ac2c260aa4ba30180e3f1495dc9835a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:03:58 +0000 Subject: [PATCH 1857/4969] Bump mongodb-driver-sync from 4.5.1 to 4.6.0 in /modules/mongodb Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.5.1 to 4.6.0. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.5.1...r4.6.0) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/mongodb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index 6bca2cb892b..d8ef34fbb40 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: MongoDB" dependencies { api project(':testcontainers') - testImplementation("org.mongodb:mongodb-driver-sync:4.5.1") + testImplementation("org.mongodb:mongodb-driver-sync:4.6.0") } From e3525704d983221c94d7af7a87b3e8452ca81933 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:04:00 +0000 Subject: [PATCH 1858/4969] Bump azure-cosmos from 4.26.0 to 4.29.1 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.26.0 to 4.29.1. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.26.0...azure-cosmos_4.29.1) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index b4dab636eb9..8ab7612c18b 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:3.14.9' testImplementation 'org.assertj:assertj-core:3.22.0' - testImplementation 'com.azure:azure-cosmos:4.26.0' + testImplementation 'com.azure:azure-cosmos:4.29.1' } From 9d1f038121cb0f8bf42611a9092af1f2b3857748 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:04:05 +0000 Subject: [PATCH 1859/4969] Bump kubernetes-client from 5.12.1 to 5.12.2 in /modules/k3s Bumps [kubernetes-client](https://github.com/fabric8io/kubernetes-client) from 5.12.1 to 5.12.2. - [Release notes](https://github.com/fabric8io/kubernetes-client/releases) - [Changelog](https://github.com/fabric8io/kubernetes-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/fabric8io/kubernetes-client/compare/v5.12.1...v5.12.2) --- updated-dependencies: - dependency-name: io.fabric8:kubernetes-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index a373d8115d7..0ab368d60c2 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -8,7 +8,7 @@ dependencies { // Any >2.8 version here is not compatible with jackson-databind 2.8.x. shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' - testImplementation 'io.fabric8:kubernetes-client:5.12.1' + testImplementation 'io.fabric8:kubernetes-client:5.12.2' testImplementation 'io.kubernetes:client-java:15.0.0' testImplementation 'org.assertj:assertj-core:3.22.0' } From 3cd4f25f6825def6c6dfeeadf40c09fe95be01d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:04:12 +0000 Subject: [PATCH 1860/4969] Bump postgresql from 42.3.3 to 42.3.4 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.3.4. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.3.4) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index 4d15e4df1c1..ad1007a4744 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.3.3' + testImplementation 'org.postgresql:postgresql:42.3.4' } From 9035c934cd87b8bcb051d4f1533fa0fc1d9fee0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:04:16 +0000 Subject: [PATCH 1861/4969] Bump google-cloud-pubsub from 1.115.1 to 1.116.4 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.115.1 to 1.116.4. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.115.1...v1.116.4) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 6a51c854552..475cfb56c45 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.2.2' testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.116.4' testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.6.1' testImplementation 'org.assertj:assertj-core:3.22.0' From f9abd766159b2d1f595f106fae9fb6325ef0e1b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:04:26 +0000 Subject: [PATCH 1862/4969] Bump reactor-core from 3.4.16 to 3.4.17 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.16 to 3.4.17. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.16...v3.4.17) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index d1ddfc0455a..2a4e3958af8 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.16' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.17' testFixturesImplementation 'org.assertj:assertj-core:3.14.0' } From 6a56e04b436b14e406df2ebb2e571dcce87f6bfa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:04:29 +0000 Subject: [PATCH 1863/4969] Bump google-cloud-datastore from 2.2.2 to 2.4.0 in /modules/gcloud Bumps [google-cloud-datastore](https://github.com/googleapis/java-datastore) from 2.2.2 to 2.4.0. - [Release notes](https://github.com/googleapis/java-datastore/releases) - [Changelog](https://github.com/googleapis/java-datastore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-datastore/compare/v2.2.2...v2.4.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-datastore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 6a51c854552..ab571447bcc 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:2.2.2' + testImplementation 'com.google.cloud:google-cloud-datastore:2.4.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0' From bf9a26680a6a4a1394cf1fc230895112e0d53e45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:04:34 +0000 Subject: [PATCH 1864/4969] Bump google-cloud-bigtable from 2.6.1 to 2.6.2 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.6.1 to 2.6.2. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.6.1...v2.6.2) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 6a51c854552..2aea93f27e5 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21' testImplementation 'com.google.cloud:google-cloud-pubsub:1.115.1' testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.6.1' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.6.2' testImplementation 'org.assertj:assertj-core:3.22.0' } From f63f9619329a2d6e25c9832c51bba3af06c7c86a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:05:33 +0000 Subject: [PATCH 1865/4969] Bump hivemq-extension-sdk from 4.7.5 to 4.8.0 in /modules/hivemq Bumps [hivemq-extension-sdk](https://github.com/hivemq/hivemq-extension-sdk) from 4.7.5 to 4.8.0. - [Release notes](https://github.com/hivemq/hivemq-extension-sdk/releases) - [Commits](https://github.com/hivemq/hivemq-extension-sdk/compare/4.7.5...4.8.0) --- updated-dependencies: - dependency-name: com.hivemq:hivemq-extension-sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index dfd01981894..bfdfecb1761 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -13,7 +13,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") testImplementation(project(":junit-jupiter")) - testImplementation("com.hivemq:hivemq-extension-sdk:4.7.5") + testImplementation("com.hivemq:hivemq-extension-sdk:4.8.0") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.10") From 9635a350d34035c204e1a2e451c77e617e778055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Prinet?= Date: Mon, 2 May 2022 16:51:33 +0200 Subject: [PATCH 1866/4969] Manage Gradle Enterprise plugins with Dependabot (#5342) * Add dependabot configuration to monitor Gradle plugins * Restrict registries to Gradle Plugin Portal --- .github/dependabot.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5d67f278219..3e2d53fed65 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,10 +1,25 @@ version: 2 +registries: + gradle-plugin-portal: + type: maven-repository + url: https://plugins.gradle.org/m2 + username: dummy # Required by dependabot + password: dummy # Required by dependabot updates: - package-ecosystem: "gradle" directory: "/core" schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/" + allow: + - dependency-name: "com.gradle*" + registries: + - gradle-plugin-portal + schedule: + interval: "monthly" + open-pull-requests-limit: 10 # Explicit entry for each module - package-ecosystem: "gradle" From e21164a893141b5a7be817a4f6c43485a9f930e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 20:10:23 +0200 Subject: [PATCH 1867/4969] Bump com.gradle.enterprise.gradle.plugin from 3.9 to 3.10 (#5343) Bumps com.gradle.enterprise.gradle.plugin from 3.9 to 3.10. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 64f2aa5d70a..6b80183bc34 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.9" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.5" } } From 46ba812ab2315626ca3d90c7432a2a0bbb544f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 6 May 2022 16:10:29 -0500 Subject: [PATCH 1868/4969] Add testcontainers/java-team in CODEOWNERS (#5353) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index add6048a437..effc21c4f1e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,7 +3,7 @@ # These owners will be the default reviewers for everything in # the repo. -* @rnorth @bsideup @kiview +* @testcontainers/java-team # The last matching pattern takes the most # precedence. From b3b2a4694f2f919b2d1a7b3fa447e4e03125d56d Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Sun, 8 May 2022 10:02:27 +0200 Subject: [PATCH 1869/4969] Elasticsearch: Don't throw exception on missing CA cert file (#5265) The current check throws an exception if the version is supposed to be greater than 8 and the ca cert file is missing. This posed two problems: 1. A custom docker image might have a 'latest' version, and thus is newer than version 8 2. A user may have configured their own CA in a different path In order to accomodate for this, a missing copy of a the ca crt file will log a warning, but not throw an exception and leave the container unstarted. There is also another public method, allowing to read the cert, called `extractCert`. Closes #5264 --- .../elasticsearch/ElasticsearchContainer.java | 31 +++++++- .../ElasticsearchContainerTest.java | 79 +++++++++++++++---- .../src/test/resources/http_ca.crt | 31 ++++++++ 3 files changed, 123 insertions(+), 18 deletions(-) create mode 100644 modules/elasticsearch/src/test/resources/http_ca.crt diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index 84881b2e87d..ac0b367f403 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -1,7 +1,10 @@ package org.testcontainers.elasticsearch; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.NotFoundException; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.Base58; @@ -21,6 +24,7 @@ * Represents an elasticsearch docker instance which exposes by default port 9200 and 9300 (transport.tcp.port) * The docker image is by default fetched from docker.elastic.co/elasticsearch/elasticsearch */ +@Slf4j public class ElasticsearchContainer extends GenericContainer { /** @@ -55,6 +59,7 @@ public class ElasticsearchContainer extends GenericContainer caCertAsBytes = Optional.empty(); + private String certPath = "/usr/share/elasticsearch/config/certs/http_ca.crt"; /** * @deprecated use {@link ElasticsearchContainer(DockerImageName)} instead @@ -100,10 +105,17 @@ public ElasticsearchContainer(final DockerImageName dockerImageName) { @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { - if (isAtLeastMajorVersion8) { - byte[] bytes = copyFileFromContainer("/usr/share/elasticsearch/config/certs/http_ca.crt", IOUtils::toByteArray); - if (bytes.length > 0) { - this.caCertAsBytes = Optional.of(bytes); + if (isAtLeastMajorVersion8 && StringUtils.isNotEmpty(certPath)) { + try { + byte[] bytes = copyFileFromContainer(certPath, IOUtils::toByteArray); + if (bytes.length > 0) { + this.caCertAsBytes = Optional.of(bytes); + } + } catch (NotFoundException e) { + // just emit an error message, but do not throw an exception + // this might be ok, if the docker image is accidentally looking like version 8 or latest + // can happen if Elasticsearch is repackaged, i.e. with custom plugins + log.warn("CA cert under " + certPath + " not found."); } } } @@ -158,6 +170,17 @@ public ElasticsearchContainer withPassword(String password) { return this; } + /** + * Configure a CA cert path that is not the default + * + * @param certPath Path to the CA certificate within the Docker container to extract it from after start up + * @return this + */ + public ElasticsearchContainer withCertPath(String certPath) { + this.certPath = certPath; + return this; + } + public String getHttpHostAddress() { return getHost() + ":" + getMappedPort(ELASTICSEARCH_DEFAULT_PORT); } diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 956c794135b..f8131268e61 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -1,5 +1,6 @@ package org.testcontainers.elasticsearch; +import com.github.dockerjava.api.DockerClient; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -17,8 +18,12 @@ import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.junit.After; import org.junit.Test; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; +import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import static org.hamcrest.CoreMatchers.containsString; @@ -252,29 +257,75 @@ public void incompatibleSettingsTest() { @Test public void testElasticsearch8SecureByDefault() throws Exception { - try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.0.0")) { + try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.1.2")) { // Start the container. This step might take some time... container.start(); - // Create the secured client. - final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(AuthScope.ANY, - new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)); - - client = RestClient.builder(HttpHost.create("https://" + container.getHttpHostAddress())) - .setHttpClientConfigCallback(httpClientBuilder -> { - httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); - httpClientBuilder.setSSLContext(container.createSslContextFromCa()); - return httpClientBuilder; - }) - .build(); + Response response = getClusterHealth(container); + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + } + } - Response response = client.performRequest(new Request("GET", "/_cluster/health")); + @Test + public void testElasticsearch8SecureByDefaultCustomCaCertFails() throws Exception { + final MountableFile mountableFile = MountableFile.forClasspathResource("http_ca.crt"); + String caPath = "/tmp/http_ca.crt"; + try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.1.2") + .withCopyToContainer(mountableFile, caPath) + .withCertPath(caPath)) { + + container.start(); + + // this is expected, as a different cert is used for creating the SSL context + assertThrows("PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors", SSLHandshakeException.class, () -> getClusterHealth(container)); + } + } + + @Test + public void testElasticsearch8SecureByDefaultFailsSilentlyOnLatestImages() throws Exception { + // this test exists for custom images by users that use the `latest` tag + // even though the version might be older than version 8 + // this tags an old 7.x version as :latest + tagImage("docker.elastic.co/elasticsearch/elasticsearch:7.9.2", "elasticsearch-tc-older-release", "latest"); + DockerImageName image = DockerImageName.parse("elasticsearch-tc-older-release:latest").asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch"); + + try (ElasticsearchContainer container = new ElasticsearchContainer(image)) { + container.start(); + + Response response = getClient(container).performRequest(new Request("GET", "/_cluster/health")); assertThat(response.getStatusLine().getStatusCode(), is(200)); assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); } } + private void tagImage(String sourceImage, String targetImage, String targetTag) throws InterruptedException { + DockerClient dockerClient = DockerClientFactory.instance().client(); + dockerClient.tagImageCmd( + new RemoteDockerImage(DockerImageName.parse(sourceImage)).get(), + targetImage, + targetTag + ) + .exec(); + } + + private Response getClusterHealth(ElasticsearchContainer container) throws IOException { + // Create the secured client. + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)); + + client = RestClient.builder(HttpHost.create("https://" + container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> { + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + httpClientBuilder.setSSLContext(container.createSslContextFromCa()); + return httpClientBuilder; + }) + .build(); + + return client.performRequest(new Request("GET", "/_cluster/health")); + } + private RestClient getClient(ElasticsearchContainer container) { if (client == null) { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); diff --git a/modules/elasticsearch/src/test/resources/http_ca.crt b/modules/elasticsearch/src/test/resources/http_ca.crt new file mode 100644 index 00000000000..704e5a37aa6 --- /dev/null +++ b/modules/elasticsearch/src/test/resources/http_ca.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIVAPVLz0Dwvzl66ZVpyJY/ntos+qQZMA0GCSqGSIb3DQEB +CwUAMDwxOjA4BgNVBAMTMUVsYXN0aWNzZWFyY2ggc2VjdXJpdHkgYXV0by1jb25m +aWd1cmF0aW9uIEhUVFAgQ0EwHhcNMjIwNDE0MDcyOTA4WhcNMjUwNDEzMDcyOTA4 +WjA8MTowOAYDVQQDEzFFbGFzdGljc2VhcmNoIHNlY3VyaXR5IGF1dG8tY29uZmln +dXJhdGlvbiBIVFRQIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA +ufHmvM04dPKNF6AulX3HrjNfcYy62pBO2oJIKhScetDzuRupv/qiXkO1gzGT3/jk +8uk57rzylDFoCgFNUyWdYQAXD+qsy5vbAytGVNCHOGSuWlNm1bbDYwZNTXjZTK6C +CKIY31lbFn9a4oM+Jp1kvIr8GSMQAYDisq+yrVloDLkRs1SPImnoaXsq8epxloBf +En0vo5V8PtOh+xQFpPP21pd5QohCSB+jMaxaizScWX+k7BijEaS1LCsc2w2PNvwn +/bEvtW7w9w+HnzRGZW2nVlt8eji1PHMmfM5Zugn4HAxsSvdI9VRFGAeT2moNiSLN +zxOWmEvQVl2MxRWiTkM1EM7CFDN40hLHtHej8UddeXTDDXyLoUjY3FmaB45rLKdE +k/rszepc3lmptEMh74iUowKaYZTS5jRqT0yIDzevP5je3JP+pe4aNkx7lWMhTReQ +6fs97nd71PfJBuMcHPEA14zwSzSRb/8mNqqaQLBb5H1DpDcZtzbBxb4wFSAa7Dd0 +pVl4A04iB4PS3DaWg/im2C5a83nUTld7Lvy+I6cO1MTaXdkzn6EWXtxkHj7P4VXX +sFTr+Z2A6g/novqderirQzq8aD87MBp2hLBgG59lVB3IXA+CJTzBRBZipU+FOSs2 +1enMlaEa84d8cb+GSpDkmsvamPMhhLeMw6QLmhQXoWMCAwEAAaNTMFEwHQYDVR0O +BBYEFOt9JC+RiqfFdGf/UT2vfmnV8f+kMB8GA1UdIwQYMBaAFOt9JC+RiqfFdGf/ +UT2vfmnV8f+kMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBALFX +r2CKtu2DcLFQaZft9LeRK67xU0rjN8w1+0MN9otSkU9avd8atPOI9p6r67HZyoTv +LDA47ajitzPo4zAXiy4GUXFVCjx3iPOQ4TTCm0YEf9IudLHLqGTbK+Pup6XlfAMb +RejkztcXkxw3Cy6SjIRq99xU8J6Y1jAggB162hqnp3u42nA1PgOJgo/biUYeVtu7 +Y01gKPdCEkiqmSFxfLiRPv5Z4WyYoKge6UyDYFHu0zyMY7zQ2hzrPMFsEhI4+g5D +W7ihilcOijhvfeeWIxcP5lRn2pGbf2GtwqtA7Bt9YKp+NQIBPzK7D1ymS0v/CAWh +3Bv1rqkqDK8TlBybZitTTB6MgGtXOBccouTPmBFBXSWydvW4GW6Dag/ogHHE2vG2 +xlXY6EC1QEzExcM5FZNJI6SOaK0nl+WKAv060U/1ZqcRIkhyctYdkrK4449n1JMy +wjtwcDW7QxhQspHp8GEXztLctokqGjnuMcgPjVoFdiF3w/IV0UUvVeFK4Oms0YbH +uFr3q44Fu/Fol68/1CUk1ytgLUS5anf0Q0WlJsmMUX156ATA29dVBfloJN63EYd7 +01uwbjoMJce7MiwTaLIetW75fxxZHlQK9TMNhaQwKUO8SRaNuE4wKURFoKPg/Dqu +yPhx9adseStlJ3oV6ziEWMwjOK2JmJf0bmIqQ7KR +-----END CERTIFICATE----- From 84a635efad8a2dc1726ee263950e013de9b51e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 9 May 2022 09:11:20 -0500 Subject: [PATCH 1870/4969] Fix docs: use getHost (#5288) --- .../src/test/java/com/example/AbstractIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java index b6859563c69..dd1b7b6fb5a 100644 --- a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java +++ b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java @@ -23,7 +23,7 @@ public abstract class AbstractIntegrationTest { @DynamicPropertySource static void redisProperties(DynamicPropertyRegistry registry) { redis.start(); - registry.add("spring.redis.host", redis::getContainerIpAddress); + registry.add("spring.redis.host", redis::getHost); registry.add("spring.redis.port", redis::getFirstMappedPort); } } From 0b03b91c22fe79af25c8576c5c13195b76f3f619 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 9 May 2022 20:40:29 -0400 Subject: [PATCH 1871/4969] Fix deadlock in `LocalImagesCache` (#5356) Fixes #5282 --- .../java/org/testcontainers/images/LocalImagesCache.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java index ec38721a229..8791ecb6986 100644 --- a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java +++ b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java @@ -27,15 +27,14 @@ enum LocalImagesCache { @VisibleForTesting final Map cache = new ConcurrentHashMap<>(); - DockerClient dockerClient = DockerClientFactory.lazyClient(); - public ImageData get(DockerImageName imageName) { - maybeInitCache(); + maybeInitCache(DockerClientFactory.instance().client()); return cache.get(imageName); } public Optional refreshCache(DockerImageName imageName) { - if (!maybeInitCache()) { + DockerClient dockerClient = DockerClientFactory.instance().client(); + if (!maybeInitCache(dockerClient)) { // Cache may be stale, trying inspectImageCmd... InspectImageResponse response = null; @@ -57,7 +56,7 @@ public Optional refreshCache(DockerImageName imageName) { return Optional.ofNullable(cache.get(imageName)); } - private synchronized boolean maybeInitCache() { + private synchronized boolean maybeInitCache(DockerClient dockerClient) { if (!initialized.compareAndSet(false, true)) { return false; } From 3164d4ec1081a8f43982dcadc9db887ea6ac79b3 Mon Sep 17 00:00:00 2001 From: Felix Seifert Date: Tue, 10 May 2022 02:40:56 +0200 Subject: [PATCH 1872/4969] Correct usage of deprecated method `createSubscription()` (#5350) Call non-deprecated `createSubscription` method in `PubSubEmulatorTest` --- .../testcontainers/containers/PubSubEmulatorContainerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java index 8db49eb3649..61d56a279d7 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java @@ -20,6 +20,7 @@ import com.google.pubsub.v1.PullRequest; import com.google.pubsub.v1.PullResponse; import com.google.pubsub.v1.PushConfig; +import com.google.pubsub.v1.SubscriptionName; import com.google.pubsub.v1.TopicName; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; @@ -104,7 +105,7 @@ private void createSubscription(String subscriptionId, String topicId, Transport .setCredentialsProvider(credentialsProvider) .build(); SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create(subscriptionAdminSettings); - ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(PROJECT_ID, subscriptionId); + SubscriptionName subscriptionName = SubscriptionName.of(PROJECT_ID, subscriptionId); subscriptionAdminClient.createSubscription(subscriptionName, TopicName.of(PROJECT_ID, topicId), PushConfig.getDefaultInstance(), 10); } // } From d4e7671a09f6312f96044f937f2d0973078860e3 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Tue, 10 May 2022 08:11:31 +0200 Subject: [PATCH 1873/4969] Add getConnectionString() for MongoDBContainer (#5271) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales Co-authored-by: Kevin Wittek --- .../containers/MongoDBContainer.java | 20 +++++++++++++------ .../containers/MongoDBContainerTest.java | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 53336d4fbec..87db80846a8 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -48,6 +48,19 @@ public MongoDBContainer(final DockerImageName dockerImageName) { ); } + /** + * Gets a connection string url, unlike {@link #getReplicaSetUrl} this does point to a + * database + * @return a connection url pointing to a mongodb instance + */ + public String getConnectionString() { + return String.format( + "mongodb://%s:%d", + getHost(), + getMappedPort(MONGODB_INTERNAL_PORT) + ); + } + /** * Gets a replica set url for the default {@value #MONGODB_DATABASE_NAME_DEFAULT} database. * @@ -67,12 +80,7 @@ public String getReplicaSetUrl(final String databaseName) { if (!isRunning()) { throw new IllegalStateException("MongoDBContainer should be started first"); } - return String.format( - "mongodb://%s:%d/%s", - getHost(), - getMappedPort(MONGODB_INTERNAL_PORT), - databaseName - ); + return getConnectionString() + "/" + databaseName; } @Override diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index ff5243acea7..532a86208c1 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -38,11 +38,15 @@ public void shouldExecuteTransactions() { final String mongoRsUrl = mongoDBContainer.getReplicaSetUrl(); assertNotNull(mongoRsUrl); + final String connectionString = mongoDBContainer.getConnectionString(); + final MongoClient mongoSyncClientBase = MongoClients.create(connectionString); final MongoClient mongoSyncClient = MongoClients.create(mongoRsUrl); mongoSyncClient.getDatabase("mydb1").getCollection("foo") .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0)); mongoSyncClient.getDatabase("mydb2").getCollection("bar") .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0)); + mongoSyncClientBase.getDatabase("mydb3").getCollection("baz") + .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("def", 0)); final ClientSession clientSession = mongoSyncClient.startSession(); final TransactionOptions txnOptions = TransactionOptions.builder() From 87126060b0e76ace2b4b9b344d92908fe4fb7cf5 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 10 May 2022 10:19:57 -0400 Subject: [PATCH 1874/4969] Test `DOCKER_HOST` in `DockerClientProviderStrategy` (#5357) * Test `DOCKER_HOST` in `DockerClientProviderStrategy` * Update DockerClientProviderStrategy.java --- .../DockerClientProviderStrategy.java | 101 +++++++++++++++--- 1 file changed, 88 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 2ae066d897d..cf091e94328 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -7,6 +7,9 @@ import com.github.dockerjava.core.DockerClientImpl; import com.github.dockerjava.core.RemoteApiVersion; import com.github.dockerjava.transport.DockerHttpClient; +import com.github.dockerjava.transport.NamedPipeSocket; +import com.github.dockerjava.transport.SSLConfig; +import com.github.dockerjava.transport.UnixSocket; import com.github.dockerjava.zerodep.ZerodepDockerHttpClient; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; @@ -14,15 +17,28 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.awaitility.Awaitility; import org.jetbrains.annotations.Nullable; import org.rnorth.ducttape.TimeoutException; import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.DockerClientFactory; +import org.testcontainers.UnstableAPI; import org.testcontainers.utility.TestcontainersConfiguration; +import javax.net.SocketFactory; +import java.io.File; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; import java.net.URI; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -31,6 +47,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; @@ -104,6 +121,71 @@ public DockerClient getClient() { return dockerClient; } + /** + * TODO we should consider moving this to docker-java at some point + */ + @UnstableAPI + protected boolean test() { + TransportConfig transportConfig = getTransportConfig(); + URI dockerHost = transportConfig.getDockerHost(); + + Callable socketProvider; + SocketAddress socketAddress; + switch (dockerHost.getScheme()) { + case "tcp": + case "http": + case "https": + SocketFactory socketFactory = SocketFactory.getDefault(); + SSLConfig sslConfig = transportConfig.getSslConfig(); + if (sslConfig != null) { + try { + socketFactory = sslConfig.getSSLContext().getSocketFactory(); + } catch (KeyManagementException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) { + log.warn("Exception while creating SSLSocketFactory", e); + return false; + } + } + socketProvider = socketFactory::createSocket; + socketAddress = new InetSocketAddress(dockerHost.getHost(), dockerHost.getPort()); + break; + case "unix": + case "npipe": + if (!new File(dockerHost.getPath()).exists()) { + log.debug("DOCKER_HOST socket file '{}' does not exist", dockerHost.getPath()); + return false; + } + socketProvider = () -> { + switch (dockerHost.getScheme()) { + case "unix": + return UnixSocket.get(dockerHost.getPath()); + case "npipe": + return new NamedPipeSocket(dockerHost.getPath()); + default: + throw new IllegalStateException("Unexpected scheme " + dockerHost.getScheme()); + } + }; + socketAddress = new InetSocketAddress("localhost", 2375); + break; + default: + log.warn("Unknown DOCKER_HOST scheme {}, skipping the strategy test...", dockerHost.getScheme()); + return true; + } + + try (Socket socket = socketProvider.call()) { + Duration timeout = Duration.ofMillis(200); + Awaitility.await() + .atMost(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS) + .pollInterval(timeout) + .pollDelay(Duration.ofSeconds(0)) // start checking immediately + .ignoreExceptionsInstanceOf(SocketTimeoutException.class) + .untilAsserted(() -> socket.connect(socketAddress, (int) timeout.toMillis())); + return true; + } catch (Exception e) { + log.warn("DOCKER_HOST {} is not listening", dockerHost); + return false; + } + } + /** * Determine the right DockerClientConfig to use for building clients by trial-and-error. * @@ -161,20 +243,13 @@ public boolean test(DockerClientProviderStrategy dockerClientProviderStrategy) { private static boolean tryOutStrategy(List configurationFailures, DockerClientProviderStrategy strategy) { try { log.debug("Trying out strategy: {}", strategy.getClass().getSimpleName()); - DockerClient dockerClient = strategy.getDockerClient(); - - Info info; - try { - info = Unreliables.retryUntilSuccess(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS, () -> { - return strategy.PING_RATE_LIMITER.getWhenReady(() -> { - log.debug("Pinging docker daemon..."); - return dockerClient.infoCmd().exec(); - }); - }); - } catch (TimeoutException e) { - IOUtils.closeQuietly(dockerClient); - throw e; + + if (!strategy.test()) { + log.debug("strategy {} did not pass the test", strategy.getClass().getSimpleName()); + return false; } + + Info info = strategy.getDockerClient().infoCmd().exec(); log.info("Found Docker environment with {}", strategy.getDescription()); log.debug( "Transport type: '{}', Docker host: '{}'", From 7d54ff90a4e9514ded0ea0a09d234ae5d76cc10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 11 May 2022 13:22:18 -0500 Subject: [PATCH 1875/4969] Allow to create exchanges, queues, bindings in the same vhost (#5348) --- .../containers/RabbitMQContainer.java | 39 +++++++++++++++++++ .../containers/RabbitMQContainerTest.java | 16 +++++--- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index 37dc2fbe7ca..f5c63a267a9 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -220,8 +220,25 @@ public RabbitMQContainer withBinding(String source, String destination) { return self(); } + public RabbitMQContainer withBinding(String vhost, String source, String destination) { + values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "binding", + "source=" + source, + "destination=" + destination)); + return self(); + } + public RabbitMQContainer withBinding(String source, String destination, Map arguments, String routingKey, String destinationType) { values.add(asList("rabbitmqadmin", "declare", "binding", + "source=" + source, + "destination=" + destination, + "routing_key=" + routingKey, + "destination_type=" + destinationType, + "arguments=" + toJson(arguments))); + return self(); + } + + public RabbitMQContainer withBinding(String vhost, String source, String destination, Map arguments, String routingKey, String destinationType) { + values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "binding", "source=" + source, "destination=" + destination, "routing_key=" + routingKey, @@ -332,6 +349,12 @@ public RabbitMQContainer withVhostLimit(String vhost, String name, int value) { public RabbitMQContainer withQueue(String name) { values.add(asList("rabbitmqadmin", "declare", "queue", + "name=" + name)); + return self(); + } + + public RabbitMQContainer withQueue(String vhost, String name) { + values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "queue", "name=" + name)); return self(); } @@ -345,6 +368,15 @@ public RabbitMQContainer withQueue(String name, boolean autoDelete, boolean dura return self(); } + public RabbitMQContainer withQueue(String vhost, String name, boolean autoDelete, boolean durable, Map arguments) { + values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "queue", + "name=" + name, + "auto_delete=" + autoDelete, + "durable=" + durable, + "arguments=" + toJson(arguments))); + return self(); + } + public RabbitMQContainer withExchange(String name, String type) { values.add(asList("rabbitmqadmin", "declare", "exchange", "name=" + name, @@ -352,6 +384,13 @@ public RabbitMQContainer withExchange(String name, String type) { return self(); } + public RabbitMQContainer withExchange(String vhost, String name, String type) { + values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "exchange", + "name=" + name, + "type=" + type)); + return self(); + } + public RabbitMQContainer withExchange(String name, String type, boolean autoDelete, boolean internal, boolean durable, Map arguments) { values.add(asList("rabbitmqadmin", "declare", "exchange", "name=" + name, diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index 474d613cb8b..d82051a94db 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -14,7 +14,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -22,8 +21,6 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Collections; -import java.util.Objects; -import java.util.Scanner; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; @@ -159,9 +156,16 @@ public void shouldStartTheWholeEnchilada() throws IOException, InterruptedExcept .withVhost("vhost2", true) .withExchange("direct-exchange", "direct") .withExchange("topic-exchange", "topic") + .withExchange("vhost1", "topic-exchange-2", "topic", false, false, true, Collections.emptyMap()) + .withExchange("vhost2", "topic-exchange-3", "topic") + .withExchange("topic-exchange-4", "topic", false, false, true, Collections.emptyMap()) .withQueue("queue1") .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) + .withQueue("vhost1", "queue3", true, false, ImmutableMap.of("x-message-ttl", 1000)) + .withQueue("vhost2", "queue4") .withBinding("direct-exchange", "queue1") + .withBinding("vhost1", "topic-exchange-2", "queue3") + .withBinding("vhost2", "topic-exchange-3", "queue4", Collections.emptyMap(), "ss7", "queue") .withUser("user1", "password1") .withUser("user2", "password2", ImmutableSet.of("administrator")) .withPermission("vhost1", "user1", ".*", ".*", ".*") @@ -175,15 +179,15 @@ public void shouldStartTheWholeEnchilada() throws IOException, InterruptedExcept assertThat(container.execInContainer("rabbitmqadmin", "list", "queues") .getStdout()) - .contains("queue1", "queue2"); + .contains("queue1", "queue2", "queue3", "queue4"); assertThat(container.execInContainer("rabbitmqadmin", "list", "exchanges") .getStdout()) - .contains("direct-exchange", "topic-exchange"); + .contains("direct-exchange", "topic-exchange", "topic-exchange-2", "topic-exchange-3", "topic-exchange-4"); assertThat(container.execInContainer("rabbitmqadmin", "list", "bindings") .getStdout()) - .contains("direct-exchange"); + .contains("direct-exchange", "topic-exchange-2", "topic-exchange-3"); assertThat(container.execInContainer("rabbitmqadmin", "list", "users") .getStdout()) From f41bdb2cda1b45e86db07507b18e8acbf8641cc6 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Fri, 13 May 2022 21:05:43 -0400 Subject: [PATCH 1876/4969] Read `indexServerAddress` from Docker's `/info` (#5347) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Read `indexServerAddress` from Docker's `/info` * remove `setIndexServerAddress` * Update fallback default registry name to `https://index.docker.io/v1/` * Fix build Co-authored-by: Kevin Wittek Co-authored-by: Eddú Meléndez Gonzales --- .../java/org/testcontainers/DockerClientFactory.java | 7 ++++++- .../dockerclient/DockerClientProviderStrategy.java | 7 +++++-- .../testcontainers/utility/RegistryAuthLocator.java | 12 ++++++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 6cf8f716704..cc85645b2b4 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -199,7 +199,7 @@ public void close() { }; log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); - Info dockerInfo = client.infoCmd().exec(); + Info dockerInfo = strategy.getInfo(); Version version = client.versionCmd().exec(); activeApiVersion = version.getApiVersion(); activeExecutionDriver = dockerInfo.getExecutionDriver(); @@ -434,4 +434,9 @@ public String getActiveExecutionDriver() { public boolean isUsing(Class providerStrategyClass) { return strategy != null && providerStrategyClass.isAssignableFrom(this.strategy.getClass()); } + + @UnstableAPI + public Info getInfo() { + return getOrInitializeStrategy().getInfo(); + } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index cf091e94328..834e670438a 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -65,6 +65,9 @@ public abstract class DockerClientProviderStrategy { private String dockerHostIpAddress; + @Getter + private Info info; + private final RateLimiter PING_RATE_LIMITER = RateLimiterBuilder.newBuilder() .withRate(10, TimeUnit.SECONDS) .withConstantThroughput() @@ -249,7 +252,7 @@ private static boolean tryOutStrategy(List configurationFailures, Docker return false; } - Info info = strategy.getDockerClient().infoCmd().exec(); + strategy.info = strategy.getDockerClient().infoCmd().exec(); log.info("Found Docker environment with {}", strategy.getDescription()); log.debug( "Transport type: '{}', Docker host: '{}'", @@ -258,7 +261,7 @@ private static boolean tryOutStrategy(List configurationFailures, Docker ); log.debug("Checking Docker OS type for {}", strategy.getDescription()); - String osType = info.getOsType(); + String osType = strategy.getInfo().getOsType(); if (StringUtils.isBlank(osType)) { log.warn("Could not determine Docker OS type"); } else if (!osType.equals("linux")) { diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index d88bdccd76a..e487bda686b 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -7,6 +7,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; +import org.testcontainers.DockerClientFactory; import org.zeroturnaround.exec.InvalidResultException; import org.zeroturnaround.exec.ProcessExecutor; @@ -32,7 +33,7 @@ public class RegistryAuthLocator { private static final Logger log = getLogger(RegistryAuthLocator.class); - private static final String DEFAULT_REGISTRY_NAME = "index.docker.io"; + private static final String DEFAULT_REGISTRY_NAME = "https://index.docker.io/v1/"; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static RegistryAuthLocator instance; @@ -282,7 +283,14 @@ private String getCredentialProgramName(String credHelper) { } private String effectiveRegistryName(DockerImageName dockerImageName) { - return StringUtils.defaultIfEmpty(dockerImageName.getRegistry(), DEFAULT_REGISTRY_NAME); + final String registry = dockerImageName.getRegistry(); + if (!StringUtils.isEmpty(registry)) { + return registry; + } + return StringUtils.defaultString( + DockerClientFactory.instance().getInfo().getIndexServerAddress(), + DEFAULT_REGISTRY_NAME + ); } private String getGenericCredentialsNotFoundMsg(String credentialHelperName) { From bf70b4093fd31850fe58d6d29af2039c1026ce23 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Sun, 15 May 2022 11:00:06 -0400 Subject: [PATCH 1877/4969] run `core` tests in parallel (#5365) * run `core` tests in parallel * ooops * Dummy change * dummy change (2) --- core/build.gradle | 2 + .../DockerClientFactoryTest.java | 38 +++++------- .../DockerRegistryContainer.java | 36 +++++++++++ .../dockerclient/AmbiguousImagePullTest.java | 31 ++++------ .../images/ImagePullPolicyTest.java | 59 +++--------------- .../utility/AuthenticatedImagePullTest.java | 62 +++---------------- 6 files changed, 79 insertions(+), 149 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 3f1ad71731d..b519673de4b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -6,6 +6,8 @@ sourceSets { jarFileTest } +test.maxParallelForks = 4 + idea.module.testSourceDirs += sourceSets.jarFileTest.allSource.srcDirs shadowJar { diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index 4dcfc26349f..247a16a76a6 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -1,18 +1,16 @@ package org.testcontainers; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import com.github.dockerjava.api.exception.NotFoundException; import org.junit.Rule; import org.junit.Test; import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory.DiskSpaceUsage; import org.testcontainers.dockerclient.LogToStringContainerCallback; -import org.testcontainers.images.LocalImagesCacheAccessor; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MockTestcontainersConfigurationRule; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + /** * Test for {@link DockerClientFactory}. */ @@ -23,30 +21,22 @@ public class DockerClientFactoryTest { @Test public void runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally() { + try (DockerRegistryContainer registryContainer = new DockerRegistryContainer()) { + registryContainer.start(); + DockerImageName imageName = registryContainer.createImage(); - final DockerClientFactory dockFactory = DockerClientFactory.instance(); + DockerClientFactory dockFactory = DockerClientFactory.instance(); - DockerImageName imageName = DockerImageName.parse("testcontainers/helloworld:1.1.0"); - - try { - //remove tiny image, so it will be pulled during next command run - dockFactory.client() - .removeImageCmd(imageName.asCanonicalNameString()) - .withForce(true).exec(); - } catch (NotFoundException ignored) { - // Do not fail if it's not pulled yet - } - LocalImagesCacheAccessor.clearCache(); - - dockFactory.runInsideDocker( + dockFactory.runInsideDocker( imageName, cmd -> cmd.withCmd("sh", "-c", "echo 'SUCCESS'"), (client, id) -> - client.logContainerCmd(id) - .withStdOut(true) - .exec(new LogToStringContainerCallback()) - .toString() - ); + client.logContainerCmd(id) + .withStdOut(true) + .exec(new LogToStringContainerCallback()) + .toString() + ); + } } @Test diff --git a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java index 641b1553d72..4018b2b954d 100644 --- a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java +++ b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java @@ -1,6 +1,9 @@ package org.testcontainers; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.command.PullImageResultCallback; import lombok.Getter; import lombok.NonNull; import lombok.SneakyThrows; @@ -8,7 +11,10 @@ import org.testcontainers.containers.output.FrameConsumerResultCallback; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.WaitingConsumer; +import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; +import java.util.UUID; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -65,4 +71,34 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { endpoint = getHost() + ":" + port.get(); } + + public DockerImageName createImage() { + return createImage(UUID.randomUUID().toString()); + } + + public DockerImageName createImage(String tag) { + return createImage("testcontainers/helloworld:latest", tag); + } + + @SneakyThrows(InterruptedException.class) + public DockerImageName createImage(String originalImage, String tag) { + DockerClient client = getDockerClient(); + client.pullImageCmd(originalImage).exec(new PullImageResultCallback()).awaitCompletion(); + + String dummyImageId = client.inspectImageCmd(originalImage).exec().getId(); + + DockerImageName imageName = DockerImageName.parse(getEndpoint() + "/" + Base58.randomString(6).toLowerCase()).withTag(tag); + + // push the image to the registry + client.tagImageCmd(dummyImageId, imageName.asCanonicalNameString(), tag).exec(); + + client.pushImageCmd(imageName.asCanonicalNameString()) + .exec(new ResultCallback.Adapter<>()) + .awaitCompletion(1, TimeUnit.MINUTES); + + // Remove from local cache, tests should pull the image themselves + client.removeImageCmd(imageName.asCanonicalNameString()).exec(); + + return imageName; + } } diff --git a/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java index 9e62148c3bb..2e39b367c46 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java @@ -1,32 +1,25 @@ package org.testcontainers.dockerclient; -import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.model.Image; import org.junit.Test; -import org.testcontainers.DockerClientFactory; +import org.testcontainers.DockerRegistryContainer; import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; -import java.util.List; - public class AmbiguousImagePullTest { @Test(timeout = 30_000) public void testNotUsingParse() { - DockerClient client = DockerClientFactory.instance().client(); - List alpineImages = client.listImagesCmd() - .withImageNameFilter("testcontainers/helloworld:latest") - .exec(); - for (Image alpineImage : alpineImages) { - client.removeImageCmd(alpineImage.getId()).exec(); - } - - try ( - final GenericContainer container = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld")) - .withExposedPorts(8080) - ) { - container.start(); - // do nothing other than start and stop + try (DockerRegistryContainer registryContainer = new DockerRegistryContainer()) { + registryContainer.start(); + DockerImageName imageName = registryContainer.createImage("latest"); + String imageNameWithoutTag = imageName.getRegistry() + "/" + imageName.getRepository(); + try ( + final GenericContainer container = new GenericContainer<>(imageNameWithoutTag) + .withExposedPorts(8080) + ) { + container.start(); + // do nothing other than start and stop + } } } } diff --git a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java index 85c2e785652..9d5ed400d32 100644 --- a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java @@ -1,12 +1,6 @@ package org.testcontainers.images; -import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.async.ResultCallback; -import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.exception.NotFoundException; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.mockito.Mockito; @@ -18,9 +12,6 @@ import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.utility.DockerImageName; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -29,47 +20,13 @@ public class ImagePullPolicyTest { @ClassRule public static DockerRegistryContainer registry = new DockerRegistryContainer(); - private static DockerImageName imageName; - - @BeforeClass - public static void beforeClass() throws Exception { - String testRegistryAddress = registry.getEndpoint(); - String testImageName = testRegistryAddress + "/image-pull-policy-test"; - String tag = UUID.randomUUID().toString(); - imageName = DockerImageName.parse(testImageName).withTag(tag); - - DockerClient client = DockerClientFactory.instance().client(); - String dummySourceImage = "hello-world:latest"; - client.pullImageCmd(dummySourceImage).exec(new PullImageResultCallback()).awaitCompletion(); - - String dummyImageId = client.inspectImageCmd(dummySourceImage).exec().getId(); - - // push the image to the registry - client.tagImageCmd(dummyImageId, testImageName, tag).exec(); - - client.pushImageCmd(imageName.asCanonicalNameString()) - .exec(new ResultCallback.Adapter<>()) - .awaitCompletion(1, TimeUnit.MINUTES); - } - - @AfterClass - public static void afterClass() { - removeImage(); - } - - @Before - public void setUp() { - // Clean up local cache - removeImage(); - - LocalImagesCache.INSTANCE.cache.remove(imageName); - } + private final DockerImageName imageName = registry.createImage(); @Test public void pullsByDefault() { try ( GenericContainer container = new GenericContainer<>(imageName) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withExposedPorts(8080) ) { container.start(); } @@ -79,7 +36,7 @@ public void pullsByDefault() { public void shouldAlwaysPull() { try ( GenericContainer container = new GenericContainer<>(imageName) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withExposedPorts(8080) ) { container.start(); } @@ -88,7 +45,7 @@ public void shouldAlwaysPull() { try ( GenericContainer container = new GenericContainer<>(imageName) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withExposedPorts(8080) ) { expectToFailWithNotFoundException(container); } @@ -99,7 +56,7 @@ public void shouldAlwaysPull() { .withImagePullPolicy(PullPolicy.alwaysPull()) // } ) { - container.withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + container.withExposedPorts(8080); container.start(); } } @@ -117,7 +74,7 @@ protected boolean shouldPullCached(DockerImageName imageName, ImageData localIma }) // } ) { - container.withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + container.withExposedPorts(8080); container.start(); } } @@ -133,7 +90,7 @@ protected boolean shouldPullCached(DockerImageName imageName, ImageData localIma try ( GenericContainer container = new GenericContainer<>(imageName) .withImagePullPolicy(policy) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withExposedPorts(8080) ) { container.start(); @@ -169,7 +126,7 @@ private void expectToFailWithNotFoundException(GenericContainer container) { } } - private static void removeImage() { + private void removeImage() { try { DockerClientFactory.instance().client() .removeImageCmd(imageName.asCanonicalNameString()) diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 412a945b204..a911675dfb3 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -1,37 +1,28 @@ package org.testcontainers.utility; -import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.async.ResultCallback; -import com.github.dockerjava.api.command.PullImageResultCallback; -import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AuthConfig; import org.intellij.lang.annotations.Language; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.mockito.Mockito; -import org.testcontainers.DockerClientFactory; import org.testcontainers.DockerRegistryContainer; import org.testcontainers.containers.ContainerState; import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.images.LocalImagesCacheAccessor; import org.testcontainers.images.builder.ImageFromDockerfile; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.concurrent.TimeUnit; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.when; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; import static org.testcontainers.TestImages.DOCKER_REGISTRY_IMAGE; -import static org.testcontainers.TestImages.TINY_IMAGE; /** * This test checks the integration between Testcontainers and an authenticated registry, but uses @@ -57,20 +48,15 @@ public class AuthenticatedImagePullTest { })); private static RegistryAuthLocator originalAuthLocatorSingleton; - private static DockerClient client; - private static String testImageName; - private static RegistryAuthLocator mockAuthLocator; + private final DockerImageName testImageName = authenticatedRegistry.createImage(); @BeforeClass - public static void setUp() throws Exception { + public static void beforeClass() throws Exception { originalAuthLocatorSingleton = RegistryAuthLocator.instance(); - client = DockerClientFactory.instance().client(); String testRegistryAddress = authenticatedRegistry.getEndpoint(); - testImageName = testRegistryAddress + "/alpine"; - final DockerImageName expectedName = DockerImageName.parse(testImageName); final AuthConfig authConfig = new AuthConfig() .withUsername("testuser") .withPassword("notasecret") @@ -79,22 +65,8 @@ public static void setUp() throws Exception { // Replace the RegistryAuthLocator singleton with our mock, for the duration of this test final RegistryAuthLocator mockAuthLocator = Mockito.mock(RegistryAuthLocator.class); RegistryAuthLocator.setInstance(mockAuthLocator); - when(mockAuthLocator.lookupAuthConfig(eq(expectedName), any())) + when(mockAuthLocator.lookupAuthConfig(argThat(argument -> testRegistryAddress.equals(argument.getRegistry())), any())) .thenReturn(authConfig); - - // a push will use the auth locator for authentication, although that isn't the goal of this test - putImageInRegistry(); - } - - @Before - public void removeImageFromLocalDocker() { - // remove the image tag from local docker so that it must be pulled before use - try { - client.removeImageCmd(testImageName).withForce(true).exec(); - } catch (NotFoundException ignored) { - - } - LocalImagesCacheAccessor.clearCache(); } @AfterClass @@ -105,7 +77,7 @@ public static void tearDown() { @Test public void testThatAuthLocatorIsUsedForContainerCreation() { // actually start a container, which will require an authenticated pull - try (final GenericContainer container = new GenericContainer<>(DockerImageName.parse(testImageName)) + try (final GenericContainer container = new GenericContainer<>(testImageName) .withCommand("/bin/sh", "-c", "sleep 10")) { container.start(); @@ -117,7 +89,7 @@ public void testThatAuthLocatorIsUsedForContainerCreation() { public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { // Prepare a simple temporary Dockerfile which requires our custom private image Path tempFile = getLocalTempFile(".Dockerfile"); - String dockerFileContent = "FROM " + testImageName; + String dockerFileContent = "FROM " + testImageName.asCanonicalNameString(); Files.write(tempFile, dockerFileContent.getBytes()); // Start a container built from a derived image, which will require an authenticated pull @@ -141,7 +113,7 @@ public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { "services:\n" + " privateservice:\n" + " command: /bin/sh -c 'sleep 60'\n" + - " image: " + testImageName; + " image: " + testImageName.asCanonicalNameString(); Files.write(tempFile, composeFileContent.getBytes()); // Start the docker compose project, which will require an authenticated pull @@ -168,24 +140,4 @@ private Path getLocalTempFile(String s) throws IOException { return tempFile; } - - private static void putImageInRegistry() throws InterruptedException { - // It doesn't matter which image we use for this test, but use one that's likely to have been pulled already - final String dummySourceImage = TINY_IMAGE.asCanonicalNameString(); - - client.pullImageCmd(dummySourceImage) - .exec(new PullImageResultCallback()) - .awaitCompletion(1, TimeUnit.MINUTES); - - final String id = client.inspectImageCmd(dummySourceImage) - .exec() - .getId(); - - // push the image to the registry - client.tagImageCmd(id, testImageName, "").exec(); - - client.pushImageCmd(testImageName) - .exec(new ResultCallback.Adapter<>()) - .awaitCompletion(1, TimeUnit.MINUTES); - } } From c0183f1d81ae2637d8ed70634ce643e3c75263b0 Mon Sep 17 00:00:00 2001 From: Andriy Redko Date: Mon, 16 May 2022 11:57:23 -0400 Subject: [PATCH 1878/4969] Allow insecure HTTPS/TLS connection for HttpWaitStrategy (#4951) Signed-off-by: Andriy Redko --- .../wait/strategy/HttpWaitStrategy.java | 63 ++++++++++++++++++- .../wait/strategy/HttpWaitStrategyTest.java | 19 ++++++ .../ElasticsearchContainerTest.java | 23 +++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java index c4751725707..d5d08ce6fd0 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java @@ -12,15 +12,26 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.time.Duration; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + import static org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess; @Slf4j @@ -47,6 +58,7 @@ public class HttpWaitStrategy extends AbstractWaitStrategy { private Predicate statusCodePredicate = null; private Optional livenessPort = Optional.empty(); private Duration readTimeout = Duration.ofSeconds(1); + private boolean allowInsecure; /** * Waits for the given status code. @@ -112,6 +124,16 @@ public HttpWaitStrategy withMethod(String method) { return this; } + /** + * Indicates that HTTPS connection could use untrusted (self signed) certificate chains. + * + * @return this + */ + public HttpWaitStrategy allowInsecure() { + this.allowInsecure = true; + return this; + } + /** * Authenticate with HTTP Basic Authorization credentials. * @@ -206,7 +228,7 @@ protected void waitUntilReady() { retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> { getRateLimiter().doWhenReady(() -> { try { - final HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection(); + final HttpURLConnection connection = openConnection(uri); connection.setReadTimeout(Math.toIntExact(readTimeout.toMillis())); // authenticate @@ -267,6 +289,45 @@ protected void waitUntilReady() { } } + private HttpURLConnection openConnection(final String uri) throws IOException, MalformedURLException { + if (tlsEnabled) { + final HttpsURLConnection connection = (HttpsURLConnection)new URL(uri).openConnection(); + if (allowInsecure) { + // Create a trust manager that does not validate certificate chains + // and trust all certificates + final TrustManager[] trustAllCerts = new TrustManager[] { + new X509TrustManager() { + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + @Override + public void checkClientTrusted(final X509Certificate[] certs, final String authType) { + } + + @Override + public void checkServerTrusted(final X509Certificate[] certs, final String authType) { + } + } + }; + + try { + // Create custom SSL context and set the "trust all certificates" trust manager + final SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(new KeyManager[0], trustAllCerts, new SecureRandom()); + connection.setSSLSocketFactory(sc.getSocketFactory()); + } catch (final NoSuchAlgorithmException | KeyManagementException ex) { + throw new IOException("Unable to create custom SSL factory instance", ex); + } + } + + return connection; + } else { + return (HttpURLConnection) new URL(uri).openConnection(); + } + } + /** * Build the URI on which to check if the container is ready. * diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java index c5a39a4538c..82207b4537e 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java @@ -57,6 +57,17 @@ public void testWaitUntilReadyWithSuccessWithCustomHeaders() { assertThat(logs, containsString("baz: boo")); } + /** + * Ensures that HTTPS requests made with the HttpWaitStrategy can skip the + * certificate validation chains (to support self-signed certificates for example). + */ + @Test + public void testWaitUntilReadyWithTlsAndAllowUnsecure() { + waitUntilReadyAndSucceed(startContainerWithCommand(createHttpsShellCommand("200 OK", GOOD_RESPONSE_BODY, 8080), + createHttpWaitStrategy(ready).usingTls().allowInsecure() + )); + } + /** * Expects that the WaitStrategy returns successfully after receiving an HTTP 401 response from the container. * This 401 response is checked with a lambda using {@link HttpWaitStrategy#forStatusCodeMatching(Predicate)} @@ -206,4 +217,12 @@ private String createShellCommand(String header, String responseBody, int port) "Content-Length: " + length + NEWLINE + "\";" + " echo \"" + responseBody + "\";} | nc -lp " + port + "; done"; } + + private String createHttpsShellCommand(String header, String responseBody, int port) { + int length = responseBody.getBytes().length; + return "apk add nmap-ncat; while true; do { echo -e \"HTTP/1.1 " + header + NEWLINE + + "Content-Type: text/html" + NEWLINE + + "Content-Length: " + length + NEWLINE + "\";" + + " echo \"" + responseBody + "\";} | ncat -lp " + port + " --ssl; done"; + } } diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index f8131268e61..5b6b5ce3194 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -19,6 +19,8 @@ import org.junit.After; import org.junit.Test; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; @@ -282,6 +284,27 @@ public void testElasticsearch8SecureByDefaultCustomCaCertFails() throws Exceptio } } + @Test + public void testElasticsearch8SecureByDefaultHttpWaitStrategy() throws Exception { + final HttpWaitStrategy httpsWaitStrategy = Wait.forHttps("/") + .forPort(9200) + .forStatusCode(200) + .withBasicCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD) + // trusting self-signed certificate + .allowInsecure(); + + try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.1.2") + .waitingFor(httpsWaitStrategy)) { + + // Start the container. This step might take some time... + container.start(); + + Response response = getClusterHealth(container); + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + } + } + @Test public void testElasticsearch8SecureByDefaultFailsSilentlyOnLatestImages() throws Exception { // this test exists for custom images by users that use the `latest` tag From 98b60fbf87f4f65f96651bee919c8f8027fe0cc5 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Mon, 16 May 2022 13:27:39 -0400 Subject: [PATCH 1879/4969] Use `GenericContainer` in `RyukResourceReaper` (#5358) * Experiment: Use `GenericContainer` in `RyukResourceReaper` * reduce global `DockerClient` usage * revert indentation * Avoid bind check * Fix `japicmp` * Add `ResourceReaperTest` --- core/build.gradle | 10 +- .../ComposeServiceWaitStrategyTarget.java | 8 +- .../testcontainers/containers/Container.java | 6 +- .../containers/ContainerState.java | 16 ++- .../containers/DockerComposeContainer.java | 9 +- .../containers/ExecInContainerPattern.java | 36 ++++- .../containers/GenericContainer.java | 4 +- .../IsRunningStartupCheckStrategy.java | 17 ++- .../startupcheck/StartupCheckStrategy.java | 10 ++ .../InternalCommandPortListeningCheck.java | 2 +- .../wait/strategy/LogMessageWaitStrategy.java | 2 +- .../utility/ResourceReaper.java | 12 ++ .../testcontainers/utility/RyukContainer.java | 27 ++++ .../utility/RyukResourceReaper.java | 135 ++++-------------- .../utility/ResourceReaperTest.java | 109 ++++++++++++++ 15 files changed, 257 insertions(+), 146 deletions(-) create mode 100644 core/src/main/java/org/testcontainers/utility/RyukContainer.java create mode 100644 core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java diff --git a/core/build.gradle b/core/build.gradle index b519673de4b..1988063489e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -43,12 +43,8 @@ tasks.japicmp { classExcludes = [] methodExcludes = [ - "org.testcontainers.utility.ResourceReaper#start(java.lang.String,com.github.dockerjava.api.DockerClient)", - "org.testcontainers.utility.ResourceReaper#start(com.github.dockerjava.api.DockerClient)", - "org.testcontainers.utility.ResourceReaper#registerNetworkForCleanup(java.lang.String)", - "org.testcontainers.utility.ResourceReaper#removeNetworks(java.lang.String)", - "org.testcontainers.images.builder.Transferable#of(java.lang.String)", - "org.testcontainers.images.builder.Transferable#updateChecksum(java.util.zip.Checksum)" + "org.testcontainers.containers.Container#getDockerClient()", + "org.testcontainers.containers.ContainerState#getDockerClient()", ] fieldExcludes = [] @@ -62,7 +58,7 @@ configurations.all { } dependencies { - baseline 'org.testcontainers:testcontainers:1.16.3', { + baseline 'org.testcontainers:testcontainers:1.17.1', { exclude group: "*", module: "*" } diff --git a/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java b/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java index 2fb953b4aee..fbb2a7cee6e 100644 --- a/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java +++ b/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java @@ -1,11 +1,11 @@ package org.testcontainers.containers; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.Container; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; -import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; import java.util.ArrayList; @@ -22,13 +22,15 @@ class ComposeServiceWaitStrategyTarget implements WaitStrategyTarget { private final Container container; private final GenericContainer proxyContainer; + private final DockerClient dockerClient; @NonNull private Map mappedPorts; @Getter(lazy=true) - private final InspectContainerResponse containerInfo = DockerClientFactory.instance().client().inspectContainerCmd(getContainerId()).exec(); + private final InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(getContainerId()).exec(); - ComposeServiceWaitStrategyTarget(Container container, GenericContainer proxyContainer, + ComposeServiceWaitStrategyTarget(DockerClient dockerClient, Container container, GenericContainer proxyContainer, @NonNull Map mappedPorts) { + this.dockerClient = dockerClient; this.container = container; this.proxyContainer = proxyContainer; this.mappedPorts = new HashMap<>(mappedPorts); diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index 8fd53fc5a0e..88fe4802945 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -389,7 +389,7 @@ default SELF withClasspathResourceMapping(final String resourcePath, final Strin * @param consumer consumer that the frames should be sent to */ default void followOutput(Consumer consumer) { - LogUtils.followOutput(DockerClientFactory.instance().client(), getContainerId(), consumer); + LogUtils.followOutput(getDockerClient(), getContainerId(), consumer); } /** @@ -400,7 +400,7 @@ default void followOutput(Consumer consumer) { * @param types types that should be followed (one or both of STDOUT, STDERR) */ default void followOutput(Consumer consumer, OutputFrame.OutputType... types) { - LogUtils.followOutput(DockerClientFactory.instance().client(), getContainerId(), consumer, types); + LogUtils.followOutput(getDockerClient(), getContainerId(), consumer, types); } @@ -439,8 +439,6 @@ default void followOutput(Consumer consumer, OutputFrame.OutputType @Deprecated Map getLinkedContainers(); - DockerClient getDockerClient(); - void setExposedPorts(List exposedPorts); void setPortBindings(List portBindings); diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index ef2c19a06c9..51eb4daddde 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -52,6 +52,10 @@ default String getContainerIpAddress() { return getHost(); } + default DockerClient getDockerClient() { + return DockerClientFactory.lazyClient(); + } + /** * Get the host that this container may be reached on (may not be the local machine). * @@ -115,7 +119,7 @@ default boolean isHealthy() { } default InspectContainerResponse getCurrentContainerInfo() { - return DockerClientFactory.instance().client().inspectContainerCmd(getContainerId()).exec(); + return getDockerClient().inspectContainerCmd(getContainerId()).exec(); } /** @@ -195,7 +199,7 @@ default List getBoundPortNumbers() { * @return all log output from the container from start until the current instant (both stdout and stderr) */ default String getLogs() { - return LogUtils.getOutput(DockerClientFactory.instance().client(), getContainerId()); + return LogUtils.getOutput(getDockerClient(), getContainerId()); } /** @@ -203,7 +207,7 @@ default String getLogs() { * @return all log output from the container from start until the current instant */ default String getLogs(OutputFrame.OutputType... types) { - return LogUtils.getOutput(DockerClientFactory.instance().client(), getContainerId(), types); + return LogUtils.getOutput(getDockerClient(), getContainerId(), types); } /** @@ -234,7 +238,7 @@ default Container.ExecResult execInContainer(String... command) throws Unsupport * @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, Charset, String...) */ default Container.ExecResult execInContainer(Charset outputCharset, String... command) throws UnsupportedOperationException, IOException, InterruptedException { - return ExecInContainerPattern.execInContainer(getContainerInfo(), outputCharset, command); + return ExecInContainerPattern.execInContainer(getDockerClient(), getContainerInfo(), outputCharset, command); } /** @@ -279,7 +283,7 @@ default void copyFileToContainer(Transferable transferable, String containerPath transferable.transferTo(tarArchive, containerPath); tarArchive.finish(); - DockerClientFactory.instance().client() + getDockerClient() .copyArchiveToContainerCmd(getContainerId()) .withTarInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) .withRemotePath("/") @@ -316,7 +320,7 @@ default T copyFileFromContainer(String containerPath, ThrowingFunction composeFiles) { - this.composeFiles = composeFiles; this.dockerComposeFiles = new DockerComposeFiles(composeFiles); @@ -132,7 +131,7 @@ public DockerComposeContainer(String identifier, List composeFiles) { this.identifier = identifier; this.project = randomProjectId(); - this.dockerClient = DockerClientFactory.instance().client(); + this.dockerClient = DockerClientFactory.lazyClient(); } @Override @@ -269,7 +268,7 @@ private void waitUntilServiceStarted() { private void createServiceInstance(Container container) { String serviceName = getServiceNameFromContainer(container); - final ComposeServiceWaitStrategyTarget containerInstance = new ComposeServiceWaitStrategyTarget(container, + final ComposeServiceWaitStrategyTarget containerInstance = new ComposeServiceWaitStrategyTarget(dockerClient, container, ambassadorContainer, ambassadorPortMappings.getOrDefault(serviceName, new HashMap<>())); String containerId = containerInstance.getContainerId(); @@ -559,7 +558,7 @@ public Optional getContainerByServiceName(String serviceName) { } private void followLogs(String containerId, Consumer consumer) { - LogUtils.followOutput(DockerClientFactory.instance().client(), containerId, consumer); + LogUtils.followOutput(dockerClient, containerId, consumer); } private SELF self() { @@ -659,7 +658,7 @@ public void invoke() { AuditLogger.doComposeLog(this.getCommandParts(), this.getEnv()); - final Integer exitCode = this.dockerClient.inspectContainerCmd(getContainerId()) + final Integer exitCode = getDockerClient().inspectContainerCmd(getContainerId()) .exec() .getState() .getExitCode(); diff --git a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java index 9cd68d48ffb..0858476880f 100644 --- a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java +++ b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; /** * Provides utility methods for executing commands in containers @@ -22,17 +23,41 @@ @Slf4j public class ExecInContainerPattern { + + /** + * + * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, String...)} + */ + @Deprecated + public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, String... command) + throws UnsupportedOperationException, IOException, InterruptedException { + DockerClient dockerClient = DockerClientFactory.instance().client(); + return execInContainer(dockerClient, containerInfo, command); + } + + /** + * + * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, Charset, String...)} + */ + @Deprecated + public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, Charset outputCharset, String... command) + throws UnsupportedOperationException, IOException, InterruptedException { + DockerClient dockerClient = DockerClientFactory.instance().client(); + return execInContainer(dockerClient, containerInfo, outputCharset, command); + } + /** * Run a command inside a running container, as though using "docker exec", and interpreting * the output as UTF8. *

+ * @param dockerClient the {@link DockerClient} * @param containerInfo the container info * @param command the command to execute - * @see #execInContainer(InspectContainerResponse, Charset, String...) + * @see #execInContainer(DockerClient, InspectContainerResponse, Charset, String...) */ - public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, String... command) + public Container.ExecResult execInContainer(DockerClient dockerClient, InspectContainerResponse containerInfo, String... command) throws UnsupportedOperationException, IOException, InterruptedException { - return execInContainer(containerInfo, Charset.forName("UTF-8"), command); + return execInContainer(dockerClient, containerInfo, StandardCharsets.UTF_8, command); } /** @@ -40,6 +65,7 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn *

* This functionality is not available on a docker daemon running the older "lxc" execution driver. At * the time of writing, CircleCI was using this driver. + * @param dockerClient the {@link DockerClient} * @param containerInfo the container info * @param outputCharset the character set used to interpret the output. * @param command the parts of the command to run @@ -48,7 +74,7 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn * @throws InterruptedException if the thread waiting for the response is interrupted * @throws UnsupportedOperationException if the docker daemon you're connecting to doesn't support "exec". */ - public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, Charset outputCharset, String... command) + public Container.ExecResult execInContainer(DockerClient dockerClient, InspectContainerResponse containerInfo, Charset outputCharset, String... command) throws UnsupportedOperationException, IOException, InterruptedException { if (!TestEnvironment.dockerExecutionDriverSupportsExec()) { // at time of writing, this is the expected result in CircleCI. @@ -64,8 +90,6 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn String containerId = containerInfo.getId(); String containerName = containerInfo.getName(); - DockerClient dockerClient = DockerClientFactory.instance().client(); - log.debug("{}: Running \"exec\" command: {}", containerName, String.join(" ", command)); final ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId) .withAttachStdout(true).withAttachStderr(true).withCmd(command).exec(); diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index d47bc6cfc5e..4e5e682738d 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -416,7 +416,7 @@ private void tryStart(Instant startedAt) { if (!reusable) { //noinspection deprecation - createCommand.getLabels().putAll(ResourceReaper.instance().getLabels()); + createCommand = ResourceReaper.instance().register(this, createCommand); } if (!reused) { @@ -469,7 +469,7 @@ private void tryStart(Instant startedAt) { containerIsStarting(containerInfo, reused); // Wait until the container has reached the desired running state - if (!this.startupCheckStrategy.waitUntilStartupSuccessful(dockerClient, containerId)) { + if (!this.startupCheckStrategy.waitUntilStartupSuccessful(this)) { // Bail out, don't wait for the port to start listening. // (Exception thrown here will be caught below and wrapped) throw new IllegalStateException("Container did not start correctly."); diff --git a/core/src/main/java/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.java b/core/src/main/java/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.java index 6a296e0329c..b4b20aad897 100644 --- a/core/src/main/java/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse; +import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerStatus; /** @@ -10,10 +11,24 @@ */ public class IsRunningStartupCheckStrategy extends StartupCheckStrategy { + @SuppressWarnings("deprecation") + @Override + public boolean waitUntilStartupSuccessful(GenericContainer container) { + // Optimization: container already has the initial "after start" state, check it first + if (checkState(container.getContainerInfo().getState()) == StartupStatus.SUCCESSFUL) { + return true; + } + return super.waitUntilStartupSuccessful(container); + } + @Override public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { InspectContainerResponse.ContainerState state = getCurrentState(dockerClient, containerId); - if (state.getRunning()) { + return checkState(state); + } + + private StartupStatus checkState(InspectContainerResponse.ContainerState state) { + if (Boolean.TRUE.equals(state.getRunning())) { return StartupStatus.SUCCESSFUL; } else if (!DockerStatus.isContainerExitCodeSuccess(state)) { return StartupStatus.FAILED; diff --git a/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java b/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java index 1425123473b..d5931454212 100644 --- a/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java @@ -5,6 +5,7 @@ import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.containers.GenericContainer; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -30,6 +31,15 @@ public SELF withTimeout(Duration timeout) { return (SELF) this; } + /** + * + * @deprecated internal API + */ + @Deprecated + public boolean waitUntilStartupSuccessful(GenericContainer container) { + return waitUntilStartupSuccessful(container.getDockerClient(), container.getContainerId()); + } + public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { final Boolean[] startedOK = {null}; Unreliables.retryUntilTrue((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> { diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index 379840a9d7e..1eba8acbbd1 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -40,7 +40,7 @@ public Boolean call() { Instant before = Instant.now(); try { - ExecResult result = ExecInContainerPattern.execInContainer(waitStrategyTarget.getContainerInfo(), "/bin/sh", "-c", command.toString()); + ExecResult result = ExecInContainerPattern.execInContainer(waitStrategyTarget.getDockerClient(), waitStrategyTarget.getContainerInfo(), "/bin/sh", "-c", command.toString()); log.trace("Check for {} took {}. Result code '{}', stdout message: '{}'", internalPorts, Duration.between(before, Instant.now()), result.getExitCode(), result.getStdout()); int exitCode = result.getExitCode(); if (exitCode != 0 && exitCode != 1) { diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java index 9f7a0078f00..65370e51bfa 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java @@ -27,7 +27,7 @@ public class LogMessageWaitStrategy extends AbstractWaitStrategy { protected void waitUntilReady() { WaitingConsumer waitingConsumer = new WaitingConsumer(); - LogContainerCmd cmd = DockerClientFactory.instance().client().logContainerCmd(waitStrategyTarget.getContainerId()) + LogContainerCmd cmd = waitStrategyTarget.getDockerClient().logContainerCmd(waitStrategyTarget.getContainerId()) .withFollowStream(true) .withSince(0) .withStdOut(true) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index 44f9456ce4c..d916579db35 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -1,6 +1,7 @@ package org.testcontainers.utility; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Network; @@ -11,6 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; import java.io.BufferedReader; import java.io.IOException; @@ -307,6 +309,16 @@ public Map getLabels() { return MARKER_LABELS; } + /** + * + * @deprecated internal API + */ + @Deprecated + public CreateContainerCmd register(GenericContainer container, CreateContainerCmd cmd) { + cmd.getLabels().putAll(getLabels()); + return cmd; + } + /** * @deprecated internal API */ diff --git a/core/src/main/java/org/testcontainers/utility/RyukContainer.java b/core/src/main/java/org/testcontainers/utility/RyukContainer.java new file mode 100644 index 00000000000..1e18c14157a --- /dev/null +++ b/core/src/main/java/org/testcontainers/utility/RyukContainer.java @@ -0,0 +1,27 @@ +package org.testcontainers.utility; + +import com.github.dockerjava.api.model.Bind; +import com.github.dockerjava.api.model.Volume; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; + +class RyukContainer extends GenericContainer { + + RyukContainer() { + super("testcontainers/ryuk:0.3.3"); + + withExposedPorts(8080); + withCreateContainerCmdModifier(cmd -> { + cmd.withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID); + cmd.withHostConfig( + cmd.getHostConfig() + .withAutoRemove(true) + .withPrivileged(TestcontainersConfiguration.getInstance().isRyukPrivileged()) + .withBinds(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))) + ); + }); + + waitingFor(Wait.forLogMessage(".*Started.*", 1)); + } +} diff --git a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java index 9efbf5ed972..c2e2cf4ef97 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java @@ -1,40 +1,21 @@ package org.testcontainers.utility; -import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.async.ResultCallback; -import com.github.dockerjava.api.command.InspectContainerResponse; -import com.github.dockerjava.api.model.Bind; -import com.github.dockerjava.api.model.ExposedPort; -import com.github.dockerjava.api.model.Frame; -import com.github.dockerjava.api.model.HostConfig; -import com.github.dockerjava.api.model.PortBinding; -import com.github.dockerjava.api.model.Ports; -import com.github.dockerjava.api.model.Volume; -import lombok.Getter; +import com.github.dockerjava.api.command.CreateContainerCmd; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.ContainerState; -import org.testcontainers.images.RemoteDockerImage; +import org.testcontainers.containers.GenericContainer; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.awaitility.Awaitility.await; /** * Ryuk-based {@link ResourceReaper} implementation. @@ -54,8 +35,11 @@ public class RyukResourceReaper extends ResourceReaper { private final AtomicBoolean started = new AtomicBoolean(false); - @Getter - private String containerId = null; + private final RyukContainer ryukContainer = new RyukContainer(); + + public String getContainerId() { + return ryukContainer.getContainerId(); + } @Override public void init() { @@ -80,91 +64,29 @@ public Map getLabels() { return super.getLabels(); } + @Override + public CreateContainerCmd register(GenericContainer container, CreateContainerCmd cmd) { + if (container == ryukContainer) { + // Do not register Ryuk container to avoid self-pruning + return cmd; + } + + maybeStart(); + return super.register(container, cmd); + } + @SneakyThrows(InterruptedException.class) private synchronized void maybeStart() { if (!started.compareAndSet(false, true)) { return; } - DockerClient client = DockerClientFactory.lazyClient(); - RemoteDockerImage ryukImage = new RemoteDockerImage(DockerImageName.parse("testcontainers/ryuk:0.3.3")); - - List binds = new ArrayList<>(); - binds.add(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))); - - ExposedPort ryukExposedPort = ExposedPort.tcp(8080); - containerId = client.createContainerCmd(ryukImage.get()) - .withHostConfig( - new HostConfig() - .withAutoRemove(true) - .withPortBindings(new PortBinding(Ports.Binding.empty(), ryukExposedPort)) - ) - .withExposedPorts(ryukExposedPort) - .withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID) - .withLabels(Collections.singletonMap(DockerClientFactory.TESTCONTAINERS_LABEL, "true")) - .withBinds(binds) - .withPrivileged(TestcontainersConfiguration.getInstance().isRyukPrivileged()) - .exec() - .getId(); - - client.startContainerCmd(containerId).exec(); - - StringBuilder ryukLog = new StringBuilder(); - - ResultCallback.Adapter logCallback = client.logContainerCmd(containerId) - .withSince(0) - .withFollowStream(true) - .withStdOut(true) - .withStdErr(true) - .exec(new ResultCallback.Adapter() { - @Override - public void onNext(Frame frame) { - ryukLog.append(new String(frame.getPayload(), StandardCharsets.UTF_8)); - } - }); - - InspectContainerResponse inspectedContainer; - try { - // inspect container response might initially not contain the mapped port - inspectedContainer = await() - .atMost(5, TimeUnit.SECONDS) - .pollInterval(DynamicPollInterval.ofMillis(50)) - .pollInSameThread() - .until( - () -> client.inspectContainerCmd(containerId).exec(), - inspectContainerResponse -> { - return inspectContainerResponse - .getNetworkSettings() - .getPorts() - .getBindings() - .values() - .stream() - .anyMatch(Objects::nonNull); - } - ); - } catch (Exception e) { - log.warn("Ryuk container cannot be inspected and probably had a problem starting. Ryuk's logs:\n{}", ryukLog); - throw new IllegalStateException("Ryuk failed to start", e); - } - - ContainerState containerState = new ContainerState() { - - @Override - public List getExposedPorts() { - return Stream.of(getContainerInfo().getConfig().getExposedPorts()) - .map(ExposedPort::getPort) - .collect(Collectors.toList()); - } - @Override - public InspectContainerResponse getContainerInfo() { - return inspectedContainer; - } - }; + ryukContainer.start(); CountDownLatch ryukScheduledLatch = new CountDownLatch(1); - String host = containerState.getHost(); - Integer ryukPort = containerState.getFirstMappedPort(); + String host = ryukContainer.getHost(); + Integer ryukPort = ryukContainer.getFirstMappedPort(); Thread kiraThread = new Thread( DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { @@ -207,17 +129,10 @@ public InspectContainerResponse getContainerInfo() { ); kiraThread.setDaemon(true); kiraThread.start(); - try { - // We need to wait before we can start any containers to make sure that we delete them - if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { - log.error("Timed out waiting for Ryuk container to start. Ryuk's logs:\n{}", ryukLog); - throw new IllegalStateException(String.format("Could not connect to Ryuk at %s:%s", host, ryukPort)); - } - } finally { - try { - logCallback.close(); - } catch (IOException ignored) { - } + // We need to wait before we can start any containers to make sure that we delete them + if (!ryukScheduledLatch.await(TestcontainersConfiguration.getInstance().getRyukTimeout(), TimeUnit.SECONDS)) { + log.error("Timed out waiting for Ryuk container to start. Ryuk's logs:\n{}", ryukContainer.getLogs()); + throw new IllegalStateException(String.format("Could not connect to Ryuk at %s:%s", host, ryukPort)); } } } diff --git a/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java b/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java new file mode 100644 index 00000000000..214b465c297 --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java @@ -0,0 +1,109 @@ +package org.testcontainers.utility; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.DockerClient; +import lombok.SneakyThrows; +import org.awaitility.Awaitility; +import org.awaitility.core.ConditionFactory; +import org.junit.Test; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; +import org.zeroturnaround.exec.ProcessExecutor; +import org.zeroturnaround.exec.ProcessResult; + +import java.io.File; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; + +public class ResourceReaperTest { + + @Test + public void shouldCleanupWithRyuk() { + Map labels = runProcess(processExecutor -> {}); + + assertCleanup(labels); + } + + @Test + public void shouldCleanupWithJVM() { + Map labels = runProcess(processExecutor -> { + processExecutor.environment("TESTCONTAINERS_RYUK_DISABLED", "true"); + }); + + assertCleanup(labels); + } + + private void assertCleanup(Map labels) { + DockerClient client = DockerClientFactory.instance().client(); + ConditionFactory awaitFactory = Awaitility.await().atMost(Duration.ofMinutes(1)).pollInterval(Duration.ofSeconds(1)); + + List labelValues = labels.entrySet().stream() + .map(it -> it.getKey() + "=" + it.getValue()) + .collect(Collectors.toList()); + + awaitFactory.untilAsserted(() -> { + assertThat(client.listContainersCmd().withFilter("label", labelValues).withShowAll(true).exec()) + .isEmpty(); + }); + + awaitFactory.untilAsserted(() -> { + assertThat(client.listNetworksCmd().withFilter("label", labelValues).exec()) + .isEmpty(); + }); + + awaitFactory.untilAsserted(() -> { + assertThat(client.listVolumesCmd().withFilter("label", labelValues).exec().getVolumes()) + .isEmpty(); + }); + } + + @SneakyThrows + private Map runProcess(Consumer processExecutorConsumer) { + ProcessExecutor processExecutor = new ProcessExecutor( + new File(System.getProperty("java.home")).toPath().resolve("bin").resolve("java").toString(), + "-ea", + "-classpath", + System.getProperty("java.class.path"), + SimpleUsage.class.getName() + ); + processExecutor.readOutput(true); + processExecutor.redirectOutput(System.out); + processExecutor.redirectError(System.err); + processExecutorConsumer.accept(processExecutor); + + ProcessResult result = processExecutor.execute(); + assertEquals(0, result.getExitValue()); + + String labelsJson = Stream.of(result.outputUTF8().split("\n")) + .filter(it -> it.startsWith(SimpleUsage.LABELS_MARKER)) + .map(it -> it.substring(SimpleUsage.LABELS_MARKER.length())) + .findFirst() + .get(); + + return new ObjectMapper().readValue(labelsJson, Map.class); + } + + public static class SimpleUsage { + + static final String LABELS_MARKER = "LABELS:"; + + @SneakyThrows + @SuppressWarnings("deprecation") + public static void main(String[] args) { + System.out.println(LABELS_MARKER + new ObjectMapper().writeValueAsString(ResourceReaper.instance().getLabels())); + + GenericContainer container = new GenericContainer<>("testcontainers/helloworld:1.1.0") + .withNetwork(org.testcontainers.containers.Network.newNetwork()) + .withExposedPorts(8080); + + container.start(); + } + } +} From b517804acfdfe0c59f484054e2b66a37c057dd5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 21:07:23 +0000 Subject: [PATCH 1880/4969] Bump cucumber-junit from 7.2.3 to 7.3.4 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.2.3 to 7.3.4. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.2.3...v7.3.4) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 78d042b95fd..f23a2d9b7af 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.2.3' - testImplementation 'io.cucumber:cucumber-junit:7.2.3' + testImplementation 'io.cucumber:cucumber-junit:7.3.4' testImplementation 'org.testcontainers:selenium' } From b3143fd8009ef82a4ebd9206b73e21da97e868de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 21:07:29 +0000 Subject: [PATCH 1881/4969] Bump r2dbc-mssql in /modules/mssqlserver Bumps [r2dbc-mssql](https://github.com/r2dbc/r2dbc-mssql) from 0.8.7.RELEASE to 0.9.0.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-mssql/releases) - [Changelog](https://github.com/r2dbc/r2dbc-mssql/blob/main/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-mssql/compare/v0.8.7.RELEASE...v0.9.0.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-mssql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index dfa15ed1c2a..e7a654e12f1 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -7,7 +7,7 @@ dependencies { api project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' + compileOnly 'io.r2dbc:r2dbc-mssql:0.9.0.RELEASE' testImplementation project(':jdbc-test') testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.1.1.jre8-preview' From e9e602b3aac9a72c6c7b4d93af62e4cc7d3acd04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 21:07:47 +0000 Subject: [PATCH 1882/4969] Bump awaitility from 4.1.1 to 4.2.0 in /modules/couchbase Bumps [awaitility](https://github.com/awaitility/awaitility) from 4.1.1 to 4.2.0. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.1.1...awaitility-4.2.0) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index f1e41fcbe11..71844a30d20 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:3.14.9' testImplementation 'com.couchbase.client:java-client:3.3.0' - testImplementation 'org.awaitility:awaitility:4.1.1' + testImplementation 'org.awaitility:awaitility:4.2.0' } From 07543ffad63bb842279abaf5dfecb9974ed2d667 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 21:07:49 +0000 Subject: [PATCH 1883/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps org.jetbrains.kotlin.plugin.spring from 1.6.20 to 1.6.21. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index b6dd68b33cd..4f3a50de21a 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.6.4" id("org.jetbrains.kotlin.jvm") version "1.6.21" - id("org.jetbrains.kotlin.plugin.spring") version "1.6.20" + id("org.jetbrains.kotlin.plugin.spring") version "1.6.21" } apply plugin: 'io.spring.dependency-management' From e94eaa11e65b984b6af7e21e98b1e02aade21282 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 21:07:56 +0000 Subject: [PATCH 1884/4969] Bump r2dbc-postgresql in /modules/postgresql Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.11.RELEASE to 0.8.12.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.12.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.11.RELEASE...v0.8.12.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index f2c50c30754..c0628afc63a 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -7,7 +7,7 @@ dependencies { api project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' testImplementation project(':jdbc-test') testImplementation project(':test-support') From 7a957d5819a3fa6964db285a46eb77c0b9360163 Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Tue, 17 May 2022 18:02:08 -0400 Subject: [PATCH 1885/4969] Remove the disk space check (#5381) --- core/build.gradle | 4 +- .../testcontainers/DockerClientFactory.java | 102 +----------------- .../utility/RyukResourceReaper.java | 8 +- .../DockerClientFactoryTest.java | 11 -- 4 files changed, 8 insertions(+), 117 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 2a81eb8568a..efb08991f8d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -40,7 +40,9 @@ tasks.japicmp { "org.testcontainers.shaded.*", ] - classExcludes = [] + classExcludes = [ + "org.testcontainers.utility.RyukResourceReaper", + ] methodExcludes = [ "org.testcontainers.containers.Container#getDockerClient()", diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index cc85645b2b4..c1e999d392a 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -2,7 +2,6 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.DockerClientDelegate; -import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.exception.DockerClientException; @@ -10,7 +9,6 @@ import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AccessMode; import com.github.dockerjava.api.model.Bind; -import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Version; import com.github.dockerjava.api.model.Volume; @@ -31,18 +29,14 @@ import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.ResourceReaper; -import org.testcontainers.utility.RyukResourceReaper; import org.testcontainers.utility.TestcontainersConfiguration; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.ServiceLoader; import java.util.UUID; import java.util.function.BiFunction; @@ -80,16 +74,10 @@ public class DockerClientFactory { RuntimeException cachedClientFailure; private String activeApiVersion; - private String activeExecutionDriver; @Getter(lazy = true) private final boolean fileMountingSupported = checkMountableFile(); - - static { - System.setProperty("org.testcontainers.shaded.io.netty.packagePrefix", "org.testcontainers.shaded."); - } - @VisibleForTesting DockerClientFactory() { @@ -200,20 +188,19 @@ public void close() { log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); Info dockerInfo = strategy.getInfo(); + log.debug("Docker info: {}", dockerInfo.getRawValues()); Version version = client.versionCmd().exec(); + log.debug("Docker version: {}", version.getRawValues()); activeApiVersion = version.getApiVersion(); - activeExecutionDriver = dockerInfo.getExecutionDriver(); log.info("Connected to docker: \n" + " Server Version: " + dockerInfo.getServerVersion() + "\n" + " API Version: " + activeApiVersion + "\n" + " Operating System: " + dockerInfo.getOperatingSystem() + "\n" + " Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB"); - final ResourceReaper resourceReaper; try { - resourceReaper = ResourceReaper.instance(); //noinspection deprecation - resourceReaper.init(); + ResourceReaper.instance().init(); } catch (RuntimeException e) { cachedClientFailure = e; throw e; @@ -226,27 +213,6 @@ public void close() { try { log.info("Checking the system..."); checkDockerVersion(version.getVersion()); - - //noinspection deprecation - String ryukContainerId = resourceReaper instanceof RyukResourceReaper - ? ((RyukResourceReaper) resourceReaper).getContainerId() - : null; - - if (ryukContainerId != null) { - checkDiskSpace(client, ryukContainerId); - } else { - runInsideDocker( - createContainerCmd -> { - createContainerCmd.withName("testcontainers-checks-" + SESSION_ID); - createContainerCmd.getHostConfig().withAutoRemove(true); - createContainerCmd.withCmd("tail", "-f", "/dev/null"); - }, - (__, containerId) -> { - checkDiskSpace(client, containerId); - return ""; - } - ); - } } catch (RuntimeException e) { cachedClientFailure = e; throw e; @@ -263,43 +229,6 @@ private void checkDockerVersion(String dockerVersion) { check("Docker server version should be at least 1.6.0", versionIsSufficient); } - private void checkDiskSpace(DockerClient dockerClient, String id) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - try { - dockerClient - .execStartCmd(dockerClient.execCreateCmd(id).withAttachStdout(true).withCmd("df", "-P").exec().getId()) - .exec(new ResultCallback.Adapter() { - @Override - public void onNext(Frame frame) { - if (frame == null) { - return; - } - switch (frame.getStreamType()) { - case RAW: - case STDOUT: - try { - outputStream.write(frame.getPayload()); - outputStream.flush(); - } catch (IOException e) { - onError(e); - } - } - } - }) - .awaitCompletion(); - } catch (Exception e) { - log.debug("Can't exec disk checking command", e); - } - - DiskSpaceUsage df = parseAvailableDiskSpace(outputStream.toString()); - - check( - "Docker environment should have more than 2GB free disk space", - df.availableMB.map(it -> it >= 2048).orElse(true) - ); - } - private void check(String message, boolean isSuccessful) { if (isSuccessful) { log.info("\u2714\ufe0e {}", message); @@ -389,28 +318,6 @@ T runInsideDocker(DockerImageName imageName, Consumer cr } } - @VisibleForTesting - static class DiskSpaceUsage { - Optional availableMB = Optional.empty(); - Optional usedPercent = Optional.empty(); - } - - @VisibleForTesting - DiskSpaceUsage parseAvailableDiskSpace(String dfOutput) { - DiskSpaceUsage df = new DiskSpaceUsage(); - String[] lines = dfOutput.split("\n"); - for (String line : lines) { - String[] fields = line.split("\\s+"); - if (fields.length > 5 && fields[5].equals("/")) { - long availableKB = Long.parseLong(fields[3]); - df.availableMB = Optional.of(availableKB / 1024L); - df.usedPercent = Optional.of(Integer.valueOf(fields[4].replace("%", ""))); - break; - } - } - return df; - } - /** * @return the docker API version of the daemon that we have connected to */ @@ -423,8 +330,7 @@ public String getActiveApiVersion() { * @return the docker execution driver of the daemon that we have connected to */ public String getActiveExecutionDriver() { - client(); - return activeExecutionDriver; + return getInfo().getExecutionDriver(); } /** diff --git a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java index c2e2cf4ef97..6ce9c372fd2 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java @@ -21,11 +21,9 @@ * Ryuk-based {@link ResourceReaper} implementation. * * @see moby-ryuk - * @deprecated internal API */ -@Deprecated @Slf4j -public class RyukResourceReaper extends ResourceReaper { +class RyukResourceReaper extends ResourceReaper { private static final RateLimiter RYUK_ACK_RATE_LIMITER = RateLimiterBuilder .newBuilder() @@ -37,10 +35,6 @@ public class RyukResourceReaper extends ResourceReaper { private final RyukContainer ryukContainer = new RyukContainer(); - public String getContainerId() { - return ryukContainer.getContainerId(); - } - @Override public void init() { if (!TestcontainersConfiguration.getInstance().environmentSupportsReuse()) { diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index 247a16a76a6..a889764579f 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -2,8 +2,6 @@ import org.junit.Rule; import org.junit.Test; -import org.rnorth.visibleassertions.VisibleAssertions; -import org.testcontainers.DockerClientFactory.DiskSpaceUsage; import org.testcontainers.dockerclient.LogToStringContainerCallback; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MockTestcontainersConfigurationRule; @@ -39,15 +37,6 @@ public void runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally() { } } - @Test - public void shouldHandleBigDiskSize() throws Exception { - String dfOutput = "/dev/disk1 2982480572 1491240286 2982480572 31% /"; - DiskSpaceUsage usage = DockerClientFactory.instance().parseAvailableDiskSpace(dfOutput); - - VisibleAssertions.assertEquals("Available MB is correct", 2982480572L / 1024L, usage.availableMB.orElse(0L)); - VisibleAssertions.assertEquals("Available percentage is correct", 31, usage.usedPercent.orElse(0)); - } - @Test public void dockerHostIpAddress() { DockerClientFactory instance = new DockerClientFactory(); From d9fa5130435d6bcd5112b864349924ad5d2cdbae Mon Sep 17 00:00:00 2001 From: Wenjun Ruan Date: Wed, 18 May 2022 06:56:00 +0800 Subject: [PATCH 1886/4969] Add SeaTunnel to who is using testcontainers (#5272) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 8749e3678cf..b2c11d6d8e8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -200,7 +200,7 @@ A huge thank you to our sponsors: * [Alkira](https://www.alkira.com/) - Testing of multiple micro-services using Kafka, PostgreSQL, Apache Zookeeper, Etcd and so on. * [Togglz](https://www.togglz.org/) - Feature Flags for the Java platform * [Byzer](https://www.byzer.org/home) - Integration tests for Data and AI platforms are based on multiple versions of Byzer, Ray and Apache Spark. - +* [Apache SeaTunnel](https://github.com/apache/incubator-seatunnel) - Integration testing with different datasource. ## License From 0073001e603ac8bd583a82f81c2a077251156c5d Mon Sep 17 00:00:00 2001 From: Denis <13610290+cac03@users.noreply.github.com> Date: Wed, 18 May 2022 02:24:11 +0300 Subject: [PATCH 1887/4969] Remove "Linux - Travis CI" from docs (#4374) --- docs/supported_docker_environment/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/supported_docker_environment/index.md b/docs/supported_docker_environment/index.md index 62a2bbe0af2..3b82cea2165 100644 --- a/docs/supported_docker_environment/index.md +++ b/docs/supported_docker_environment/index.md @@ -5,7 +5,6 @@ | Host Operating System / Environment | Minimum recommended docker versions | Known issues / tips | |-------------------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Linux - general | Docker v17.09 | | -| Linux - Travis CI | Docker v17.09 | See [example .travis.yml](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/.travis.yml) for baseline Travis CI configuration | | Linux - CircleCI (LXC driver) | Docker v17.09 | The `exec` feature is not compatible with CircleCI. See CircleCI configuration [example](./continuous_integration/circle_ci.md) | | Linux - within a Docker container | Docker v17.09 | See [Running inside Docker](continuous_integration/dind_patterns.md) for Docker-in-Docker and Docker wormhole patterns | | Mac OS X - Docker Toolbox | Docker Machine v0.8.0 | | From 55334479422b97fea8110a0a59bf64127e29a6ae Mon Sep 17 00:00:00 2001 From: John Athanaselis Date: Wed, 18 May 2022 12:53:27 +0300 Subject: [PATCH 1888/4969] K3sContainer: expose kubeConfig for docker network access (#5097) Co-authored-by: Sergei Egorov --- .../org/testcontainers/k3s/K3sContainer.java | 63 ++++++++++++++----- .../k3s/KubectlContainerTest.java | 45 +++++++++++++ 2 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 modules/k3s/src/test/java/org/testcontainers/k3s/KubectlContainerTest.java diff --git a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java index 54cb2ff500f..7f21ca7dbb8 100644 --- a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java +++ b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java @@ -8,23 +8,29 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.DockerObjectAccessor; import lombok.SneakyThrows; +import org.apache.commons.io.IOUtils; import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; public class K3sContainer extends GenericContainer { + public static int KUBE_SECURE_PORT = 6443; + + public static int RANCHER_WEBHOOK_PORT = 8443; + private String kubeConfigYaml; public K3sContainer(DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DockerImageName.parse("rancher/k3s")); - addExposedPorts(6443, 8443); + addExposedPorts(KUBE_SECURE_PORT, RANCHER_WEBHOOK_PORT); setPrivilegedMode(true); withCreateContainerCmdModifier(it -> { it.getHostConfig().withCgroupnsMode("host"); @@ -44,30 +50,57 @@ public K3sContainer(DockerImageName dockerImageName) { setWaitStrategy(new LogMessageWaitStrategy().withRegEx(".*Node controller sync successful.*")); } - @SneakyThrows @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { + String rawKubeConfig = copyFileFromContainer("/etc/rancher/k3s/k3s.yaml", + is -> IOUtils.toString(is, StandardCharsets.UTF_8) + ); + String serverUrl = "https://" + this.getHost() + ":" + this.getMappedPort(KUBE_SECURE_PORT); + kubeConfigYaml = kubeConfigWithServerUrl(rawKubeConfig, serverUrl); + } + + /** + * Return the kubernetes client configuration to access k3s from the host machine. + * + * @return the kubeConfig yaml. + */ + public String getKubeConfigYaml() { + return kubeConfigYaml; + } + + /** + * Generate a kubernetes client configuration for use on a docker internal network. The kubeConfig can be used by + * another docker container running in the same network as the k3s container. For access from the host, use + * the {@link #getKubeConfigYaml()} method instead. + * + * @param networkAlias a valid network alias of the k3s container. + * @return the kubeConfig yaml. + */ + public String generateInternalKubeConfigYaml(String networkAlias) { + if (this.getNetworkAliases().contains(networkAlias)) { + String serverUrl = "https://" + networkAlias + ":" + KUBE_SECURE_PORT; + return kubeConfigWithServerUrl(kubeConfigYaml, serverUrl); + } else { + throw new IllegalArgumentException(networkAlias + " is not a network alias for k3s container"); + } + } + + @SneakyThrows + private String kubeConfigWithServerUrl(String kubeConfigYaml, String serverUrl) { ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); - ObjectNode rawKubeConfig = copyFileFromContainer( - "/etc/rancher/k3s/k3s.yaml", - is -> objectMapper.readValue(is, ObjectNode.class) - ); + ObjectNode kubeConfigObjectNode = objectMapper.readValue(kubeConfigYaml, ObjectNode.class); - JsonNode clusterNode = rawKubeConfig.at("/clusters/0/cluster"); + JsonNode clusterNode = kubeConfigObjectNode.at("/clusters/0/cluster"); if (!clusterNode.isObject()) { throw new IllegalStateException("'/clusters/0/cluster' expected to be an object"); } ObjectNode clusterConfig = (ObjectNode) clusterNode; + clusterConfig.replace("server", new TextNode(serverUrl)); - clusterConfig.replace("server", new TextNode("https://" + this.getHost() + ":" + this.getMappedPort(6443))); + kubeConfigObjectNode.set("current-context", new TextNode("default")); - rawKubeConfig.set("current-context", new TextNode("default")); - - kubeConfigYaml = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(rawKubeConfig); - } - - public String getKubeConfigYaml() { - return kubeConfigYaml; + return objectMapper.writerWithDefaultPrettyPrinter() + .writeValueAsString(kubeConfigObjectNode); } } diff --git a/modules/k3s/src/test/java/org/testcontainers/k3s/KubectlContainerTest.java b/modules/k3s/src/test/java/org/testcontainers/k3s/KubectlContainerTest.java new file mode 100644 index 00000000000..5c0d44ff0f1 --- /dev/null +++ b/modules/k3s/src/test/java/org/testcontainers/k3s/KubectlContainerTest.java @@ -0,0 +1,45 @@ +package org.testcontainers.k3s; + +import org.junit.ClassRule; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.images.builder.Transferable; +import org.testcontainers.utility.DockerImageName; + +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; + +public class KubectlContainerTest { + + public static Network network = Network.SHARED; + + @ClassRule + public static K3sContainer k3s = new K3sContainer(DockerImageName.parse("rancher/k3s:v1.21.3-k3s1")) + .withNetwork(network) + .withNetworkAliases("k3s"); + + @Test + public void shouldExposeKubeConfigForNetworkAlias() throws Exception { + String kubeConfigYaml = k3s.generateInternalKubeConfigYaml("k3s"); + + try ( + GenericContainer kubectlContainer = new GenericContainer<>("rancher/kubectl:v1.23.3") + .withNetwork(network) + .withCopyToContainer(Transferable.of(kubeConfigYaml), "/.kube/config") + .withCommand("get namespaces") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(30))) + ) { + kubectlContainer.start(); + + assertThat(kubectlContainer.getLogs()).contains("kube-system"); + } + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowAnExceptionForUnknownNetworkAlias() { + k3s.generateInternalKubeConfigYaml("not-set-network-alias"); + } +} From ada816c136d6a46c77d301b1a85968ae5d4ae430 Mon Sep 17 00:00:00 2001 From: edee111 <4160602+edee111@users.noreply.github.com> Date: Wed, 18 May 2022 11:59:44 +0200 Subject: [PATCH 1889/4969] Removal of containers from the cache is not synchronized (#4598) Co-authored-by: Eduard Tomek --- .../org/testcontainers/jdbc/ContainerDatabaseDriver.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java index c1b4fc29067..4b3a7ba98f7 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java @@ -162,8 +162,10 @@ private Connection wrapConnection(final Connection connection, final JdbcDatabas return new ConnectionWrapper(connection, () -> { finalConnections.remove(connection); if (!isDaemon && finalConnections.isEmpty()) { - container.stop(); - jdbcUrlContainerCache.remove(connectionUrl.getUrl()); + synchronized (jdbcUrlContainerCache) { + container.stop(); + jdbcUrlContainerCache.remove(connectionUrl.getUrl()); + } } }); } From b8d75b153b61af01127b0fb8a09405d6624a8ab8 Mon Sep 17 00:00:00 2001 From: Jurrian Fahner Date: Wed, 18 May 2022 18:30:34 +0200 Subject: [PATCH 1890/4969] Add docs for using Gitlab CI with Docker wormhole executor (#4770) --- .../continuous_integration/gitlab_ci.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md index 5e701007ab0..b4571403654 100644 --- a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md +++ b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md @@ -1,5 +1,36 @@ # GitLab CI +## Example using Docker socket +This applies if you have your own GitlabCI runner installed, use the Docker executor and you have `/var/run/docker.sock` mounted in the runner configuration. + +See below for an example runner configuration: +```toml +[[runners]] + name = "MACHINE_NAME" + url = "https://gitlab.com/" + token = "GENERATED_GITLAB_RUNNER_TOKEN" + executor = "docker" + [runners.docker] + tls_verify = false + image = "docker:latest" + privileged = false + disable_entrypoint_overwrite = false + oom_kill_disable = false + disable_cache = false + volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"] + shm_size = 0 +``` + +Please also include the following in your GitlabCI pipeline definitions (`.gitlab-ci.yml`) that use Testcontainers: +```yml +variables: + TESTCONTAINERS_HOST_OVERRIDE: "host.docker.internal" +``` + +The environment variable `TESTCONTAINERS_HOST_OVERRIDE` needs to be configured, otherwise, a wrong IP address would be used to resolve the Docker host, which will likely lead to failing tests. + +## Example using DinD (Docker-in-Docker) + In order to use Testcontainers in a Gitlab CI pipeline, you need to run the job as a Docker container (see [Patterns for running inside Docker](dind_patterns.md)). So edit your `.gitlab-ci.yml` to include the [Docker-In-Docker service](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-workflow-with-docker-executor) (`docker:dind`) and set the `DOCKER_HOST` variable to `tcp://docker:2375` and `DOCKER_TLS_CERTDIR` to empty string. From 6dc05d30cccd8211728e6082f3aa11c6964d0967 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Wed, 18 May 2022 18:52:15 +0200 Subject: [PATCH 1891/4969] Reset driver and vncRecordingContainer when Selenium container stops (#5116) --- .../testcontainers/containers/BrowserWebDriverContainer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 12bbbc07de5..fc3778385cd 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -318,6 +318,7 @@ public void stop() { } catch (Exception e) { LOGGER.debug("Failed to quit the driver", e); } + driver = null; } if (vncRecordingContainer != null) { @@ -326,6 +327,7 @@ public void stop() { } catch (Exception e) { LOGGER.debug("Failed to stop vncRecordingContainer", e); } + vncRecordingContainer = null; } super.stop(); From ea7b29baac0422c0c7a58554a49b393b7ebcc8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 19 May 2022 12:58:16 -0500 Subject: [PATCH 1892/4969] Upgrade lombok to be compatible against java 17 (#5388) --- build.gradle | 4 ++-- examples/kafka-cluster/build.gradle | 2 +- examples/solr-container/build.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 309743477c1..96e1940eba5 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { } plugins { - id 'io.franzbecker.gradle-lombok' version '4.0.0' + id 'io.franzbecker.gradle-lombok' version '5.0.0' id 'com.github.johnrengelman.shadow' version '7.0.0' id 'me.champeau.gradle.japicmp' version '0.2.9' apply false } @@ -40,7 +40,7 @@ subprojects { } lombok { - version = '1.18.20' + version = '1.18.24' } diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index ee8035ea51c..db89b4335fe 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { testCompileOnly "org.projectlombok:lombok:1.18.24" - testAnnotationProcessor "org.projectlombok:lombok:1.18.22" + testAnnotationProcessor "org.projectlombok:lombok:1.18.24" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:3.1.0' testImplementation 'org.assertj:assertj-core:3.22.0' diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 3f3366f9d46..abb7c12e0ed 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly "org.projectlombok:lombok:1.18.24" - annotationProcessor "org.projectlombok:lombok:1.18.22" + annotationProcessor "org.projectlombok:lombok:1.18.24" implementation 'org.apache.solr:solr-solrj:8.11.1' From fffab559a25d2e0501ab721182bc9cbdcb722506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 19 May 2022 13:32:08 -0500 Subject: [PATCH 1893/4969] Fix TestcontainersTestDescription filename (#5387) --- ...nerTestDescription.java => TestcontainersTestDescription.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/{TestcontainerTestDescription.java => TestcontainersTestDescription.java} (100%) diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainerTestDescription.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersTestDescription.java similarity index 100% rename from modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainerTestDescription.java rename to modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersTestDescription.java From b04540b2cafbb25a580595d2d7832781a1de9825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 20 May 2022 18:14:30 -0500 Subject: [PATCH 1894/4969] Add spotless and checkstyle (#5383) Co-authored-by: Sergei Egorov --- build.gradle | 31 +++++++++++++++++++++ config/checkstyle/checkstyle.xml | 47 ++++++++++++++++++++++++++++++++ docs/contributing.md | 1 + gradle/ci-support.gradle | 2 +- modules/neo4j/build.gradle | 2 +- 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 config/checkstyle/checkstyle.xml diff --git a/build.gradle b/build.gradle index 96e1940eba5..adbd1a47c4a 100644 --- a/build.gradle +++ b/build.gradle @@ -13,6 +13,7 @@ plugins { id 'io.franzbecker.gradle-lombok' version '5.0.0' id 'com.github.johnrengelman.shadow' version '7.0.0' id 'me.champeau.gradle.japicmp' version '0.2.9' apply false + id 'com.diffplug.spotless' version '6.3.0' apply false } apply from: "$rootDir/gradle/ci-support.gradle" @@ -22,6 +23,8 @@ subprojects { apply plugin: 'idea' apply plugin: 'io.franzbecker.gradle-lombok' apply from: "$rootDir/gradle/shading.gradle" + apply plugin: 'com.diffplug.spotless' + apply plugin: 'checkstyle' group = "org.testcontainers" @@ -105,4 +108,32 @@ subprojects { dependencies { testImplementation 'ch.qos.logback:logback-classic:1.2.3' } + + spotless { + enforceCheck false + java { + removeUnusedImports() + trimTrailingWhitespace() + endWithNewline() + + prettier(['prettier': '2.5.1', 'prettier-plugin-java': '1.6.1']) + .config([ + 'parser' : 'java', + 'tabWidth' : 4, + 'printWidth': 120 + ]) + + importOrder('', 'java', 'javax', '\\#') + } + groovyGradle { + target '**/*.groovy' + greclipse('4.19.0') + } + } + + checkstyle { + toolVersion = "9.3" + configFile = rootProject.file('config/checkstyle/checkstyle.xml') + ignoreFailures = true + } } diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 00000000000..39598dae2e4 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/docs/contributing.md b/docs/contributing.md index 6cd3e2719f8..01c4fce57b6 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -8,6 +8,7 @@ * follow the style, naming and structure conventions of the rest of the project. * make commits atomic and easy to merge. * when updating documentation, please see [our guidance for documentation contributions](contributing_docs.md). + * apply format running `./gradlew spotlessApply` * verify all tests are passing. Build the project with `./gradlew check` to do this. **N.B.** Gradle's Build Cache is enabled by default, but you can add `--no-build-cache` flag to disable it. diff --git a/gradle/ci-support.gradle b/gradle/ci-support.gradle index b878c107796..5b85837361e 100644 --- a/gradle/ci-support.gradle +++ b/gradle/ci-support.gradle @@ -17,7 +17,7 @@ task testMatrix { } } -// If we're executing the `taskMatrix` task, disable tests and other slow tasks +// If we're executing the `testMatrix` task, disable tests and other slow tasks // so that we can get a result quickly. gradle.taskGraph.whenReady { if (it.hasTask(tasks.testMatrix)) { diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 0bdd9ba960c..efba3dd0db5 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -26,7 +26,7 @@ task customNeo4jPluginJar(type: Jar) { outputs.dir(customNeo4jPluginDestinationDir) } -test.dependsOn customNeo4jPluginJar +processTestResources.dependsOn customNeo4jPluginJar dependencies { customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.32" From f60051c0b7f89bed30ddeffd09b8feed0500e342 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Tue, 24 May 2022 20:43:27 +0200 Subject: [PATCH 1895/4969] Use `TestInstances` API from JUnit Jupiter (#2719) Co-authored-by: Richard North --- .../jupiter/TestcontainersExtension.java | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java index 1ed5e954e44..990940be14d 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java @@ -12,7 +12,6 @@ import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; -import org.junit.jupiter.api.extension.TestInstancePostProcessor; import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.Preconditions; @@ -23,7 +22,8 @@ import org.testcontainers.lifecycle.TestLifecycleAware; import java.lang.reflect.Field; -import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -34,20 +34,13 @@ import static java.util.stream.Collectors.toList; import static org.testcontainers.junit.jupiter.FilesystemFriendlyNameGenerator.filesystemFriendlyNameOf; -class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition, TestInstancePostProcessor { +class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition { private static final Namespace NAMESPACE = Namespace.create(TestcontainersExtension.class); - private static final String TEST_INSTANCE = "testInstance"; private static final String SHARED_LIFECYCLE_AWARE_CONTAINERS = "sharedLifecycleAwareContainers"; private static final String LOCAL_LIFECYCLE_AWARE_CONTAINERS = "localLifecycleAwareContainers"; - @Override - public void postProcessTestInstance(final Object testInstance, final ExtensionContext context) { - Store store = context.getStore(NAMESPACE); - store.put(TEST_INSTANCE, testInstance); - } - @Override public void beforeAll(ExtensionContext context) { Class testClass = context.getTestClass() @@ -156,17 +149,9 @@ boolean isDockerAvailable() { } private Set collectParentTestInstances(final ExtensionContext context) { - Set testInstances = new LinkedHashSet<>(); - Optional current = Optional.of(context); - while (current.isPresent()) { - ExtensionContext ctx = current.get(); - Object testInstance = ctx.getStore(NAMESPACE).remove(TEST_INSTANCE); - if (testInstance != null) { - testInstances.add(testInstance); - } - current = ctx.getParent(); - } - return testInstances; + List allInstances = new ArrayList<>(context.getRequiredTestInstances().getAllInstances()); + Collections.reverse(allInstances); + return new LinkedHashSet<>(allInstances); } private List findSharedContainers(Class testClass) { From 2bdbc8cd6d42cb5dc12165617e72abfa0dee2fec Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 24 May 2022 21:07:58 +0200 Subject: [PATCH 1896/4969] Don't delete images if `deleteOnExit` is false (#5391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- .../images/builder/ImageFromDockerfile.java | 10 +++++----- .../builder/ImageFromDockerfileTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 281a74feaba..000487bfa4d 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -87,9 +87,6 @@ protected final String resolve() { DockerClient dockerClient = DockerClientFactory.instance().client(); try { - if (deleteOnExit) { - ResourceReaper.instance().registerImageForCleanup(dockerImageName); - } BuildImageResultCallback resultCallback = new BuildImageResultCallback() { @Override @@ -114,9 +111,12 @@ public void onNext(BuildResponseItem item) { if (buildImageCmd.getLabels() != null) { labels.putAll(buildImageCmd.getLabels()); } + labels.putAll(DockerClientFactory.DEFAULT_LABELS); - //noinspection deprecation - labels.putAll(ResourceReaper.instance().getLabels()); + if (deleteOnExit) { + //noinspection deprecation + labels.putAll(ResourceReaper.instance().getLabels()); + } buildImageCmd.withLabels(labels); prePullDependencyImages(dependencyImageNames); diff --git a/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java b/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java index 93ec5cb5cd1..da3509cea7b 100644 --- a/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java @@ -4,6 +4,7 @@ import com.github.dockerjava.api.command.InspectImageResponse; import org.junit.Test; import org.testcontainers.DockerClientFactory; +import org.testcontainers.utility.Base58; import static org.assertj.core.api.Assertions.assertThat; @@ -24,4 +25,22 @@ public void shouldAddDefaultLabels() { .containsAllEntriesOf(DockerClientFactory.DEFAULT_LABELS); } + @Test + public void shouldNotAddSessionLabelIfDeleteOnExitIsFalse() { + ImageFromDockerfile image = new ImageFromDockerfile("localhost/testcontainers/" + Base58.randomString(16).toLowerCase(), false) + .withDockerfileFromBuilder(it -> it.from("scratch")); + String imageId = image.resolve(); + DockerClient dockerClient = DockerClientFactory.instance().client(); + + try { + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + assertThat(inspectImageResponse.getConfig().getLabels()) + .doesNotContainKey(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL); + } finally { + // ensure the image is deleted, even if the test fails + dockerClient.removeImageCmd(imageId).exec(); + } + + } + } From de1324ed2800eff4da326d0c23d281399d006bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 24 May 2022 23:31:37 -0500 Subject: [PATCH 1897/4969] Apply spotless and checkstyle (#5390) --- .github/workflows/ci-docker-wormhole.yml | 1 + build.gradle | 11 +- config/checkstyle/checkstyle.xml | 8 +- .../testcontainers/AbstractJarFileTest.java | 5 +- .../testcontainers/JarFileShadingTest.java | 24 +- .../testcontainers/PublicBinaryAPITest.java | 76 +- .../testcontainers/DockerClientFactory.java | 93 ++- .../org/testcontainers/Testcontainers.java | 15 +- .../java/org/testcontainers/UnstableAPI.java | 6 +- .../testcontainers/containers/BindMode.java | 3 +- .../ComposeServiceWaitStrategyTarget.java | 15 +- .../testcontainers/containers/Container.java | 22 +- .../containers/ContainerFetchException.java | 1 + .../containers/ContainerState.java | 42 +- .../containers/DockerComposeContainer.java | 236 ++++-- .../containers/DockerComposeFiles.java | 4 +- .../containers/ExecInContainerPattern.java | 38 +- .../FailureDetectingExternalResource.java | 16 +- .../FixedHostPortGenericContainer.java | 5 +- .../containers/FutureContainer.java | 1 + .../containers/GenericContainer.java | 323 ++++---- .../containers/InternetProtocol.java | 1 - .../testcontainers/containers/Network.java | 1 - .../containers/ParsedDockerComposeFile.java | 65 +- .../containers/PortForwardingContainer.java | 24 +- .../containers/SelinuxContext.java | 1 - .../containers/SocatContainer.java | 16 +- .../containers/VncRecordingContainer.java | 55 +- .../containers/output/BaseConsumer.java | 1 + .../output/FrameConsumerResultCallback.java | 4 +- .../containers/output/OutputFrame.java | 19 +- .../containers/output/Slf4jLogConsumer.java | 10 +- .../containers/output/ToStringConsumer.java | 1 + .../containers/output/WaitingConsumer.java | 4 +- ...finiteWaitOneShotStartupCheckStrategy.java | 1 + ...umDurationRunningStartupCheckStrategy.java | 1 - .../startupcheck/StartupCheckStrategy.java | 51 +- .../containers/traits/LinkableContainer.java | 1 - .../internal/ExternalPortListeningCheck.java | 20 +- .../InternalCommandPortListeningCheck.java | 25 +- .../wait/strategy/AbstractWaitStrategy.java | 21 +- .../DockerHealthcheckWaitStrategy.java | 7 +- .../wait/strategy/HostPortWaitStrategy.java | 98 ++- .../wait/strategy/HttpWaitStrategy.java | 207 ++--- .../wait/strategy/LogMessageWaitStrategy.java | 18 +- .../containers/wait/strategy/Wait.java | 9 +- .../wait/strategy/WaitAllStrategy.java | 29 +- .../wait/strategy/WaitStrategy.java | 1 - .../wait/strategy/WaitStrategyTarget.java | 8 +- .../AuditLoggingDockerClient.java | 127 +-- .../AuthDelegatingDockerClientConfig.java | 14 +- .../dockerclient/DockerClientConfigUtils.java | 27 +- .../DockerClientProviderStrategy.java | 139 ++-- .../DockerMachineClientProviderStrategy.java | 21 +- ...dSystemPropertyClientProviderStrategy.java | 11 +- .../HeadersAddingDockerHttpClient.java | 4 +- .../InvalidConfigurationException.java | 2 +- .../LogToStringContainerCallback.java | 1 + .../NpipeSocketClientProviderStrategy.java | 5 +- .../RootlessDockerClientProviderStrategy.java | 20 +- .../UnixSocketClientProviderStrategy.java | 11 +- .../images/AbstractImagePullPolicy.java | 3 +- .../org/testcontainers/images/ImageData.java | 7 +- .../images/ImagePullPolicy.java | 2 - .../images/LocalImagesCache.java | 8 +- .../images/LoggedPullImageResultCallback.java | 38 +- .../images/ParsedDockerfile.java | 17 +- .../org/testcontainers/images/PullPolicy.java | 5 +- .../images/RemoteDockerImage.java | 24 +- ...eLimitedLoggedPullImageResultCallback.java | 39 +- .../images/builder/ImageFromDockerfile.java | 54 +- .../images/builder/Transferable.java | 1 - .../builder/dockerfile/DockerfileBuilder.java | 5 +- .../dockerfile/statement/Statement.java | 2 +- .../dockerfile/traits/AddStatementTrait.java | 1 - .../dockerfile/traits/CmdStatementTrait.java | 1 - .../dockerfile/traits/CopyStatementTrait.java | 1 - .../traits/DockerfileBuilderTrait.java | 1 - .../traits/EntryPointStatementTrait.java | 1 - .../dockerfile/traits/EnvStatementTrait.java | 1 - .../traits/ExposeStatementTrait.java | 8 +- .../dockerfile/traits/FromStatementTrait.java | 1 - .../traits/LabelStatementTrait.java | 1 - .../dockerfile/traits/RunStatementTrait.java | 1 - .../dockerfile/traits/UserStatementTrait.java | 1 - .../traits/VolumeStatementTrait.java | 1 - .../traits/WorkdirStatementTrait.java | 1 - .../traits/BuildContextBuilderTrait.java | 1 - .../images/builder/traits/ClasspathTrait.java | 1 - .../builder/traits/DockerfileTrait.java | 38 +- .../images/builder/traits/FilesTrait.java | 1 - .../images/builder/traits/StringsTrait.java | 29 +- .../testcontainers/lifecycle/Startable.java | 1 - .../testcontainers/lifecycle/Startables.java | 36 +- .../lifecycle/TestDescription.java | 1 - .../lifecycle/TestLifecycleAware.java | 9 +- .../testcontainers/utility/AuditLogger.java | 45 +- .../utility/AuthConfigUtil.java | 9 +- .../org/testcontainers/utility/Base58.java | 3 +- .../utility/ClasspathScanner.java | 6 +- .../testcontainers/utility/CommandLine.java | 14 +- .../utility/ComparableVersion.java | 10 +- ...ConfigurationFileImageNameSubstitutor.java | 3 +- .../utility/DefaultImageNameSubstitutor.java | 13 +- .../utility/DockerImageName.java | 68 +- .../utility/DockerLoggerFactory.java | 1 - .../utility/DockerMachineClient.java | 45 +- .../testcontainers/utility/DockerStatus.java | 22 +- .../utility/DynamicPollInterval.java | 1 + .../utility/ImageNameSubstitutor.java | 40 +- .../utility/JVMHookResourceReaper.java | 21 +- .../testcontainers/utility/LazyFuture.java | 2 +- .../utility/LicenseAcceptance.java | 17 +- .../org/testcontainers/utility/LogUtils.java | 40 +- .../testcontainers/utility/MountableFile.java | 115 ++- .../org/testcontainers/utility/PathUtils.java | 34 +- .../PrefixingImageNameSubstitutor.java | 6 +- .../utility/RegistryAuthLocator.java | 141 ++-- .../utility/ResourceReaper.java | 66 +- .../testcontainers/utility/RyukContainer.java | 11 +- .../utility/RyukResourceReaper.java | 5 +- .../utility/TestEnvironment.java | 4 +- .../utility/TestcontainersConfiguration.java | 95 ++- .../utility/ThrowingFunction.java | 1 - .../testcontainers/utility/Versioning.java | 5 + .../OutOfPackageImagePullPolicyTest.java | 19 +- .../java/org/testcontainers/DaemonTest.java | 10 +- .../DockerClientFactoryTest.java | 8 +- .../DockerRegistryContainer.java | 39 +- .../containers/ContainerStateTest.java | 22 +- ...ockerComposeContainerWithServicesTest.java | 36 +- .../containers/DockerComposeFilesTest.java | 22 +- .../DockerComposeOverridesTest.java | 81 +- .../containers/ExposedHostTest.java | 36 +- .../FailureDetectingExternalResourceTest.java | 1 - .../containers/GenericContainerTest.java | 84 +- .../containers/NetworkTest.java | 73 +- ...ParsedDockerComposeFileValidationTest.java | 69 +- .../containers/ReusabilityUnitTests.java | 170 ++-- .../containers/output/ContainerLogsTest.java | 15 +- .../FrameConsumerResultCallbackTest.java | 100 ++- .../output/ToStringConsumerTest.java | 27 +- .../ExternalPortListeningCheckTest.java | 32 +- ...InternalCommandPortListeningCheckTest.java | 44 +- .../DockerHealthcheckWaitStrategyTest.java | 14 +- .../wait/strategy/WaitAllStrategyTest.java | 61 +- .../dockerclient/AmbiguousImagePullTest.java | 3 +- .../DockerClientConfigUtilsTest.java | 24 +- ...temPropertyClientProviderStrategyTest.java | 77 +- .../dockerclient/EventStreamTest.java | 30 +- .../dockerclient/ImagePullTest.java | 10 +- .../images/AgeBasedPullPolicyTest.java | 12 +- .../testcontainers/images/ImageDataTest.java | 8 +- .../images/ImagePullPolicyTest.java | 46 +- .../images/ParsedDockerfileTest.java | 90 ++- .../images/RemoteDockerImageTest.java | 10 +- .../images/builder/DockerfileBuildTest.java | 47 +- .../images/builder/DockerignoreTest.java | 30 +- .../builder/ImageFromDockerfileTest.java | 10 +- .../statement/AbstractStatementTest.java | 6 +- .../statement/KeyValuesStatementTest.java | 24 +- .../statement/MultiArgsStatementTest.java | 2 +- .../statement/RawStatementTest.java | 3 +- .../SingleArgumentStatementTest.java | 2 +- .../junit/BaseDockerComposeTest.java | 29 +- .../junit/CopyFileToContainerTest.java | 13 +- .../junit/DependenciesTest.java | 26 +- .../DockerComposeContainerScalingTest.java | 17 +- .../junit/DockerComposeContainerTest.java | 39 +- .../DockerComposeContainerWithBuildTest.java | 84 +- ...DockerComposeContainerWithOptionsTest.java | 53 +- .../junit/DockerComposeErrorHandlingTest.java | 14 +- .../junit/DockerComposeLocalImageTest.java | 4 +- .../junit/DockerComposeLogConsumerTest.java | 18 +- .../junit/DockerComposePassthroughTest.java | 20 +- .../junit/DockerComposeServiceTest.java | 13 +- .../junit/DockerComposeV2FormatTest.java | 6 +- .../junit/DockerComposeV2WithNetworkTest.java | 13 +- .../junit/DockerComposeWaitStrategyTest.java | 62 +- .../junit/DockerNetworkModeTest.java | 6 +- .../junit/DockerfileContainerTest.java | 31 +- .../testcontainers/junit/DockerfileTest.java | 68 +- .../junit/FileOperationsTest.java | 32 +- .../junit/FixedHostPortContainerTest.java | 32 +- .../junit/GenericContainerRuleTest.java | 269 ++++--- .../junit/NonExistentImagePullTest.java | 12 +- .../junit/OutputStreamTest.java | 57 +- .../junit/OutputStreamWithTTYTest.java | 43 +- .../ParameterizedDockerfileContainerTest.java | 30 +- .../junit/WorkingDirectoryTest.java | 11 +- .../strategy/AbstractWaitStrategyTest.java | 28 +- .../strategy/HostPortWaitStrategyTest.java | 3 +- .../wait/strategy/HttpWaitStrategyTest.java | 154 ++-- .../strategy/LogMessageWaitStrategyTest.java | 29 +- .../utility/AuthenticatedImagePullTest.java | 65 +- .../utility/ClasspathScannerTest.java | 83 +- .../utility/ComparableVersionTest.java | 24 +- .../DefaultImageNameSubstitutorTest.java | 2 + .../utility/DirectoryTarResourceTest.java | 81 +- .../DockerImageNameCompatibilityTest.java | 13 +- .../utility/DockerImageNameTest.java | 95 ++- .../utility/DockerStatusTest.java | 18 +- .../utility/FakeImageSubstitutor.java | 1 + .../utility/FilterRegistryTest.java | 12 +- .../utility/ImageNameSubstitutorTest.java | 12 +- .../utility/LazyFutureTest.java | 16 +- .../utility/MountableFileTest.java | 33 +- .../PrefixingImageNameSubstitutorTest.java | 51 +- .../utility/RegistryAuthLocatorTest.java | 76 +- .../utility/ResourceReaperTest.java | 27 +- .../TestcontainersConfigurationTest.java | 69 +- .../test/java/generic/CmdModifierTest.java | 15 +- .../src/test/java/generic/CommandsTest.java | 3 +- .../java/generic/ContainerCreationTest.java | 24 +- .../test/java/generic/ContainerLabelTest.java | 2 +- .../java/generic/HostPortExposedTest.java | 24 +- .../generic/ImageNameSubstitutionTest.java | 9 +- .../generic/MultiplePortsExposedTest.java | 13 +- .../test/java/generic/WaitStrategiesTest.java | 29 +- .../StartupCheckStrategyTest.java | 38 +- .../quickstart/RedisBackedCacheIntTest.java | 5 +- .../RedisBackedCacheIntTestStep0.java | 2 +- .../quickstart/RedisBackedCacheIntTest.java | 5 +- .../RedisBackedCacheIntTestStep0.java | 2 +- .../quickstart/RedisBackedCacheIntTest.groovy | 38 +- .../RedisBackedCacheIntTestStep0.groovy | 26 +- docs/modules/hivemq.md | 4 +- .../containers/CosmosDBEmulatorContainer.java | 5 +- .../containers/KeyStoreBuilder.java | 46 +- .../CosmosDBEmulatorContainerTest.java | 22 +- .../containers/CassandraContainer.java | 34 +- .../delegate/CassandraDatabaseDelegate.java | 11 +- .../wait/CassandraQueryWaitStrategy.java | 22 +- .../containers/CassandraContainerTest.java | 24 +- .../containers/ClickHouseContainer.java | 7 +- .../containers/ClickHouseProvider.java | 1 + .../clickhouse/ClickhouseJDBCDriverTest.java | 12 +- .../clickhouse/SimpleClickhouseTest.java | 4 +- .../containers/CockroachContainer.java | 32 +- .../CockroachContainerProvider.java | 1 + .../CockroachDBJDBCDriverTest.java | 12 +- .../cockroachdb/SimpleCockroachDBTest.java | 15 +- .../couchbase/BucketDefinition.java | 6 +- .../couchbase/CouchbaseContainer.java | 333 +++++--- .../couchbase/CouchbaseService.java | 2 - .../couchbase/CouchbaseContainerTest.java | 85 +- .../delegate/AbstractDatabaseDelegate.java | 7 +- .../delegate/DatabaseDelegate.java | 9 +- .../org/testcontainers/ext/ScriptUtils.java | 736 ++++++++++-------- .../ext/ScriptSplittingTest.java | 143 ++-- .../containers/Db2Container.java | 16 +- .../containers/Db2ContainerProvider.java | 1 + .../jdbc/db2/DB2JDBCDriverTest.java | 12 +- .../junit/db2/SimpleDb2Test.java | 17 +- .../dynamodb/DynaliteContainer.java | 22 +- .../dynamodb/DynaliteContainerTest.java | 30 +- .../elasticsearch/ElasticsearchContainer.java | 26 +- .../ElasticsearchContainerTest.java | 215 +++-- .../containers/BigtableEmulatorContainer.java | 9 +- .../DatastoreEmulatorContainer.java | 9 +- .../FirestoreEmulatorContainer.java | 9 +- .../containers/PubSubEmulatorContainer.java | 9 +- .../containers/SpannerEmulatorContainer.java | 9 +- .../BigtableEmulatorContainerTest.java | 61 +- .../DatastoreEmulatorContainerTest.java | 18 +- .../FirestoreEmulatorContainerTest.java | 24 +- .../PubSubEmulatorContainerTest.java | 85 +- .../SpannerEmulatorContainerTest.java | 68 +- .../hivemq/HiveMQContainer.java | 138 ++-- .../hivemq/HiveMQExtension.java | 98 ++- .../hivemq/ContainerWithControlCenterIT.java | 14 +- .../hivemq/ContainerWithCustomConfigIT.java | 25 +- ...ContainerWithExtensionFromDirectoryIT.java | 25 +- .../hivemq/ContainerWithExtensionIT.java | 22 +- .../ContainerWithExtensionSubclassIT.java | 22 +- .../ContainerWithFileInExtensionHomeIT.java | 55 +- .../hivemq/ContainerWithFileInHomeIT.java | 52 +- .../hivemq/ContainerWithLicenseIT.java | 46 +- .../ContainerWithoutPlatformExtensionsIT.java | 71 +- .../hivemq/CreateFileInCopiedDirectoryIT.java | 47 +- .../CreateFileInExtensionDirectoryIT.java | 45 +- ...DisableEnableExtensionFromDirectoryIT.java | 19 +- .../hivemq/DisableEnableExtensionIT.java | 29 +- .../hivemq/HiveMQExtensionTest.java | 5 +- .../hivemq/HiveMQTestContainerCore.java | 20 +- .../hivemq/docs/DemoDisableExtensionsIT.java | 27 +- .../hivemq/docs/DemoExtensionTestsIT.java | 32 +- .../hivemq/docs/DemoFilesIT.java | 35 +- .../hivemq/docs/DemoHiveMQContainerIT.java | 31 +- .../hivemq/util/MyExtension.java | 19 +- .../util/MyExtensionWithSubclasses.java | 19 +- .../hivemq/util/PublishModifier.java | 12 +- .../hivemq/util/TestPublishModifiedUtil.java | 31 +- .../containers/InfluxDBContainer.java | 14 +- .../containers/InfluxDBContainerTest.java | 8 +- .../InfluxDBContainerWithUserTest.java | 15 +- .../db/AbstractContainerDatabaseTest.java | 3 +- .../jdbc/AbstractJDBCDriverTest.java | 136 ++-- .../containers/JdbcDatabaseContainer.java | 49 +- .../JdbcDatabaseContainerProvider.java | 16 +- .../jdbc/ConnectionDelegate.java | 2 +- .../testcontainers/jdbc/ConnectionUrl.java | 89 +-- .../jdbc/ConnectionWrapper.java | 2 +- .../jdbc/ContainerDatabaseDriver.java | 63 +- .../jdbc/JdbcDatabaseDelegate.java | 18 +- .../testcontainers/jdbc/ext/ScriptUtils.java | 62 +- .../containers/JdbcDatabaseContainerTest.java | 5 +- .../jdbc/ConnectionUrlDriversTests.java | 109 ++- .../jdbc/ConnectionUrlTest.java | 41 +- .../jdbc/ContainerDatabaseDriverTest.java | 37 +- .../jdbc/MissingJdbcDriverTest.java | 2 +- .../FilesystemFriendlyNameGenerator.java | 10 +- .../junit/jupiter/Testcontainers.java | 1 - .../jupiter/TestcontainersExtension.java | 69 +- .../TestcontainersTestDescription.java | 2 + .../junit/jupiter/ComposeContainerTests.java | 3 +- .../FilesystemFriendlyNameGeneratorTest.java | 6 +- .../junit/jupiter/MixedLifecycleTests.java | 8 - .../junit/jupiter/PostgresContainerTests.java | 12 +- .../TestLifecycleAwareContainerMock.java | 10 +- ...tLifecycleAwareExceptionCapturingTest.java | 1 + .../jupiter/TestLifecycleAwareMethodTest.java | 17 +- .../jupiter/TestcontainersExtensionTests.java | 10 +- ...ntainersNestedRestartedContainerTests.java | 16 +- ...tcontainersNestedSharedContainerTests.java | 5 +- .../TestcontainersRestartBetweenTests.java | 10 +- .../TestcontainersSharedContainerTests.java | 6 +- .../jupiter/WrongAnnotationUsageTests.java | 3 - .../jupiter/inheritance/AbstractTestBase.java | 1 - .../org/testcontainers/k3s/K3sContainer.java | 13 +- .../k3s/Fabric8K3sContainerTest.java | 10 +- .../containers/KafkaContainer.java | 18 +- .../containers/KafkaContainerTest.java | 80 +- .../localstack/LocalStackContainer.java | 30 +- .../containers/localstack/LegacyModeTest.java | 70 +- .../localstack/LocalstackContainerTest.java | 160 ++-- .../containers/MariaDBContainer.java | 19 +- .../containers/MariaDBContainerProvider.java | 3 +- .../MariaDBR2DBCDatabaseContainer.java | 6 +- .../MariaDBR2DBCDatabaseContainerTest.java | 1 - .../jdbc/mariadb/MariaDBJDBCDriverTest.java | 49 +- .../junit/mariadb/SimpleMariaDBTest.java | 37 +- .../containers/MockServerContainer.java | 2 +- .../MockServerContainerRuleTest.java | 12 +- .../containers/MockServerContainerTest.java | 19 +- .../containers/SimpleHttpClient.java | 4 +- .../containers/MongoDBContainer.java | 45 +- .../containers/MongoDBContainerTest.java | 42 +- .../MSSQLR2DBCDatabaseContainer.java | 6 +- .../containers/MSSQLServerContainer.java | 21 +- .../MSSQLServerContainerProvider.java | 1 + .../MSSQLServerJDBCDriverTest.java | 15 +- .../CustomPasswordMSSQLServerTest.java | 60 +- .../CustomizableMSSQLServerTest.java | 9 +- .../mssqlserver/SimpleMSSQLServerTest.java | 25 +- .../containers/MySQLContainer.java | 17 +- .../containers/MySQLContainerProvider.java | 1 - .../MySQLR2DBCDatabaseContainer.java | 6 +- .../org/testcontainers/MySQLTestImages.java | 3 + .../MySQLR2DBCDatabaseContainerTest.java | 1 - .../containers/MySQLRootAccountTest.java | 7 +- .../jdbc/mysql/JDBCDriverWithPoolTest.java | 54 +- .../jdbc/mysql/MySQLJDBCDriverTest.java | 51 +- .../junit/mysql/CustomizableMysqlTest.java | 16 +- .../junit/mysql/MultiVersionMySQLTest.java | 20 +- .../junit/mysql/SimpleMySQLTest.java | 104 +-- .../neo4j/demos/plugins/HelloWorld.java | 1 - .../containers/Neo4jContainer.java | 71 +- .../Neo4jContainerJUnitIntegrationTest.java | 5 +- .../containers/Neo4jContainerTest.java | 93 +-- .../containers/NginxContainer.java | 7 +- .../testcontainers/junit/SimpleNginxTest.java | 14 +- .../containers/OracleContainer.java | 36 +- .../containers/OracleContainerProvider.java | 1 + .../containers/jdbc/OracleJDBCDriverTest.java | 24 +- .../junit/oracle/SimpleOracleTest.java | 29 +- .../containers/OrientDBContainer.java | 16 +- .../containers/OrientDBContainerTest.java | 13 +- .../containers/PostgisContainerProvider.java | 9 +- .../containers/PostgreSQLContainer.java | 29 +- .../PostgreSQLContainerProvider.java | 2 +- .../PostgreSQLR2DBCDatabaseContainer.java | 6 +- .../TimescaleDBContainerProvider.java | 9 +- .../PostgreSQLConnectionURLTest.java | 19 +- .../PostgreSQLR2DBCDatabaseContainerTest.java | 2 + .../containers/TimescaleDBContainerTest.java | 29 +- .../jdbc/DatabaseDriverShutdownTest.java | 1 + .../jdbc/DatabaseDriverTmpfsTest.java | 1 - .../jdbc/postgis/PostgisJDBCDriverTest.java | 20 +- .../postgresql/PostgreSQLJDBCDriverTest.java | 15 +- .../TimescaleDBJDBCDriverTest.java | 20 +- .../CustomizablePostgreSQLTest.java | 10 +- .../postgresql/SimplePostgreSQLTest.java | 30 +- .../containers/PrestoContainer.java | 26 +- .../containers/PrestoContainerProvider.java | 2 +- .../containers/PrestoContainerTest.java | 98 ++- .../jdbc/presto/PrestoJDBCDriverTest.java | 12 +- .../containers/PulsarContainer.java | 4 +- .../containers/PulsarContainerTest.java | 28 +- .../r2dbc/CancellableSubscription.java | 3 +- .../r2dbc/ConnectionPublisher.java | 10 +- .../r2dbc/EmptySubscription.java | 8 +- .../java/org/testcontainers/r2dbc/Hidden.java | 4 +- .../r2dbc/R2DBCDatabaseContainer.java | 1 - .../r2dbc/R2DBCDatabaseContainerProvider.java | 1 - .../TestcontainersR2DBCConnectionFactory.java | 45 +- ...tcontainersR2DBCConnectionFactoryTest.java | 19 +- .../AbstractR2DBCDatabaseContainerTest.java | 4 +- .../containers/RabbitMQContainer.java | 373 ++++++--- .../containers/RabbitMQContainerTest.java | 248 +++--- .../containers/BrowserWebDriverContainer.java | 125 ++- .../DefaultRecordingFileFactory.java | 23 +- .../containers/RecordingFileFactory.java | 15 +- .../containers/SeleniumUtils.java | 13 +- .../DefaultRecordingFileFactoryTest.java | 37 +- .../junit/BaseWebDriverContainerTest.java | 22 +- .../junit/BrowserWebDriverContainerTest.java | 18 +- ...ChromeRecordingWebDriverContainerTest.java | 102 +-- .../junit/ChromeWebDriverContainerTest.java | 2 +- .../ContainerWithoutCapabilitiesTest.java | 7 +- ...stomWaitTimeoutWebDriverContainerTest.java | 5 +- .../junit/FirefoxWebDriverContainerTest.java | 4 +- .../LocalServerWebDriverContainerTest.java | 8 +- .../junit/SeleniumStartTest.java | 14 +- .../junit/SeleniumUtilsTest.java | 2 - ...ecificImageNameWebDriverContainerTest.java | 5 +- .../containers/SolrClientUtils.java | 49 +- .../containers/SolrClientUtilsException.java | 1 + .../containers/SolrContainer.java | 23 +- .../SolrContainerConfiguration.java | 8 +- .../containers/SolrContainerTest.java | 15 +- .../spock/SpockTestDescription.groovy | 36 +- .../spock/Testcontainers.groovy | 1 - .../spock/TestcontainersExtension.groovy | 42 +- .../TestcontainersMethodInterceptor.groovy | 224 +++--- .../spock/ComposeContainerIT.groovy | 34 +- .../spock/MySqlContainerIT.groovy | 14 +- .../spock/PostgresContainerIT.groovy | 56 +- .../spock/SharedComposeContainerIT.groovy | 36 +- .../spock/SpockTestImages.groovy | 8 +- .../spock/TestHierarchyIT.groovy | 22 +- .../TestLifecycleAwareContainerMock.java | 10 +- .../spock/TestLifecycleAwareIT.groovy | 57 +- ...TestcontainersRestartBetweenTestsIT.groovy | 29 +- .../TestcontainersSharedContainerIT.groovy | 61 +- .../containers/ToxiproxyContainer.java | 50 +- .../containers/ToxiproxyTest.java | 78 +- .../containers/TrinoContainer.java | 17 +- .../containers/TrinoContainerProvider.java | 1 + .../containers/TrinoContainerTest.java | 38 +- .../jdbc/trino/TrinoJDBCDriverTest.java | 12 +- .../testcontainers/vault/VaultContainer.java | 46 +- .../testcontainers/vault/VaultLogLevel.java | 6 +- .../testcontainers/vault/VaultClientTest.java | 20 +- .../vault/VaultContainerTest.java | 74 +- .../org/testcontainers/testsupport/Flaky.java | 10 +- .../testsupport/FlakyTestJUnit4RetryRule.java | 14 +- .../testsupport/FlakyRuleTest.java | 60 +- 458 files changed, 8766 insertions(+), 5973 deletions(-) diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index b93d26d98bb..6d0df9a3c21 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -16,5 +16,6 @@ jobs: -v "$HOME:$HOME" \ -v "$PWD:$PWD" \ -w "$PWD" \ + -e AUTO_APPLY_GIT_HOOKS=false \ openjdk:8-jdk-alpine \ ./gradlew --no-daemon --continue --scan testcontainers:test --tests '*GenericContainerRuleTest' diff --git a/build.gradle b/build.gradle index adbd1a47c4a..1458b3db027 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,13 @@ buildscript { repositories { mavenCentral() + maven { url 'https://jitpack.io' } } dependencies { // https://github.com/melix/japicmp-gradle-plugin/issues/36 classpath 'com.google.guava:guava:30.1.1-jre' + classpath 'com.github.kiview:captain-hook:76a1c11a16' } } @@ -17,6 +19,12 @@ plugins { } apply from: "$rootDir/gradle/ci-support.gradle" +apply plugin: 'com.github.tjni.captainhook' + +captainHook { + autoApplyGitHooks = Boolean.valueOf(System.getenv("AUTO_APPLY_GIT_HOOKS")) + preCommit = './gradlew spotlessApply' +} subprojects { apply plugin: 'java-library' @@ -110,8 +118,8 @@ subprojects { } spotless { - enforceCheck false java { + toggleOffOn() removeUnusedImports() trimTrailingWhitespace() endWithNewline() @@ -134,6 +142,5 @@ subprojects { checkstyle { toolVersion = "9.3" configFile = rootProject.file('config/checkstyle/checkstyle.xml') - ignoreFailures = true } } diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 39598dae2e4..ccb8367404c 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -11,8 +11,12 @@ LITERAL_FOR, LITERAL_IF, LITERAL_WHILE, - LITERAL_CASE, - LITERAL_DEFAULT, + " + /> + + + diff --git a/core/src/jarFileTest/java/org/testcontainers/AbstractJarFileTest.java b/core/src/jarFileTest/java/org/testcontainers/AbstractJarFileTest.java index d6043422640..ae92aa371b0 100644 --- a/core/src/jarFileTest/java/org/testcontainers/AbstractJarFileTest.java +++ b/core/src/jarFileTest/java/org/testcontainers/AbstractJarFileTest.java @@ -5,8 +5,7 @@ import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; - -import static java.util.Collections.emptyMap; +import java.util.Collections; public abstract class AbstractJarFileTest { @@ -16,7 +15,7 @@ public abstract class AbstractJarFileTest { try { Path jarFilePath = Paths.get(System.getProperty("jarFile")); URI jarFileUri = new URI("jar", jarFilePath.toUri().toString(), null); - FileSystem fileSystem = FileSystems.newFileSystem(jarFileUri, emptyMap()); + FileSystem fileSystem = FileSystems.newFileSystem(jarFileUri, Collections.emptyMap()); root = fileSystem.getPath("/"); } catch (Exception e) { throw new RuntimeException(e); diff --git a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java index 4cf7b3a9e9f..99fd1359c85 100644 --- a/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java +++ b/core/src/jarFileTest/java/org/testcontainers/JarFileShadingTest.java @@ -13,34 +13,26 @@ public class JarFileShadingTest extends AbstractJarFileTest { @Test public void testPackages() throws Exception { - assertThatFileList(root).containsOnly( - "org", - "META-INF" - ); - - assertThatFileList(root.resolve("org")).containsOnly( - "testcontainers" - ); + assertThatFileList(root).containsOnly("org", "META-INF"); + + assertThatFileList(root.resolve("org")).containsOnly("testcontainers"); } @Test public void testMetaInf() throws Exception { - assertThatFileList(root.resolve("META-INF")).containsOnly( - "MANIFEST.MF", - "services" - ); + assertThatFileList(root.resolve("META-INF")).containsOnly("MANIFEST.MF", "services"); } @Test public void testMetaInfServices() throws Exception { assertThatFileList(root.resolve("META-INF").resolve("services")) - .allMatch(it -> it.startsWith("org.testcontainers.")); + .allMatch(it -> it.startsWith("org.testcontainers.")); } private ListAssert assertThatFileList(Path path) throws IOException { return (ListAssert) assertThat(Files.list(path)) - .extracting(Path::getFileName) - .extracting(Path::toString) - .extracting(it -> it.endsWith("/") ? it.substring(0, it.length() - 1) : it); + .extracting(Path::getFileName) + .extracting(Path::toString) + .extracting(it -> it.endsWith("/") ? it.substring(0, it.length() - 1) : it); } } diff --git a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java index 208c8702654..77156e77636 100644 --- a/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java +++ b/core/src/jarFileTest/java/org/testcontainers/PublicBinaryAPITest.java @@ -37,6 +37,7 @@ public class PublicBinaryAPITest extends AbstractJarFileTest { private static String SHADED_PACKAGE = "org.testcontainers.shaded."; + private static String SHADED_PACKAGE_PATH = SHADED_PACKAGE.replaceAll("\\.", "/"); static { @@ -49,36 +50,38 @@ public class PublicBinaryAPITest extends AbstractJarFileTest { public static List data() throws Exception { List result = new ArrayList<>(); - Files.walkFileTree(root, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { - String fileName = path.toString(); + Files.walkFileTree( + root, + new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { + String fileName = path.toString(); - if (!fileName.endsWith(".class")) { - return super.visitFile(path, attrs); - } + if (!fileName.endsWith(".class")) { + return super.visitFile(path, attrs); + } - if (!fileName.startsWith("/org/testcontainers/") ) { - return super.visitFile(path, attrs); - } + if (!fileName.startsWith("/org/testcontainers/")) { + return super.visitFile(path, attrs); + } - if (fileName.startsWith("/" + SHADED_PACKAGE_PATH)) { - return super.visitFile(path, attrs); - } + if (fileName.startsWith("/" + SHADED_PACKAGE_PATH)) { + return super.visitFile(path, attrs); + } - try(InputStream inputStream = Files.newInputStream(path)) { - ClassReader reader = new ClassReader(inputStream); - ClassNode node = new ClassNode(); - reader.accept(node, ClassReader.SKIP_CODE); - if ((node.access & Opcodes.ACC_PUBLIC) != 0) { - result.add(new Object[]{ fileName, node }); + try (InputStream inputStream = Files.newInputStream(path)) { + ClassReader reader = new ClassReader(inputStream); + ClassNode node = new ClassNode(); + reader.accept(node, ClassReader.SKIP_CODE); + if ((node.access & Opcodes.ACC_PUBLIC) != 0) { + result.add(new Object[] { fileName, node }); + } } - } - return super.visitFile(path, attrs); + return super.visitFile(path, attrs); + } } - }); + ); return result; } @@ -100,39 +103,36 @@ public void setUp() { @Test public void testSuperClass() { - assertThat(classNode.superName) - .doesNotStartWith(SHADED_PACKAGE_PATH); + assertThat(classNode.superName).doesNotStartWith(SHADED_PACKAGE_PATH); } @Test public void testInterfaces() { - assertThat(classNode.interfaces) - .allSatisfy(it -> assertThat(it).doesNotStartWith(SHADED_PACKAGE_PATH)); + assertThat(classNode.interfaces).allSatisfy(it -> assertThat(it).doesNotStartWith(SHADED_PACKAGE_PATH)); } @Test public void testMethodReturnTypes() { assertThat(classNode.methods) - .filteredOn(it -> (it.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0) - .allSatisfy(it -> assertThat(Type.getReturnType(it.desc).getClassName()).doesNotStartWith(SHADED_PACKAGE)); + .filteredOn(it -> (it.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0) + .allSatisfy(it -> assertThat(Type.getReturnType(it.desc).getClassName()).doesNotStartWith(SHADED_PACKAGE)); } @Test public void testMethodArguments() { assertThat(classNode.methods) - .filteredOn(it -> (it.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0) - .allSatisfy(method -> assertThat(Arrays.asList(Type.getArgumentTypes(method.desc))) - .extracting(Type::getClassName) - .allSatisfy(it -> assertThat(it).doesNotStartWith(SHADED_PACKAGE)) - ); + .filteredOn(it -> (it.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0) + .allSatisfy(method -> { + assertThat(Arrays.asList(Type.getArgumentTypes(method.desc))) + .extracting(Type::getClassName) + .allSatisfy(it -> assertThat(it).doesNotStartWith(SHADED_PACKAGE)); + }); } @Test public void testFields() { assertThat(classNode.fields) - .filteredOn(it -> (it.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0) - .allSatisfy(it -> assertThat(Type.getType(it.desc).getClassName()) - .doesNotStartWith(SHADED_PACKAGE) - ); + .filteredOn(it -> (it.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0) + .allSatisfy(it -> assertThat(Type.getType(it.desc).getClassName()).doesNotStartWith(SHADED_PACKAGE)); } } diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index c1e999d392a..04c20236763 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -51,16 +51,17 @@ public class DockerClientFactory { public static final ThreadGroup TESTCONTAINERS_THREAD_GROUP = new ThreadGroup("testcontainers"); + public static final String TESTCONTAINERS_LABEL = DockerClientFactory.class.getPackage().getName(); + public static final String TESTCONTAINERS_SESSION_ID_LABEL = TESTCONTAINERS_LABEL + ".sessionId"; public static final String SESSION_ID = UUID.randomUUID().toString(); - public static final Map DEFAULT_LABELS = ImmutableMap.of( - TESTCONTAINERS_LABEL, "true" - ); + public static final Map DEFAULT_LABELS = ImmutableMap.of(TESTCONTAINERS_LABEL, "true"); private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14"); + private static DockerClientFactory instance; // Cached client configuration @@ -79,9 +80,7 @@ public class DockerClientFactory { private final boolean fileMountingSupported = checkMountableFile(); @VisibleForTesting - DockerClientFactory() { - - } + DockerClientFactory() {} public static DockerClient lazyClient() { return new DockerClientDelegate() { @@ -102,7 +101,7 @@ public String toString() { * * @return the singleton instance of DockerClientFactory */ - public synchronized static DockerClientFactory instance() { + public static synchronized DockerClientFactory instance() { if (instance == null) { instance = new DockerClientFactory(); } @@ -112,6 +111,7 @@ public synchronized static DockerClientFactory instance() { /** * Checks whether Docker is accessible and {@link #client()} is able to produce a client. + * * @return true if Docker is available, false if not. */ public synchronized boolean isDockerAvailable() { @@ -149,16 +149,11 @@ public String getRemoteDockerUnixSocketPath() { } URI dockerHost = getTransportConfig().getDockerHost(); - String path = "unix".equals(dockerHost.getScheme()) - ? dockerHost.getRawPath() - : "/var/run/docker.sock"; - return SystemUtils.IS_OS_WINDOWS - ? "/" + path - : path; + String path = "unix".equals(dockerHost.getScheme()) ? dockerHost.getRawPath() : "/var/run/docker.sock"; + return SystemUtils.IS_OS_WINDOWS ? "/" + path : path; } /** - * * @return a new initialized Docker client */ @Synchronized @@ -175,16 +170,16 @@ public DockerClient client() { final DockerClientProviderStrategy strategy = getOrInitializeStrategy(); - client = new DockerClientDelegate() { - - @Getter - final DockerClient dockerClient = strategy.getDockerClient(); + client = + new DockerClientDelegate() { + @Getter + final DockerClient dockerClient = strategy.getDockerClient(); - @Override - public void close() { - throw new IllegalStateException("You should never close the global DockerClient!"); - } - }; + @Override + public void close() { + throw new IllegalStateException("You should never close the global DockerClient!"); + } + }; log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress()); Info dockerInfo = strategy.getInfo(); @@ -192,11 +187,22 @@ public void close() { Version version = client.versionCmd().exec(); log.debug("Docker version: {}", version.getRawValues()); activeApiVersion = version.getApiVersion(); - log.info("Connected to docker: \n" + - " Server Version: " + dockerInfo.getServerVersion() + "\n" + - " API Version: " + activeApiVersion + "\n" + - " Operating System: " + dockerInfo.getOperatingSystem() + "\n" + - " Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB"); + log.info( + "Connected to docker: \n" + + " Server Version: " + + dockerInfo.getServerVersion() + + "\n" + + " API Version: " + + activeApiVersion + + "\n" + + " Operating System: " + + dockerInfo.getOperatingSystem() + + "\n" + + " Total Memory: " + + dockerInfo.getMemTotal() / + (1024 * 1024) + + " MB" + ); try { //noinspection deprecation @@ -225,7 +231,8 @@ public void close() { } private void checkDockerVersion(String dockerVersion) { - boolean versionIsSufficient = new ComparableVersion(dockerVersion).compareTo(new ComparableVersion("1.6.0")) >= 0; + boolean versionIsSufficient = new ComparableVersion(dockerVersion).compareTo(new ComparableVersion("1.6.0")) >= + 0; check("Docker server version should be at least 1.6.0", versionIsSufficient); } @@ -241,14 +248,22 @@ private void check(String message, boolean isSuccessful) { private boolean checkMountableFile() { DockerClient dockerClient = client(); - MountableFile mountableFile = MountableFile.forClasspathResource(ResourceReaper.class.getName().replace(".", "/") + ".class"); + MountableFile mountableFile = MountableFile.forClasspathResource( + ResourceReaper.class.getName().replace(".", "/") + ".class" + ); Volume volume = new Volume("/dummy"); try { return runInsideDocker( - createContainerCmd -> createContainerCmd.withBinds(new Bind(mountableFile.getResolvedPath(), volume, AccessMode.ro)), + createContainerCmd -> { + createContainerCmd.withBinds(new Bind(mountableFile.getResolvedPath(), volume, AccessMode.ro)); + }, (__, containerId) -> { - try (InputStream stream = dockerClient.copyArchiveFromContainerCmd(containerId, volume.getPath()).exec()) { + try ( + InputStream stream = dockerClient + .copyArchiveFromContainerCmd(containerId, volume.getPath()) + .exec() + ) { stream.read(); return true; } catch (Exception e) { @@ -293,16 +308,22 @@ public String dockerHostIpAddress() { return getOrInitializeStrategy().getDockerHostIpAddress(); } - public T runInsideDocker(Consumer createContainerCmdConsumer, BiFunction block) { + public T runInsideDocker( + Consumer createContainerCmdConsumer, + BiFunction block + ) { return runInsideDocker(TINY_IMAGE, createContainerCmdConsumer, block); } - T runInsideDocker(DockerImageName imageName, Consumer createContainerCmdConsumer, BiFunction block) { + T runInsideDocker( + DockerImageName imageName, + Consumer createContainerCmdConsumer, + BiFunction block + ) { RemoteDockerImage dockerImage = new RemoteDockerImage(imageName); HashMap labels = new HashMap<>(DEFAULT_LABELS); labels.putAll(ResourceReaper.instance().getLabels()); - CreateContainerCmd createContainerCmd = client.createContainerCmd(dockerImage.get()) - .withLabels(labels); + CreateContainerCmd createContainerCmd = client.createContainerCmd(dockerImage.get()).withLabels(labels); createContainerCmdConsumer.accept(createContainerCmd); String id = createContainerCmd.exec().getId(); diff --git a/core/src/main/java/org/testcontainers/Testcontainers.java b/core/src/main/java/org/testcontainers/Testcontainers.java index 0f83725c55b..ab567e1fda7 100644 --- a/core/src/main/java/org/testcontainers/Testcontainers.java +++ b/core/src/main/java/org/testcontainers/Testcontainers.java @@ -1,12 +1,11 @@ package org.testcontainers; -import java.util.Map; -import java.util.Map.Entry; - import lombok.experimental.UtilityClass; - import org.testcontainers.containers.PortForwardingContainer; +import java.util.Map; +import java.util.Map.Entry; + @UtilityClass public class Testcontainers { @@ -15,10 +14,10 @@ public void exposeHostPorts(int... ports) { PortForwardingContainer.INSTANCE.exposeHostPort(port); } } - + public void exposeHostPorts(Map ports) { - for(Entry entry : ports.entrySet()) { - PortForwardingContainer.INSTANCE.exposeHostPort(entry.getKey(), entry.getValue()); - } + for (Entry entry : ports.entrySet()) { + PortForwardingContainer.INSTANCE.exposeHostPort(entry.getKey(), entry.getValue()); + } } } diff --git a/core/src/main/java/org/testcontainers/UnstableAPI.java b/core/src/main/java/org/testcontainers/UnstableAPI.java index 21fd2c3176c..01221738dd4 100644 --- a/core/src/main/java/org/testcontainers/UnstableAPI.java +++ b/core/src/main/java/org/testcontainers/UnstableAPI.java @@ -11,11 +11,7 @@ * a stable API. */ @Retention(RetentionPolicy.SOURCE) -@Target({ - ElementType.TYPE, - ElementType.METHOD, - ElementType.FIELD, -}) +@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD }) @Documented public @interface UnstableAPI { } diff --git a/core/src/main/java/org/testcontainers/containers/BindMode.java b/core/src/main/java/org/testcontainers/containers/BindMode.java index 579dc4d5eca..5fc9c610165 100644 --- a/core/src/main/java/org/testcontainers/containers/BindMode.java +++ b/core/src/main/java/org/testcontainers/containers/BindMode.java @@ -6,7 +6,8 @@ * Possible modes for binding storage volumes. */ public enum BindMode { - READ_ONLY(AccessMode.ro), READ_WRITE(AccessMode.rw); + READ_ONLY(AccessMode.ro), + READ_WRITE(AccessMode.rw); public final AccessMode accessMode; diff --git a/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java b/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java index fbb2a7cee6e..81525710700 100644 --- a/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java +++ b/core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java @@ -13,7 +13,6 @@ import java.util.List; import java.util.Map; - /** * Class to provide a wait strategy target for services started through docker-compose */ @@ -21,15 +20,23 @@ class ComposeServiceWaitStrategyTarget implements WaitStrategyTarget { private final Container container; + private final GenericContainer proxyContainer; + private final DockerClient dockerClient; + @NonNull private Map mappedPorts; - @Getter(lazy=true) + + @Getter(lazy = true) private final InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(getContainerId()).exec(); - ComposeServiceWaitStrategyTarget(DockerClient dockerClient, Container container, GenericContainer proxyContainer, - @NonNull Map mappedPorts) { + ComposeServiceWaitStrategyTarget( + DockerClient dockerClient, + Container container, + GenericContainer proxyContainer, + @NonNull Map mappedPorts + ) { this.dockerClient = dockerClient; this.container = container; this.proxyContainer = proxyContainer; diff --git a/core/src/main/java/org/testcontainers/containers/Container.java b/core/src/main/java/org/testcontainers/containers/Container.java index 88fe4802945..7e6f492c284 100644 --- a/core/src/main/java/org/testcontainers/containers/Container.java +++ b/core/src/main/java/org/testcontainers/containers/Container.java @@ -1,17 +1,15 @@ package org.testcontainers.containers; -import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Bind; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NonNull; import lombok.Value; -import org.testcontainers.DockerClientFactory; -import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.traits.LinkableContainer; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.images.ImagePullPolicy; import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.LogUtils; import org.testcontainers.utility.MountableFile; @@ -25,7 +23,6 @@ import java.util.function.Function; public interface Container> extends LinkableContainer, ContainerState { - /** * @return a reference to this container instance, cast to the expected generic type. */ @@ -40,8 +37,11 @@ default SELF self() { @Value @AllArgsConstructor(access = AccessLevel.MODULE) class ExecResult { + int exitCode; + String stdout; + String stderr; } @@ -298,7 +298,11 @@ default SELF withEnv(String key, Function, String> mapper) { * @param mode access mode for the file * @return this */ - default SELF withClasspathResourceMapping(final String resourcePath, final String containerPath, final BindMode mode) { + default SELF withClasspathResourceMapping( + final String resourcePath, + final String containerPath, + final BindMode mode + ) { withClasspathResourceMapping(resourcePath, containerPath, mode, SelinuxContext.NONE); return self(); } @@ -313,7 +317,12 @@ default SELF withClasspathResourceMapping(final String resourcePath, final Strin * @param selinuxContext selinux context argument to use for this file * @return this */ - SELF withClasspathResourceMapping(String resourcePath, String containerPath, BindMode mode, SelinuxContext selinuxContext); + SELF withClasspathResourceMapping( + String resourcePath, + String containerPath, + BindMode mode, + SelinuxContext selinuxContext + ); /** * Set the duration of waiting time until container treated as started. @@ -403,7 +412,6 @@ default void followOutput(Consumer consumer, OutputFrame.OutputType LogUtils.followOutput(getDockerClient(), getContainerId(), consumer, types); } - /** * Attach an output consumer at container startup, enabling stdout and stderr to be followed, waited on, etc. *

diff --git a/core/src/main/java/org/testcontainers/containers/ContainerFetchException.java b/core/src/main/java/org/testcontainers/containers/ContainerFetchException.java index 66aa1a493b0..66414434786 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerFetchException.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerFetchException.java @@ -4,6 +4,7 @@ * Created by rnorth on 15/10/2015. */ public class ContainerFetchException extends RuntimeException { + public ContainerFetchException(String s, Exception e) { super(s, e); } diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 51eb4daddde..b82b5448d2f 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -37,7 +37,6 @@ import java.util.stream.Collectors; public interface ContainerState { - String STATE_HEALTHY = "healthy"; /** @@ -109,7 +108,9 @@ default boolean isHealthy() { InspectContainerResponse inspectContainerResponse = getCurrentContainerInfo(); HealthState health = inspectContainerResponse.getState().getHealth(); if (health == null) { - throw new RuntimeException("This container's image does not have a healthcheck declared, so health cannot be determined. Either amend the image or use another approach to determine whether containers are healthy."); + throw new RuntimeException( + "This container's image does not have a healthcheck declared, so health cannot be determined. Either amend the image or use another approach to determine whether containers are healthy." + ); } return STATE_HEALTHY.equals(health.getStatus()); @@ -145,7 +146,10 @@ default Integer getFirstMappedPort() { * @return the port that the exposed port is mapped to, or null if it is not exposed */ default Integer getMappedPort(int originalPort) { - Preconditions.checkState(this.getContainerId() != null, "Mapped port can only be obtained after the container is started"); + Preconditions.checkState( + this.getContainerId() != null, + "Mapped port can only be obtained after the container is started" + ); Ports.Binding[] binding = new Ports.Binding[0]; final InspectContainerResponse containerInfo = this.getContainerInfo(); @@ -183,7 +187,8 @@ default List getPortBindings() { * @return the bound port numbers */ default List getBoundPortNumbers() { - return getPortBindings().stream() + return getPortBindings() + .stream() .map(PortBinding::parse) .map(PortBinding::getBinding) .map(Ports.Binding::getHostPortSpec) @@ -194,7 +199,6 @@ default List getBoundPortNumbers() { .collect(Collectors.toList()); } - /** * @return all log output from the container from start until the current instant (both stdout and stderr) */ @@ -228,7 +232,8 @@ default String getContainerId() { *

* @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, String...) */ - default Container.ExecResult execInContainer(String... command) throws UnsupportedOperationException, IOException, InterruptedException { + default Container.ExecResult execInContainer(String... command) + throws UnsupportedOperationException, IOException, InterruptedException { return execInContainer(StandardCharsets.UTF_8, command); } @@ -237,7 +242,8 @@ default Container.ExecResult execInContainer(String... command) throws Unsupport *

* @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, Charset, String...) */ - default Container.ExecResult execInContainer(Charset outputCharset, String... command) throws UnsupportedOperationException, IOException, InterruptedException { + default Container.ExecResult execInContainer(Charset outputCharset, String... command) + throws UnsupportedOperationException, IOException, InterruptedException { return ExecInContainerPattern.execInContainer(getDockerClient(), getContainerInfo(), outputCharset, command); } @@ -253,7 +259,9 @@ default void copyFileToContainer(MountableFile mountableFile, String containerPa if (containerPath.endsWith("/") && sourceFile.isFile()) { final Logger logger = LoggerFactory.getLogger(GenericContainer.class); - logger.warn("folder-like containerPath in copyFileToContainer is deprecated, please explicitly specify a file path"); + logger.warn( + "folder-like containerPath in copyFileToContainer is deprecated, please explicitly specify a file path" + ); copyFileToContainer((Transferable) mountableFile, containerPath + sourceFile.getName()); } else { copyFileToContainer((Transferable) mountableFile, containerPath); @@ -299,13 +307,17 @@ default void copyFileToContainer(Transferable transferable, String containerPath * @throws IOException if there's an issue communicating with Docker or receiving entry from TarArchiveInputStream * @throws InterruptedException if the thread waiting for the response is interrupted */ - default void copyFileFromContainer(String containerPath, String destinationPath) throws IOException, InterruptedException { - copyFileFromContainer(containerPath, inputStream -> { - try(FileOutputStream output = new FileOutputStream(destinationPath)) { - IOUtils.copy(inputStream, output); - return null; + default void copyFileFromContainer(String containerPath, String destinationPath) + throws IOException, InterruptedException { + copyFileFromContainer( + containerPath, + inputStream -> { + try (FileOutputStream output = new FileOutputStream(destinationPath)) { + IOUtils.copy(inputStream, output); + return null; + } } - }); + ); } /** @@ -315,7 +327,7 @@ default void copyFileFromContainer(String containerPath, String destinationPath) * @param function function that takes InputStream of the copied file */ @SneakyThrows - default T copyFileFromContainer(String containerPath, ThrowingFunction function) { + default T copyFileFromContainer(String containerPath, ThrowingFunction function) { if (getContainerId() == null) { throw new IllegalStateException("copyFileFromContainer can only be used when the Container is created."); } diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 6f0a3a086b6..86a98586c7f 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -6,7 +6,9 @@ import com.github.dockerjava.transport.SSLConfig; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; import com.google.common.base.Splitter; +import com.google.common.base.Strings; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.Uninterruptibles; @@ -57,42 +59,52 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; -import static org.testcontainers.containers.BindMode.READ_WRITE; - /** * Container which launches Docker Compose, for the purposes of launching a defined set of containers. */ @Slf4j -public class DockerComposeContainer> extends FailureDetectingExternalResource implements Startable { +public class DockerComposeContainer> + extends FailureDetectingExternalResource + implements Startable { /** * Random identifier which will become part of spawned containers names, so we can shut them down */ private final String identifier; + private final List composeFiles; + private DockerComposeFiles dockerComposeFiles; + private final Map scalingPreferences = new HashMap<>(); + private DockerClient dockerClient; + private boolean localCompose; + private boolean pull = true; + private boolean build = false; + private Set options = new HashSet<>(); + private boolean tailChildContainers; private String project; private final AtomicInteger nextAmbassadorPort = new AtomicInteger(2000); + private final Map> ambassadorPortMappings = new ConcurrentHashMap<>(); + private final Map serviceInstanceMap = new ConcurrentHashMap<>(); + private final Map waitStrategyMap = new ConcurrentHashMap<>(); + private final SocatContainer ambassadorContainer = new SocatContainer(); + private final Map>> logConsumers = new ConcurrentHashMap<>(); private static final Object MUTEX = new Object(); @@ -104,6 +116,7 @@ public class DockerComposeContainer> e * necessarily to containers that are spawned by Compose itself) */ private Map env = new HashMap<>(); + private RemoveImages removeImages; @Deprecated @@ -148,13 +161,11 @@ public void starting(Description description) { @Override @Deprecated - protected void succeeded(Description description) { - } + protected void succeeded(Description description) {} @Override @Deprecated - protected void failed(Throwable e, Description description) { - } + protected void failed(Throwable e, Description description) {} @Override @Deprecated @@ -183,15 +194,23 @@ private void pullImages() { // Pull images using our docker client rather than compose itself, // (a) as a workaround for https://github.com/docker/compose/issues/5854, which prevents authenticated image pulls being possible when credential helpers are in use // (b) so that credential helper-based auth still works when compose is running from within a container - dockerComposeFiles.getDependencyImages() + dockerComposeFiles + .getDependencyImages() .forEach(imageName -> { try { - log.info("Preemptively checking local images for '{}', referenced via a compose file or transitive Dockerfile. If not available, it will be pulled.", imageName); + log.info( + "Preemptively checking local images for '{}', referenced via a compose file or transitive Dockerfile. If not available, it will be pulled.", + imageName + ); new RemoteDockerImage(DockerImageName.parse(imageName)) .withImageNameSubstitutor(ImageNameSubstitutor.noop()) .get(); } catch (Exception e) { - log.warn("Unable to pre-fetch an image ({}) depended upon by Docker Compose build - startup will continue but may fail. Exception message was: {}", imageName, e.getMessage()); + log.warn( + "Unable to pre-fetch an image ({}) depended upon by Docker Compose build - startup will continue but may fail. Exception message was: {}", + imageName, + e.getMessage() + ); } }); } @@ -203,18 +222,21 @@ public SELF withServices(@NonNull String... services) { private void createServices() { // services that have been explicitly requested to be started. If empty, all services should be started. - final String serviceNameArgs = Stream.concat( - services.stream(), // services that have been specified with `withServices` - scalingPreferences.keySet().stream() // services that are implicitly needed via `withScaledService` - ) + final String serviceNameArgs = Stream + .concat( + services.stream(), // services that have been specified with `withServices` + scalingPreferences.keySet().stream() // services that are implicitly needed via `withScaledService` + ) .distinct() - .collect(joining(" ")); + .collect(Collectors.joining(" ")); // Apply scaling for the services specified using `withScaledService` - final String scalingOptions = scalingPreferences.entrySet().stream() + final String scalingOptions = scalingPreferences + .entrySet() + .stream() .map(entry -> "--scale " + entry.getKey() + "=" + entry.getValue()) .distinct() - .collect(joining(" ")); + .collect(Collectors.joining(" ")); String command = optionsAsString() + "up -d"; @@ -222,11 +244,11 @@ private void createServices() { command += " --build"; } - if (!isNullOrEmpty(scalingOptions)) { + if (!Strings.isNullOrEmpty(scalingOptions)) { command += " " + scalingOptions; } - if (!isNullOrEmpty(serviceNameArgs)) { + if (!Strings.isNullOrEmpty(serviceNameArgs)) { command += " " + serviceNameArgs; } @@ -235,10 +257,8 @@ private void createServices() { } private String optionsAsString() { - String optionsString = options - .stream() - .collect(joining(" ")); - if (optionsString.length() !=0 ) { + String optionsString = options.stream().collect(Collectors.joining(" ")); + if (optionsString.length() != 0) { // ensures that there is a space between the options and 'up' if options are passed. return optionsString + " "; } else { @@ -252,15 +272,17 @@ private void waitUntilServiceStarted() { Set servicesToWaitFor = waitStrategyMap.keySet(); Set instantiatedServices = serviceInstanceMap.keySet(); - Sets.SetView missingServiceInstances = - Sets.difference(servicesToWaitFor, instantiatedServices); + Sets.SetView missingServiceInstances = Sets.difference(servicesToWaitFor, instantiatedServices); if (!missingServiceInstances.isEmpty()) { throw new IllegalStateException( - "Services named " + missingServiceInstances + " " + - "do not exist, but wait conditions have been defined " + - "for them. This might mean that you misspelled " + - "the service name when defining the wait condition."); + "Services named " + + missingServiceInstances + + " " + + "do not exist, but wait conditions have been defined " + + "for them. This might mean that you misspelled " + + "the service name when defining the wait condition." + ); } serviceInstanceMap.forEach(this::waitUntilServiceStarted); @@ -268,15 +290,21 @@ private void waitUntilServiceStarted() { private void createServiceInstance(Container container) { String serviceName = getServiceNameFromContainer(container); - final ComposeServiceWaitStrategyTarget containerInstance = new ComposeServiceWaitStrategyTarget(dockerClient, container, - ambassadorContainer, ambassadorPortMappings.getOrDefault(serviceName, new HashMap<>())); + final ComposeServiceWaitStrategyTarget containerInstance = new ComposeServiceWaitStrategyTarget( + dockerClient, + container, + ambassadorContainer, + ambassadorPortMappings.getOrDefault(serviceName, new HashMap<>()) + ); String containerId = containerInstance.getContainerId(); if (tailChildContainers) { followLogs(containerId, new Slf4jLogConsumer(log).withPrefix(container.getNames()[0])); } //follow logs using registered consumers for this service - logConsumers.getOrDefault(serviceName, Collections.emptyList()).forEach(consumer -> followLogs(containerId, consumer)); + logConsumers + .getOrDefault(serviceName, Collections.emptyList()) + .forEach(consumer -> followLogs(containerId, consumer)); serviceInstanceMap.putIfAbsent(serviceName, containerInstance); } @@ -294,8 +322,8 @@ private String getServiceNameFromContainer(Container container) { } private void runWithCompose(String cmd) { - checkNotNull(composeFiles); - checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided"); + Preconditions.checkNotNull(composeFiles); + Preconditions.checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided"); final DockerCompose dockerCompose; if (localCompose) { @@ -304,26 +332,24 @@ private void runWithCompose(String cmd) { dockerCompose = new ContainerisedDockerCompose(composeFiles, project); } - dockerCompose - .withCommand(cmd) - .withEnv(env) - .invoke(); + dockerCompose.withCommand(cmd).withEnv(env).invoke(); } private void registerContainersForShutdown() { - ResourceReaper.instance().registerLabelsFilterForCleanup(Collections.singletonMap( - "com.docker.compose.project", project - )); + ResourceReaper + .instance() + .registerLabelsFilterForCleanup(Collections.singletonMap("com.docker.compose.project", project)); } @VisibleForTesting List listChildContainers() { - return dockerClient.listContainersCmd() + return dockerClient + .listContainersCmd() .withShowAll(true) - .exec().stream() - .filter(container -> Arrays.stream(container.getNames()).anyMatch(name -> - name.startsWith("/" + project))) - .collect(toList()); + .exec() + .stream() + .filter(container -> Arrays.stream(container.getNames()).anyMatch(name -> name.startsWith("/" + project))) + .collect(Collectors.toList()); } private void startAmbassadorContainers() { @@ -345,7 +371,6 @@ public void stop() { cmd += " --rmi " + removeImages.dockerRemoveImagesType(); } runWithCompose(cmd); - } finally { project = randomProjectId(); } @@ -360,12 +385,16 @@ public DockerComposeContainer withExposedService(String serviceName, int instanc return withExposedService(serviceName + "_" + instance, servicePort); } - public DockerComposeContainer withExposedService(String serviceName, int instance, int servicePort, WaitStrategy waitStrategy) { + public DockerComposeContainer withExposedService( + String serviceName, + int instance, + int servicePort, + WaitStrategy waitStrategy + ) { return withExposedService(serviceName + "_" + instance, servicePort, waitStrategy); } public SELF withExposedService(String serviceName, int servicePort, @NonNull WaitStrategy waitStrategy) { - String serviceInstanceName = getServiceInstanceName(serviceName); /* @@ -384,7 +413,9 @@ public SELF withExposedService(String serviceName, int servicePort, @NonNull Wai // Ambassador container will be started together after docker compose has started int ambassadorPort = nextAmbassadorPort.getAndIncrement(); - ambassadorPortMappings.computeIfAbsent(serviceInstanceName, __ -> new ConcurrentHashMap<>()).put(servicePort, ambassadorPort); + ambassadorPortMappings + .computeIfAbsent(serviceInstanceName, __ -> new ConcurrentHashMap<>()) + .put(servicePort, ambassadorPort); ambassadorContainer.withTarget(ambassadorPort, serviceInstanceName, servicePort); ambassadorContainer.addLink(new FutureContainer(this.project + "_" + serviceInstanceName), serviceInstanceName); addWaitStrategy(serviceInstanceName, waitStrategy); @@ -405,8 +436,13 @@ private String getServiceInstanceName(String serviceName) { * The WaitAllStrategy uses an long timeout, because timeouts should be handled by the inner strategies. */ private void addWaitStrategy(String serviceInstanceName, @NonNull WaitStrategy waitStrategy) { - final WaitAllStrategy waitAllStrategy = waitStrategyMap.computeIfAbsent(serviceInstanceName, __ -> - new WaitAllStrategy(WaitAllStrategy.Mode.WITH_MAXIMUM_OUTER_TIMEOUT).withStartupTimeout(Duration.ofMinutes(30))); + final WaitAllStrategy waitAllStrategy = waitStrategyMap.computeIfAbsent( + serviceInstanceName, + __ -> { + return new WaitAllStrategy(WaitAllStrategy.Mode.WITH_MAXIMUM_OUTER_TIMEOUT) + .withStartupTimeout(Duration.ofMinutes(30)); + } + ); waitAllStrategy.withStrategy(waitStrategy); } @@ -452,9 +488,17 @@ public Integer getServicePort(String serviceName, Integer servicePort) { Map portMap = ambassadorPortMappings.get(getServiceInstanceName(serviceName)); if (portMap == null) { - throw new IllegalArgumentException("Could not get a port for '" + serviceName + "'. " + - "Testcontainers does not have an exposed port configured for '" + serviceName + "'. " + - "To fix, please ensure that the service '" + serviceName + "' has ports exposed using .withExposedService(...)"); + throw new IllegalArgumentException( + "Could not get a port for '" + + serviceName + + "'. " + + "Testcontainers does not have an exposed port configured for '" + + serviceName + + "'. " + + "To fix, please ensure that the service '" + + serviceName + + "' has ports exposed using .withExposedService(...)" + ); } else { return ambassadorContainer.getMappedPort(portMap.get(servicePort)); } @@ -517,7 +561,8 @@ public SELF withTailChildContainers(boolean tailChildContainers) { */ public SELF withLogConsumer(String serviceName, Consumer consumer) { String serviceInstanceName = getServiceInstanceName(serviceName); - final List> consumers = this.logConsumers.getOrDefault(serviceInstanceName, new ArrayList<>()); + final List> consumers = + this.logConsumers.getOrDefault(serviceInstanceName, new ArrayList<>()); consumers.add(consumer); this.logConsumers.putIfAbsent(serviceInstanceName, consumers); return self(); @@ -609,34 +654,39 @@ interface DockerCompose { class ContainerisedDockerCompose extends GenericContainer implements DockerCompose { public static final char UNIX_PATH_SEPERATOR = ':'; + public static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker/compose:1.29.2"); public ContainerisedDockerCompose(List composeFiles, String identifier) { - super(DEFAULT_IMAGE_NAME); addEnv(ENV_PROJECT_NAME, identifier); // Map the docker compose file into the container final File dockerComposeBaseFile = composeFiles.get(0); final String pwd = dockerComposeBaseFile.getAbsoluteFile().getParentFile().getAbsolutePath(); - final String containerPwd = convertToUnixFilesystemPath(pwd); + final String containerPwd = convertToUnixFilesystemPath(pwd); - final List absoluteDockerComposeFiles = composeFiles.stream() + final List absoluteDockerComposeFiles = composeFiles + .stream() .map(File::getAbsolutePath) .map(MountableFile::forHostPath) .map(MountableFile::getFilesystemPath) .map(this::convertToUnixFilesystemPath) - .collect(toList()); + .collect(Collectors.toList()); final String composeFileEnvVariableValue = Joiner.on(UNIX_PATH_SEPERATOR).join(absoluteDockerComposeFiles); // we always need the UNIX path separator logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); addEnv(ENV_COMPOSE_FILE, composeFileEnvVariableValue); - addFileSystemBind(pwd, containerPwd, READ_WRITE); + addFileSystemBind(pwd, containerPwd, BindMode.READ_WRITE); // Ensure that compose can access docker. Since the container is assumed to be running on the same machine // as the docker daemon, just mapping the docker control socket is OK. // As there seems to be a problem with mapping to the /var/run directory in certain environments (e.g. CircleCI) // we map the socket file outside of /var/run, as just /docker.sock - addFileSystemBind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), "/docker.sock", READ_WRITE); + addFileSystemBind( + DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), + "/docker.sock", + BindMode.READ_WRITE + ); addEnv("DOCKER_HOST", "unix:///docker.sock"); setStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy()); setWorkingDirectory(containerPwd); @@ -649,7 +699,8 @@ public void invoke() { this.followOutput(new Slf4jLogConsumer(logger())); // wait for the compose container to stop, which should only happen after it has spawned all the service containers - logger().info("Docker Compose container is running for command: {}", Joiner.on(" ").join(this.getCommandParts())); + logger() + .info("Docker Compose container is running for command: {}", Joiner.on(" ").join(this.getCommandParts())); while (this.isRunning()) { logger().trace("Compose container is still running"); Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); @@ -658,7 +709,8 @@ public void invoke() { AuditLogger.doComposeLog(this.getCommandParts(), this.getEnv()); - final Integer exitCode = getDockerClient().inspectContainerCmd(getContainerId()) + final Integer exitCode = getDockerClient() + .inspectContainerCmd(getContainerId()) .exec() .getState() .getExitCode(); @@ -668,14 +720,13 @@ public void invoke() { "Containerised Docker Compose exited abnormally with code " + exitCode + " whilst running command: " + - StringUtils.join(this.getCommandParts(), ' ')); + StringUtils.join(this.getCommandParts(), ' ') + ); } } private String convertToUnixFilesystemPath(String path) { - return SystemUtils.IS_OS_WINDOWS - ? PathUtils.createMinGWPath(path).substring(1) - : path; + return SystemUtils.IS_OS_WINDOWS ? PathUtils.createMinGWPath(path).substring(1) : path; } } @@ -683,14 +734,20 @@ private String convertToUnixFilesystemPath(String path) { * Use local Docker Compose binary, if present. */ class LocalDockerCompose implements DockerCompose { + /** * Executable name for Docker Compose. */ - private static final String COMPOSE_EXECUTABLE = SystemUtils.IS_OS_WINDOWS ? "docker-compose.exe" : "docker-compose"; + private static final String COMPOSE_EXECUTABLE = SystemUtils.IS_OS_WINDOWS + ? "docker-compose.exe" + : "docker-compose"; private final List composeFiles; + private final String identifier; + private String cmd = ""; + private Map env = new HashMap<>(); public LocalDockerCompose(List composeFiles, String identifier) { @@ -719,7 +776,9 @@ static boolean executableExists() { public void invoke() { // bail out early if (!executableExists()) { - throw new ContainerLaunchException("Local Docker Compose not found. Is " + COMPOSE_EXECUTABLE + " on the PATH?"); + throw new ContainerLaunchException( + "Local Docker Compose not found. Is " + COMPOSE_EXECUTABLE + " on the PATH?" + ); } final Map environment = Maps.newHashMap(env); @@ -732,18 +791,23 @@ public void invoke() { environment.put("DOCKER_CERT_PATH", ((LocalDirectorySSLConfig) sslConfig).getDockerCertPath()); environment.put("DOCKER_TLS_VERIFY", "true"); } else { - logger().warn("Couldn't set DOCKER_CERT_PATH. `sslConfig` is present but it's not LocalDirectorySSLConfig."); + logger() + .warn( + "Couldn't set DOCKER_CERT_PATH. `sslConfig` is present but it's not LocalDirectorySSLConfig." + ); } } String dockerHost = transportConfig.getDockerHost().toString(); environment.put("DOCKER_HOST", dockerHost); - final Stream absoluteDockerComposeFilePaths = composeFiles.stream() + final Stream absoluteDockerComposeFilePaths = composeFiles + .stream() .map(File::getAbsolutePath) .map(Objects::toString); final String composeFileEnvVariableValue = absoluteDockerComposeFilePaths.collect( - joining(File.pathSeparator + "")); + Collectors.joining(File.pathSeparator + "") + ); logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); final File pwd = composeFiles.get(0).getAbsoluteFile().getParentFile().getAbsoluteFile(); @@ -751,12 +815,14 @@ public void invoke() { logger().info("Local Docker Compose is running command: {}", cmd); - final List command = Splitter.onPattern(" ") + final List command = Splitter + .onPattern(" ") .omitEmptyStrings() .splitToList(COMPOSE_EXECUTABLE + " " + cmd); try { - new ProcessExecutor().command(command) + new ProcessExecutor() + .command(command) .redirectOutput(Slf4jStream.of(logger()).asInfo()) .redirectError(Slf4jStream.of(logger()).asInfo()) // docker-compose will log pull information to stderr .environment(environment) @@ -765,11 +831,13 @@ public void invoke() { .executeNoTimeout(); logger().info("Docker Compose has finished running"); - } catch (InvalidExitValueException e) { - throw new ContainerLaunchException("Local Docker Compose exited abnormally with code " + - e.getExitValue() + " whilst running command: " + cmd); - + throw new ContainerLaunchException( + "Local Docker Compose exited abnormally with code " + + e.getExitValue() + + " whilst running command: " + + cmd + ); } catch (Exception e) { throw new ContainerLaunchException("Error running local Docker Compose command: " + cmd, e); } diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java b/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java index 76754df5118..b96ebfb005e 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java @@ -33,7 +33,9 @@ private Map> mergeServiceDependencyImageNames() { } private Set getImageNames(Map> serviceToImageNames) { - return serviceToImageNames.values().stream() + return serviceToImageNames + .values() + .stream() .flatMap(Collection::stream) // Pass through DockerImageName to convert image names to canonical form (e.g. making implicit latest tag explicit) .map(DockerImageName::parse) diff --git a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java index 0858476880f..fe641618cc4 100644 --- a/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java +++ b/core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java @@ -23,7 +23,6 @@ @Slf4j public class ExecInContainerPattern { - /** * * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, String...)} @@ -40,8 +39,11 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, Charset, String...)} */ @Deprecated - public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, Charset outputCharset, String... command) - throws UnsupportedOperationException, IOException, InterruptedException { + public Container.ExecResult execInContainer( + InspectContainerResponse containerInfo, + Charset outputCharset, + String... command + ) throws UnsupportedOperationException, IOException, InterruptedException { DockerClient dockerClient = DockerClientFactory.instance().client(); return execInContainer(dockerClient, containerInfo, outputCharset, command); } @@ -55,8 +57,11 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn * @param command the command to execute * @see #execInContainer(DockerClient, InspectContainerResponse, Charset, String...) */ - public Container.ExecResult execInContainer(DockerClient dockerClient, InspectContainerResponse containerInfo, String... command) - throws UnsupportedOperationException, IOException, InterruptedException { + public Container.ExecResult execInContainer( + DockerClient dockerClient, + InspectContainerResponse containerInfo, + String... command + ) throws UnsupportedOperationException, IOException, InterruptedException { return execInContainer(dockerClient, containerInfo, StandardCharsets.UTF_8, command); } @@ -74,13 +79,17 @@ public Container.ExecResult execInContainer(DockerClient dockerClient, InspectCo * @throws InterruptedException if the thread waiting for the response is interrupted * @throws UnsupportedOperationException if the docker daemon you're connecting to doesn't support "exec". */ - public Container.ExecResult execInContainer(DockerClient dockerClient, InspectContainerResponse containerInfo, Charset outputCharset, String... command) - throws UnsupportedOperationException, IOException, InterruptedException { + public Container.ExecResult execInContainer( + DockerClient dockerClient, + InspectContainerResponse containerInfo, + Charset outputCharset, + String... command + ) throws UnsupportedOperationException, IOException, InterruptedException { if (!TestEnvironment.dockerExecutionDriverSupportsExec()) { // at time of writing, this is the expected result in CircleCI. throw new UnsupportedOperationException( - "Your docker daemon is running the \"lxc\" driver, which doesn't support \"docker exec\"."); - + "Your docker daemon is running the \"lxc\" driver, which doesn't support \"docker exec\"." + ); } if (!isRunning(containerInfo)) { @@ -91,8 +100,12 @@ public Container.ExecResult execInContainer(DockerClient dockerClient, InspectCo String containerName = containerInfo.getName(); log.debug("{}: Running \"exec\" command: {}", containerName, String.join(" ", command)); - final ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId) - .withAttachStdout(true).withAttachStderr(true).withCmd(command).exec(); + final ExecCreateCmdResponse execCreateCmdResponse = dockerClient + .execCreateCmd(containerId) + .withAttachStdout(true) + .withAttachStderr(true) + .withCmd(command) + .exec(); final ToStringConsumer stdoutConsumer = new ToStringConsumer(); final ToStringConsumer stderrConsumer = new ToStringConsumer(); @@ -108,7 +121,8 @@ public Container.ExecResult execInContainer(DockerClient dockerClient, InspectCo final Container.ExecResult result = new Container.ExecResult( exitCode, stdoutConsumer.toString(outputCharset), - stderrConsumer.toString(outputCharset)); + stderrConsumer.toString(outputCharset) + ); log.trace("{}: stdout: {}", containerName, result.getStdout()); log.trace("{}: stderr: {}", containerName, result.getStderr()); diff --git a/core/src/main/java/org/testcontainers/containers/FailureDetectingExternalResource.java b/core/src/main/java/org/testcontainers/containers/FailureDetectingExternalResource.java index 29a032d320b..71344267d32 100644 --- a/core/src/main/java/org/testcontainers/containers/FailureDetectingExternalResource.java +++ b/core/src/main/java/org/testcontainers/containers/FailureDetectingExternalResource.java @@ -16,13 +16,12 @@ * figures). */ public class FailureDetectingExternalResource implements TestRule { + @Override public Statement apply(Statement base, Description description) { - return new Statement() { @Override public void evaluate() throws Throwable { - List errors = new ArrayList(); try { @@ -41,16 +40,11 @@ public void evaluate() throws Throwable { }; } - protected void starting(Description description) { - - } + protected void starting(Description description) {} - protected void succeeded(Description description) { - } + protected void succeeded(Description description) {} - protected void failed(Throwable e, Description description) { - } + protected void failed(Throwable e, Description description) {} - protected void finished(Description description) { - } + protected void finished(Description description) {} } diff --git a/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java b/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java index 6477c28042e..db610ad57c2 100644 --- a/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/FixedHostPortGenericContainer.java @@ -11,7 +11,8 @@ *

Callers are responsible for ensuring that this fixed port is actually available; failure will occur if it is * not available - which could manifest as flaky or unstable tests.

*/ -public class FixedHostPortGenericContainer> extends GenericContainer { +public class FixedHostPortGenericContainer> + extends GenericContainer { /** * @deprecated it is highly recommended that {@link FixedHostPortGenericContainer} not be used, as it risks port conflicts. @@ -28,7 +29,6 @@ public FixedHostPortGenericContainer(@NotNull String dockerImageName) { * @return this container */ public SELF withFixedExposedPort(int hostPort, int containerPort) { - return withFixedExposedPort(hostPort, containerPort, InternetProtocol.TCP); } @@ -40,7 +40,6 @@ public SELF withFixedExposedPort(int hostPort, int containerPort) { * @return this container */ public SELF withFixedExposedPort(int hostPort, int containerPort, InternetProtocol protocol) { - super.addFixedExposedPort(hostPort, containerPort, protocol); return self(); diff --git a/core/src/main/java/org/testcontainers/containers/FutureContainer.java b/core/src/main/java/org/testcontainers/containers/FutureContainer.java index b2269b534c1..28cfbfff6c9 100644 --- a/core/src/main/java/org/testcontainers/containers/FutureContainer.java +++ b/core/src/main/java/org/testcontainers/containers/FutureContainer.java @@ -8,5 +8,6 @@ */ @Data public class FutureContainer implements LinkableContainer { + private final String containerName; } diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 4e5e682738d..7163ea40a93 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -20,6 +20,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; import com.google.common.hash.Hashing; import lombok.AccessLevel; import lombok.Data; @@ -27,7 +28,6 @@ import lombok.NonNull; import lombok.Setter; import lombok.SneakyThrows; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; @@ -56,6 +56,7 @@ import org.testcontainers.lifecycle.TestDescription; import org.testcontainers.lifecycle.TestLifecycleAware; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.CommandLine; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.DockerLoggerFactory; import org.testcontainers.utility.DockerMachineClient; @@ -66,12 +67,10 @@ import org.testcontainers.utility.TestcontainersConfiguration; import java.io.File; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; import java.nio.charset.Charset; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; @@ -101,17 +100,15 @@ import java.util.zip.Adler32; import java.util.zip.Checksum; -import static com.google.common.collect.Lists.newArrayList; import static org.awaitility.Awaitility.await; -import static org.testcontainers.utility.CommandLine.runShellCommand; /** * Base class for that allows a container to be launched and controlled. */ @Data public class GenericContainer> - extends FailureDetectingExternalResource - implements Container, AutoCloseable, WaitStrategyTarget, Startable { + extends FailureDetectingExternalResource + implements Container, AutoCloseable, WaitStrategyTarget, Startable { private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -142,9 +139,7 @@ public class GenericContainer> private Network network; @NonNull - private List networkAliases = new ArrayList<>(Arrays.asList( - "tc-" + Base58.randomString(8) - )); + private List networkAliases = new ArrayList<>(Arrays.asList("tc-" + Base58.randomString(8))); @NonNull private RemoteDockerImage image; @@ -228,6 +223,7 @@ public class GenericContainer> private final Set> createContainerCmdModifiers = new LinkedHashSet<>(); private static final Set AVAILABLE_IMAGE_NAME_CACHE = new HashSet<>(); + private static final RateLimiter DOCKER_CLIENT_RATE_LIMITER = RateLimiterBuilder .newBuilder() .withRate(1, TimeUnit.SECONDS) @@ -315,7 +311,7 @@ public String getContainerId() { * Starts the container using docker, pulling an image if necessary. */ @Override - @SneakyThrows({InterruptedException.class, ExecutionException.class}) + @SneakyThrows({ InterruptedException.class, ExecutionException.class }) public void start() { if (containerId != null) { return; @@ -335,12 +331,20 @@ protected void doStart() { logger().debug("Starting container: {}", getDockerImageName()); AtomicInteger attempt = new AtomicInteger(0); - Unreliables.retryUntilSuccess(startupAttempts, () -> { - logger().debug("Trying to start container: {} (attempt {}/{})", getDockerImageName(), attempt.incrementAndGet(), startupAttempts); - tryStart(startedAt); - return true; - }); - + Unreliables.retryUntilSuccess( + startupAttempts, + () -> { + logger() + .debug( + "Trying to start container: {} (attempt {}/{})", + getDockerImageName(), + attempt.incrementAndGet(), + startupAttempts + ); + tryStart(startedAt); + return true; + } + ); } catch (Exception e) { throw new ContainerLaunchException("Container startup failed", e); } @@ -383,10 +387,9 @@ private void tryStart(Instant startedAt) { } if (TestcontainersConfiguration.getInstance().environmentSupportsReuse()) { - createCommand.getLabels().put( - COPIED_FILES_HASH_LABEL, - Long.toHexString(hashCopiedFiles().getValue()) - ); + createCommand + .getLabels() + .put(COPIED_FILES_HASH_LABEL, Long.toHexString(hashCopiedFiles().getValue())); String hash = hash(createCommand); @@ -402,12 +405,13 @@ private void tryStart(Instant startedAt) { } reusable = true; } else { - logger().warn( - "" + + logger() + .warn( + "" + "Reuse was requested but the environment does not support the reuse of containers\n" + "To enable reuse of containers, you must set 'testcontainers.reuse.enable=true' in a file located at {}", - Paths.get(System.getProperty("user.home"), ".testcontainers.properties") - ); + Paths.get(System.getProperty("user.home"), ".testcontainers.properties") + ); reusable = false; } } else { @@ -443,27 +447,28 @@ private void tryStart(Instant startedAt) { this.logConsumers.forEach(this::followOutput); // Wait until inspect container returns the mapped ports - containerInfo = await() - .atMost(5, TimeUnit.SECONDS) - .pollInterval(DynamicPollInterval.ofMillis(50)) - .pollInSameThread() - .until( - () -> dockerClient.inspectContainerCmd(containerId).exec(), - inspectContainerResponse -> { - Set exposedAndMappedPorts = inspectContainerResponse - .getNetworkSettings() - .getPorts() - .getBindings() - .entrySet() - .stream() - .filter(it -> Objects.nonNull(it.getValue())) // filter out exposed but not yet mapped - .map(Entry::getKey) - .map(ExposedPort::getPort) - .collect(Collectors.toSet()); - - return exposedAndMappedPorts.containsAll(exposedPorts); - } - ); + containerInfo = + await() + .atMost(5, TimeUnit.SECONDS) + .pollInterval(DynamicPollInterval.ofMillis(50)) + .pollInSameThread() + .until( + () -> dockerClient.inspectContainerCmd(containerId).exec(), + inspectContainerResponse -> { + Set exposedAndMappedPorts = inspectContainerResponse + .getNetworkSettings() + .getPorts() + .getBindings() + .entrySet() + .stream() + .filter(it -> Objects.nonNull(it.getValue())) // filter out exposed but not yet mapped + .map(Entry::getKey) + .map(ExposedPort::getPort) + .collect(Collectors.toSet()); + + return exposedAndMappedPorts.containsAll(exposedPorts); + } + ); // Tell subclasses that we're starting containerIsStarting(containerInfo, reused); @@ -541,9 +546,11 @@ private void tryStart(Instant startedAt) { @VisibleForTesting Checksum hashCopiedFiles() { Checksum checksum = new Adler32(); - Stream.of(copyToFileContainerPathMap, copyToTransferableContainerPathMap) + Stream + .of(copyToFileContainerPathMap, copyToTransferableContainerPathMap) .flatMap(it -> it.entrySet().stream()) - .sorted(Entry.comparingByValue()).forEach(entry -> { + .sorted(Entry.comparingByValue()) + .forEach(entry -> { byte[] pathBytes = entry.getValue().getBytes(); // Add path to the hash checksum.update(pathBytes, 0, pathBytes.length); @@ -558,7 +565,8 @@ Checksum hashCopiedFiles() { final String hash(CreateContainerCmd createCommand) { DefaultDockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); - byte[] commandJson = dockerClientConfig.getObjectMapper() + byte[] commandJson = dockerClientConfig + .getObjectMapper() .copy() .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY) .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) @@ -571,7 +579,8 @@ final String hash(CreateContainerCmd createCommand) { @VisibleForTesting Optional findContainerForReuse(String hash) { // TODO locking - return dockerClient.listContainersCmd() + return dockerClient + .listContainersCmd() .withLabelFilter(ImmutableMap.of(HASH_LABEL, hash)) .withLimit(1) .withStatusFilter(Arrays.asList("running")) @@ -596,11 +605,14 @@ private HostConfig buildHostConfig() { } private void connectToPortForwardingNetwork(String networkMode) { - PortForwardingContainer.INSTANCE.getNetwork().map(ContainerNetwork::getNetworkID).ifPresent(networkId -> { - if (!Arrays.asList(networkId, "none", "host").contains(networkMode)) { - dockerClient.connectToNetworkCmd().withContainerId(containerId).withNetworkId(networkId).exec(); - } - }); + PortForwardingContainer.INSTANCE + .getNetwork() + .map(ContainerNetwork::getNetworkID) + .ifPresent(networkId -> { + if (!Arrays.asList(networkId, "none", "host").contains(networkMode)) { + dockerClient.connectToNetworkCmd().withContainerId(containerId).withNetworkId(networkId).exec(); + } + }); } /** @@ -608,7 +620,6 @@ private void connectToPortForwardingNetwork(String networkMode) { */ @Override public void stop() { - if (containerId == null) { return; } @@ -651,35 +662,40 @@ protected Path createVolumeDirectory(boolean temporary) { Path directory = new File(".tmp-volume-" + UUID.randomUUID()).toPath(); PathUtils.mkdirp(directory); - if (temporary) Runtime.getRuntime().addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { - PathUtils.recursiveDeleteDir(directory); - })); + if (temporary) { + Runtime + .getRuntime() + .addShutdownHook( + new Thread( + DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, + () -> { + PathUtils.recursiveDeleteDir(directory); + } + ) + ); + } return directory; } - protected void configure() { - } + protected void configure() {} - @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) - protected void containerIsCreated(String containerId) { - } + @SuppressWarnings({ "EmptyMethod", "UnusedParameters" }) + protected void containerIsCreated(String containerId) {} - @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) - protected void containerIsStarting(InspectContainerResponse containerInfo) { - } + @SuppressWarnings({ "EmptyMethod", "UnusedParameters" }) + protected void containerIsStarting(InspectContainerResponse containerInfo) {} - @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) + @SuppressWarnings({ "EmptyMethod", "UnusedParameters" }) @UnstableAPI protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { containerIsStarting(containerInfo); } - @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) - protected void containerIsStarted(InspectContainerResponse containerInfo) { - } + @SuppressWarnings({ "EmptyMethod", "UnusedParameters" }) + protected void containerIsStarted(InspectContainerResponse containerInfo) {} - @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) + @SuppressWarnings({ "EmptyMethod", "UnusedParameters" }) @UnstableAPI protected void containerIsStarted(InspectContainerResponse containerInfo, boolean reused) { containerIsStarted(containerInfo); @@ -690,18 +706,16 @@ protected void containerIsStarted(InspectContainerResponse containerInfo, boolea * Warning! This hook won't be executed if the container is terminated during * the JVM's shutdown hook or by Ryuk. */ - @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) - protected void containerIsStopping(InspectContainerResponse containerInfo) { - } + @SuppressWarnings({ "EmptyMethod", "UnusedParameters" }) + protected void containerIsStopping(InspectContainerResponse containerInfo) {} /** * A hook that is executed after the container is stopped with {@link #stop()}. * Warning! This hook won't be executed if the container is terminated during * the JVM's shutdown hook or by Ryuk. */ - @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) - protected void containerIsStopped(InspectContainerResponse containerInfo) { - } + @SuppressWarnings({ "EmptyMethod", "UnusedParameters" }) + protected void containerIsStopped(InspectContainerResponse containerInfo) {} /** * @return the port on which to check if the container is ready @@ -772,35 +786,36 @@ private void applyConfiguration(CreateContainerCmd createCommand) { createCommand.withCmd(commandParts); } - String[] envArray = env.entrySet().stream() - .filter(it -> it.getValue() != null) - .map(it -> it.getKey() + "=" + it.getValue()) - .toArray(String[]::new); + String[] envArray = env + .entrySet() + .stream() + .filter(it -> it.getValue() != null) + .map(it -> it.getKey() + "=" + it.getValue()) + .toArray(String[]::new); createCommand.withEnv(envArray); - boolean shouldCheckFileMountingSupport = binds.size() > 0 && !TestcontainersConfiguration.getInstance().isDisableChecks(); + boolean shouldCheckFileMountingSupport = + binds.size() > 0 && !TestcontainersConfiguration.getInstance().isDisableChecks(); if (shouldCheckFileMountingSupport) { if (!DockerClientFactory.instance().isFileMountingSupported()) { - logger().warn( - "Unable to mount a file from test host into a running container. " + + logger() + .warn( + "Unable to mount a file from test host into a running container. " + "This may be a misconfiguration or limitation of your Docker environment. " + "Some features might not work." - ); + ); } } - Bind[] bindsArray = binds.stream() - .toArray(Bind[]::new); + Bind[] bindsArray = binds.stream().toArray(Bind[]::new); createCommand.withBinds(bindsArray); - VolumesFrom[] volumesFromsArray = volumesFroms.stream() - .toArray(VolumesFrom[]::new); + VolumesFrom[] volumesFromsArray = volumesFroms.stream().toArray(VolumesFrom[]::new); createCommand.withVolumesFrom(volumesFromsArray); Set allLinks = new HashSet<>(); Set allLinkedContainerNetworks = new HashSet<>(); for (Entry linkEntries : linkedContainers.entrySet()) { - String alias = linkEntries.getKey(); LinkableContainer linkableContainer = linkEntries.getValue(); @@ -808,9 +823,11 @@ private void applyConfiguration(CreateContainerCmd createCommand) { allLinks.addAll(links); if (allLinks.size() == 0) { - throw new ContainerLaunchException("Aborting attempt to link to container " + - linkableContainer.getContainerName() + - " as it is not running"); + throw new ContainerLaunchException( + "Aborting attempt to link to container " + + linkableContainer.getContainerName() + + " as it is not running" + ); } Set linkedContainerNetworks = findAllNetworksForLinkedContainers(linkableContainer); @@ -821,9 +838,12 @@ private void applyConfiguration(CreateContainerCmd createCommand) { allLinkedContainerNetworks.remove("bridge"); if (allLinkedContainerNetworks.size() > 1) { - logger().warn("Container needs to be on more than one custom network to link to other " + - "containers - this is not currently supported. Required networks are: {}", - allLinkedContainerNetworks); + logger() + .warn( + "Container needs to be on more than one custom network to link to other " + + "containers - this is not currently supported. Required networks are: {}", + allLinkedContainerNetworks + ); } Optional networkForLinks = allLinkedContainerNetworks.stream().findFirst(); @@ -835,12 +855,13 @@ private void applyConfiguration(CreateContainerCmd createCommand) { if (hostAccessible) { PortForwardingContainer.INSTANCE.start(); } - PortForwardingContainer.INSTANCE.getNetwork().ifPresent(it -> { - withExtraHost(INTERNAL_HOST_HOSTNAME, it.getIpAddress()); - }); + PortForwardingContainer.INSTANCE + .getNetwork() + .ifPresent(it -> { + withExtraHost(INTERNAL_HOST_HOSTNAME, it.getIpAddress()); + }); - String[] extraHostsArray = extraHosts.stream() - .toArray(String[]::new); + String[] extraHostsArray = extraHosts.stream().toArray(String[]::new); createCommand.withExtraHosts(extraHostsArray); if (network != null) { @@ -870,23 +891,29 @@ private void applyConfiguration(CreateContainerCmd createCommand) { } private Set findLinksFromThisContainer(String alias, LinkableContainer linkableContainer) { - return dockerClient.listContainersCmd() - .withStatusFilter(Arrays.asList("running")) - .exec().stream() - .flatMap(container -> Stream.of(container.getNames())) - .filter(name -> name.endsWith(linkableContainer.getContainerName())) - .map(name -> new Link(name, alias)) - .collect(Collectors.toSet()); + return dockerClient + .listContainersCmd() + .withStatusFilter(Arrays.asList("running")) + .exec() + .stream() + .flatMap(container -> Stream.of(container.getNames())) + .filter(name -> name.endsWith(linkableContainer.getContainerName())) + .map(name -> new Link(name, alias)) + .collect(Collectors.toSet()); } private Set findAllNetworksForLinkedContainers(LinkableContainer linkableContainer) { - return dockerClient.listContainersCmd().exec().stream() - .filter(container -> container.getNames()[0].endsWith(linkableContainer.getContainerName())) - .filter(container -> container.getNetworkSettings() != null && - container.getNetworkSettings().getNetworks() != null) - .flatMap(container -> container.getNetworkSettings().getNetworks().keySet().stream()) - .distinct() - .collect(Collectors.toSet()); + return dockerClient + .listContainersCmd() + .exec() + .stream() + .filter(container -> container.getNames()[0].endsWith(linkableContainer.getContainerName())) + .filter(container -> { + return container.getNetworkSettings() != null && container.getNetworkSettings().getNetworks() != null; + }) + .flatMap(container -> container.getNetworkSettings().getNetworks().keySet().stream()) + .distinct() + .collect(Collectors.toSet()); } /** @@ -953,19 +980,12 @@ public Map getEnvMap() { */ @Override public List getEnv() { - return env.entrySet().stream() - .map(it -> it.getKey() + "=" + it.getValue()) - .collect(Collectors.toList()); + return env.entrySet().stream().map(it -> it.getKey() + "=" + it.getValue()).collect(Collectors.toList()); } @Override public void setEnv(List env) { - this.env = env.stream() - .map(it -> it.split("=")) - .collect(Collectors.toMap( - it -> it[0], - it -> it[1] - )); + this.env = env.stream().map(it -> it.split("=")).collect(Collectors.toMap(it -> it[0], it -> it[1])); } /** @@ -980,14 +1000,25 @@ public void addEnv(String key, String value) { * {@inheritDoc} */ @Override - public void addFileSystemBind(final String hostPath, final String containerPath, final BindMode mode, final SelinuxContext selinuxContext) { + public void addFileSystemBind( + final String hostPath, + final String containerPath, + final BindMode mode, + final SelinuxContext selinuxContext + ) { if (SystemUtils.IS_OS_WINDOWS && hostPath.startsWith("/")) { // e.g. Docker socket mount binds.add(new Bind(hostPath, new Volume(containerPath), mode.accessMode, selinuxContext.selContext)); - } else { final MountableFile mountableFile = MountableFile.forHostPath(hostPath); - binds.add(new Bind(mountableFile.getResolvedPath(), new Volume(containerPath), mode.accessMode, selinuxContext.selContext)); + binds.add( + new Bind( + mountableFile.getResolvedPath(), + new Volume(containerPath), + mode.accessMode, + selinuxContext.selContext + ) + ); } } @@ -1090,9 +1121,8 @@ protected void finished(Description description) { */ @Override public SELF withExposedPorts(Integer... ports) { - this.setExposedPorts(newArrayList(ports)); + this.setExposedPorts(Lists.newArrayList(ports)); return self(); - } /** @@ -1218,7 +1248,11 @@ public SELF withImagePullPolicy(ImagePullPolicy imagePullPolicy) { * {@inheritDoc} */ @Override - public SELF withClasspathResourceMapping(final String resourcePath, final String containerPath, final BindMode mode) { + public SELF withClasspathResourceMapping( + final String resourcePath, + final String containerPath, + final BindMode mode + ) { return withClasspathResourceMapping(resourcePath, containerPath, mode, SelinuxContext.NONE); } @@ -1226,7 +1260,12 @@ public SELF withClasspathResourceMapping(final String resourcePath, final String * {@inheritDoc} */ @Override - public SELF withClasspathResourceMapping(final String resourcePath, final String containerPath, final BindMode mode, final SelinuxContext selinuxContext) { + public SELF withClasspathResourceMapping( + final String resourcePath, + final String containerPath, + final BindMode mode, + final SelinuxContext selinuxContext + ) { final MountableFile mountableFile = MountableFile.forClasspathResource(resourcePath); if (mode == BindMode.READ_ONLY && selinuxContext == SelinuxContext.NONE) { @@ -1346,23 +1385,33 @@ public String getTestHostIpAddress() { throw new IllegalStateException("Could not find a default docker-machine instance"); } - String sshConnectionString = runShellCommand("docker-machine", "ssh", defaultMachine.get(), "echo $SSH_CONNECTION").trim(); + String sshConnectionString = CommandLine + .runShellCommand("docker-machine", "ssh", defaultMachine.get(), "echo $SSH_CONNECTION") + .trim(); if (Strings.isNullOrEmpty(sshConnectionString)) { - throw new IllegalStateException("Could not obtain SSH_CONNECTION environment variable for docker machine " + defaultMachine.get()); + throw new IllegalStateException( + "Could not obtain SSH_CONNECTION environment variable for docker machine " + + defaultMachine.get() + ); } String[] sshConnectionParts = sshConnectionString.split("\\s"); if (sshConnectionParts.length != 4) { - throw new IllegalStateException("Unexpected pattern for SSH_CONNECTION for docker machine - expected 'IP PORT IP PORT' pattern but found '" + sshConnectionString + "'"); + throw new IllegalStateException( + "Unexpected pattern for SSH_CONNECTION for docker machine - expected 'IP PORT IP PORT' pattern but found '" + + sshConnectionString + + "'" + ); } return sshConnectionParts[0]; } catch (Exception e) { throw new RuntimeException(e); } - } else { - throw new UnsupportedOperationException("getTestHostIpAddress() is only implemented for docker-machine right now"); + throw new UnsupportedOperationException( + "getTestHostIpAddress() is only implemented for docker-machine right now" + ); } } diff --git a/core/src/main/java/org/testcontainers/containers/InternetProtocol.java b/core/src/main/java/org/testcontainers/containers/InternetProtocol.java index 0df0480a1bf..6574a517cdf 100644 --- a/core/src/main/java/org/testcontainers/containers/InternetProtocol.java +++ b/core/src/main/java/org/testcontainers/containers/InternetProtocol.java @@ -4,7 +4,6 @@ * The IP protocols supported by Docker. */ public enum InternetProtocol { - TCP, UDP; diff --git a/core/src/main/java/org/testcontainers/containers/Network.java b/core/src/main/java/org/testcontainers/containers/Network.java index 046133815b6..fac7beff638 100644 --- a/core/src/main/java/org/testcontainers/containers/Network.java +++ b/core/src/main/java/org/testcontainers/containers/Network.java @@ -18,7 +18,6 @@ import java.util.function.Consumer; public interface Network extends AutoCloseable, TestRule { - Network SHARED = new NetworkImpl(false, null, Collections.emptySet(), null) { @Override public void close() { diff --git a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java index e9457ba92bd..abb6deaab3d 100644 --- a/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java +++ b/core/src/main/java/org/testcontainers/containers/ParsedDockerComposeFile.java @@ -26,7 +26,9 @@ class ParsedDockerComposeFile { private final Map composeFileContent; + private final String composeFileName; + private final File composeFile; @Getter @@ -57,14 +59,20 @@ private void parseAndValidate() { final Map servicesMap; if (composeFileContent.containsKey("version")) { if ("2.0".equals(composeFileContent.get("version"))) { - log.warn("Testcontainers may not be able to clean up networks spawned using Docker Compose v2.0 files. " + + log.warn( + "Testcontainers may not be able to clean up networks spawned using Docker Compose v2.0 files. " + "Please see https://github.com/testcontainers/moby-ryuk/issues/2, and specify 'version: \"2.1\"' or " + - "higher in {}", composeFileName); + "higher in {}", + composeFileName + ); } final Object servicesElement = composeFileContent.get("services"); if (servicesElement == null) { - log.debug("Compose file {} has an unknown format: 'version' is set but 'services' is not defined", composeFileName); + log.debug( + "Compose file {} has an unknown format: 'version' is set but 'services' is not defined", + composeFileName + ); return; } if (!(servicesElement instanceof Map)) { @@ -81,7 +89,11 @@ private void parseAndValidate() { String serviceName = entry.getKey(); Object serviceDefinition = entry.getValue(); if (!(serviceDefinition instanceof Map)) { - log.debug("Compose file {} has an unknown format: service '{}' is not Map", composeFileName, serviceName); + log.debug( + "Compose file {} has an unknown format: service '{}' is not Map", + composeFileName, + serviceName + ); break; } @@ -95,11 +107,13 @@ private void parseAndValidate() { private void validateNoContainerNameSpecified(String serviceName, Map serviceDefinitionMap) { if (serviceDefinitionMap.containsKey("container_name")) { - throw new IllegalStateException(String.format( - "Compose file %s has 'container_name' property set for service '%s' but this property is not supported by Testcontainers, consider removing it", - composeFileName, - serviceName - )); + throw new IllegalStateException( + String.format( + "Compose file %s has 'container_name' property set for service '%s' but this property is not supported by Testcontainers, consider removing it", + composeFileName, + serviceName + ) + ); } } @@ -120,28 +134,35 @@ private void findImageNamesInDockerfile(String serviceName, Map serviceDefinitio final Object dockerfileRelativePath = buildElement.get("dockerfile"); final Object contextRelativePath = buildElement.get("context"); if (dockerfileRelativePath instanceof String && contextRelativePath instanceof String) { - dockerfilePath = composeFile + dockerfilePath = + composeFile + .getAbsoluteFile() + .getParentFile() + .toPath() + .resolve((String) contextRelativePath) + .resolve((String) dockerfileRelativePath) + .normalize(); + } + } else if (buildNode instanceof String) { + dockerfilePath = + composeFile .getAbsoluteFile() .getParentFile() .toPath() - .resolve((String) contextRelativePath) - .resolve((String) dockerfileRelativePath) + .resolve((String) buildNode) + .resolve("./Dockerfile") .normalize(); - } - } else if (buildNode instanceof String) { - dockerfilePath = composeFile - .getAbsoluteFile() - .getParentFile() - .toPath() - .resolve((String) buildNode) - .resolve("./Dockerfile") - .normalize(); } if (dockerfilePath != null && Files.exists(dockerfilePath)) { Set resolvedImageNames = new ParsedDockerfile(dockerfilePath).getDependencyImageNames(); if (!resolvedImageNames.isEmpty()) { - log.debug("Resolved Dockerfile dependency images for Docker Compose in {} -> {}: {}", composeFileName, dockerfilePath, resolvedImageNames); + log.debug( + "Resolved Dockerfile dependency images for Docker Compose in {} -> {}: {}", + composeFileName, + dockerfilePath, + resolvedImageNames + ); this.serviceNameToImageNames.put(serviceName, resolvedImageNames); } } diff --git a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java index a854b1e55c3..22d364c0762 100644 --- a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java @@ -30,15 +30,16 @@ public enum PortForwardingContainer { @SneakyThrows private Connection createSSHSession() { String password = UUID.randomUUID().toString(); - container = new GenericContainer<>(DockerImageName.parse("testcontainers/sshd:1.0.0")) - .withExposedPorts(22) - .withEnv("PASSWORD", password) - .withCommand( - "sh", - "-c", - // Disable ipv6 & Make it listen on all interfaces, not just localhost - "echo \"root:$PASSWORD\" | chpasswd && /usr/sbin/sshd -D -o PermitRootLogin=yes -o AddressFamily=inet -o GatewayPorts=yes" - ); + container = + new GenericContainer<>(DockerImageName.parse("testcontainers/sshd:1.0.0")) + .withExposedPorts(22) + .withEnv("PASSWORD", password) + .withCommand( + "sh", + "-c", + // Disable ipv6 & Make it listen on all interfaces, not just localhost + "echo \"root:$PASSWORD\" | chpasswd && /usr/sbin/sshd -D -o PermitRootLogin=yes -o AddressFamily=inet -o GatewayPorts=yes" + ); container.start(); Connection connection = new Connection(container.getHost(), container.getMappedPort(22)); @@ -64,7 +65,7 @@ public void exposeHostPort(int port) { @SneakyThrows public void exposeHostPort(int hostPort, int containerPort) { - if (exposedPorts.add(new AbstractMap.SimpleEntry<>(hostPort, containerPort))) { + if (exposedPorts.add(new AbstractMap.SimpleEntry<>(hostPort, containerPort))) { getSshConnection().requestRemotePortForwarding("", containerPort, "localhost", hostPort); } } @@ -74,7 +75,8 @@ void start() { } Optional getNetwork() { - return Optional.ofNullable(container) + return Optional + .ofNullable(container) .map(GenericContainer::getContainerInfo) .flatMap(it -> it.getNetworkSettings().getNetworks().values().stream().findFirst()); } diff --git a/core/src/main/java/org/testcontainers/containers/SelinuxContext.java b/core/src/main/java/org/testcontainers/containers/SelinuxContext.java index 735d3e3a277..ec814d5640a 100644 --- a/core/src/main/java/org/testcontainers/containers/SelinuxContext.java +++ b/core/src/main/java/org/testcontainers/containers/SelinuxContext.java @@ -13,5 +13,4 @@ public enum SelinuxContext { NONE(SELContext.none); public final SELContext selContext; - } diff --git a/core/src/main/java/org/testcontainers/containers/SocatContainer.java b/core/src/main/java/org/testcontainers/containers/SocatContainer.java index bc9ced57845..9455ac77227 100644 --- a/core/src/main/java/org/testcontainers/containers/SocatContainer.java +++ b/core/src/main/java/org/testcontainers/containers/SocatContainer.java @@ -1,10 +1,11 @@ package org.testcontainers.containers; +import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; + import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -import org.testcontainers.utility.Base58; -import org.testcontainers.utility.DockerImageName; /** * A socat container is used as a TCP proxy, enabling any TCP port of another container to be exposed @@ -36,10 +37,13 @@ public SocatContainer withTarget(int exposedPort, String host, int internalPort) @Override protected void configure() { - withCommand("-c", - targets.entrySet().stream() - .map(entry -> "socat TCP-LISTEN:" + entry.getKey() + ",fork,reuseaddr TCP:" + entry.getValue()) - .collect(Collectors.joining(" & ")) + withCommand( + "-c", + targets + .entrySet() + .stream() + .map(entry -> "socat TCP-LISTEN:" + entry.getKey() + ",fork,reuseaddr TCP:" + entry.getValue()) + .collect(Collectors.joining(" & ")) ); } } diff --git a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java index be8a4ed735f..f629a141357 100644 --- a/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/VncRecordingContainer.java @@ -15,10 +15,9 @@ import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.Base64; -import static java.time.temporal.ChronoUnit.SECONDS; - /** * 'Sidekick container' with the sole purpose of recording the VNC screen output from another container. * @@ -48,7 +47,9 @@ public class VncRecordingContainer extends GenericContainer targetContainer) { this( targetContainer.getNetwork(), - targetContainer.getNetworkAliases().stream() + targetContainer + .getNetworkAliases() + .stream() .findFirst() .orElseThrow(() -> new IllegalStateException("Target container must have a network alias")) ); @@ -57,14 +58,16 @@ public VncRecordingContainer(@NonNull GenericContainer targetContainer) { /** * Create a sidekick container and attach it to another container. The VNC output of that container will be recorded. */ - public VncRecordingContainer(@NonNull Network network, @NonNull String targetNetworkAlias) throws IllegalStateException { + public VncRecordingContainer(@NonNull Network network, @NonNull String targetNetworkAlias) + throws IllegalStateException { super(DockerImageName.parse("testcontainers/vnc-recorder:1.2.0")); - this.targetNetworkAlias = targetNetworkAlias; withNetwork(network); - waitingFor(new LogMessageWaitStrategy() - .withRegEx(".*Connected.*") - .withStartupTimeout(Duration.of(15, SECONDS))); + waitingFor( + new LogMessageWaitStrategy() + .withRegEx(".*Connected.*") + .withStartupTimeout(Duration.of(15, ChronoUnit.SECONDS)) + ); } public VncRecordingContainer withVncPassword(@NonNull String vncPassword) { @@ -95,8 +98,17 @@ protected void configure() { String encodedPassword = Base64.getEncoder().encodeToString(vncPassword.getBytes()); setCommand( "-c", - "echo '" + encodedPassword + "' | base64 -d > /vnc_password && " + - "flvrec.py -o " + ORIGINAL_RECORDING_FILE_NAME + " -d -r " + frameRate + " -P /vnc_password " + targetNetworkAlias + " " + vncPort + "echo '" + + encodedPassword + + "' | base64 -d > /vnc_password && " + + "flvrec.py -o " + + ORIGINAL_RECORDING_FILE_NAME + + " -d -r " + + frameRate + + " -P /vnc_password " + + targetNetworkAlias + + " " + + vncPort ); } @@ -122,7 +134,8 @@ public void saveRecordingToFile(@NonNull File file) { public enum VncRecordingFormat { FLV("flv") { @Override - String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull String source) throws IOException, InterruptedException { + String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull String source) + throws IOException, InterruptedException { String newFileOutput = "/newScreen.flv"; container.execInContainer("ffmpeg", "-i", source, "-vcodec", "libx264", newFileOutput); return newFileOutput; @@ -130,17 +143,29 @@ String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull Stri }, MP4("mp4") { @Override - String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull String source) throws IOException, InterruptedException { + String reencodeRecording(@NonNull VncRecordingContainer container, @NonNull String source) + throws IOException, InterruptedException { String newFileOutput = "/newScreen.mp4"; - container.execInContainer("ffmpeg", "-i", source, "-vcodec", "libx264", "-movflags", "faststart", "-pix_fmt", "yuv420p", newFileOutput); + container.execInContainer( + "ffmpeg", + "-i", + source, + "-vcodec", + "libx264", + "-movflags", + "faststart", + "-pix_fmt", + "yuv420p", + newFileOutput + ); return newFileOutput; } }; - abstract String reencodeRecording(VncRecordingContainer container, String source) throws IOException, InterruptedException; + abstract String reencodeRecording(VncRecordingContainer container, String source) + throws IOException, InterruptedException; @Getter private final String filenameExtension; } - } diff --git a/core/src/main/java/org/testcontainers/containers/output/BaseConsumer.java b/core/src/main/java/org/testcontainers/containers/output/BaseConsumer.java index 2967eb4d33a..7679ee8ab57 100644 --- a/core/src/main/java/org/testcontainers/containers/output/BaseConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/BaseConsumer.java @@ -6,6 +6,7 @@ import java.util.function.Consumer; public abstract class BaseConsumer> implements Consumer { + @Getter @Setter private boolean removeColorCodes = true; diff --git a/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java b/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java index 8c7480320a8..75c24d1ac1d 100644 --- a/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java +++ b/core/src/main/java/org/testcontainers/containers/output/FrameConsumerResultCallback.java @@ -1,6 +1,5 @@ package org.testcontainers.containers.output; - import com.github.dockerjava.api.async.ResultCallbackTemplate; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.StreamType; @@ -79,7 +78,7 @@ public void onError(Throwable throwable) { // Sink any errors try { close(); - } catch (IOException ignored) { } + } catch (IOException ignored) {} } @Override @@ -169,7 +168,6 @@ private String processAnsiColorCodes(String utf8String, Consumer co return utf8String; } - private byte[] merge(byte[] str1, byte[] str2) { byte[] mergedString = new byte[str1.length + str2.length]; System.arraycopy(str1, 0, mergedString, 0, str1.length); diff --git a/core/src/main/java/org/testcontainers/containers/output/OutputFrame.java b/core/src/main/java/org/testcontainers/containers/output/OutputFrame.java index d5ddcada8c8..f6eb5c18cbc 100644 --- a/core/src/main/java/org/testcontainers/containers/output/OutputFrame.java +++ b/core/src/main/java/org/testcontainers/containers/output/OutputFrame.java @@ -12,6 +12,7 @@ public class OutputFrame { public static final OutputFrame END = new OutputFrame(OutputType.END, null); private final OutputType type; + private final byte[] bytes; public OutputFrame(OutputType type, byte[] bytes) { @@ -28,7 +29,6 @@ public byte[] getBytes() { } public String getUtf8String() { - if (bytes == null) { return ""; } @@ -37,14 +37,20 @@ public String getUtf8String() { } public enum OutputType { - STDOUT, STDERR, END; + STDOUT, + STDERR, + END; public static OutputType forStreamType(StreamType streamType) { switch (streamType) { - case RAW: return STDOUT; - case STDOUT: return STDOUT; - case STDERR: return STDERR; - default: return null; + case RAW: + return STDOUT; + case STDOUT: + return STDOUT; + case STDERR: + return STDERR; + default: + return null; } } } @@ -56,5 +62,4 @@ public static OutputFrame forFrame(Frame frame) { } return new OutputFrame(outputType, frame.getPayload()); } - } diff --git a/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java b/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java index a274cd63004..ece7ab0e5b7 100644 --- a/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/Slf4jLogConsumer.java @@ -1,18 +1,22 @@ package org.testcontainers.containers.output; -import java.util.HashMap; -import java.util.Map; - import org.slf4j.Logger; import org.slf4j.MDC; +import java.util.HashMap; +import java.util.Map; + /** * A consumer for container output that logs output to an SLF4J logger. */ public class Slf4jLogConsumer extends BaseConsumer { + private final Logger logger; + private final Map mdc = new HashMap<>(); + private boolean separateOutputStreams; + private String prefix = ""; public Slf4jLogConsumer(Logger logger) { diff --git a/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java b/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java index 40ec60fb744..444434fa702 100644 --- a/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/ToStringConsumer.java @@ -10,6 +10,7 @@ * Created by rnorth on 26/03/2016. */ public class ToStringConsumer extends BaseConsumer { + private ByteArrayOutputStream stringBuffer = new ByteArrayOutputStream(); @Override diff --git a/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java b/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java index 858f5a4b487..e9b34692319 100644 --- a/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java @@ -71,14 +71,14 @@ public void waitUntil(Predicate predicate, int limit, TimeUnit limi * @param limitUnit maximum time to wait (units) * @param times number of times the predicate has to match */ - public void waitUntil(Predicate predicate, long limit, TimeUnit limitUnit, int times) throws TimeoutException { + public void waitUntil(Predicate predicate, long limit, TimeUnit limitUnit, int times) + throws TimeoutException { long expiry = limitUnit.toMillis(limit) + System.currentTimeMillis(); waitUntil(predicate, expiry, times); } private void waitUntil(Predicate predicate, long expiry, int times) throws TimeoutException { - int numberOfMatches = 0; while (System.currentTimeMillis() < expiry) { try { diff --git a/core/src/main/java/org/testcontainers/containers/startupcheck/IndefiniteWaitOneShotStartupCheckStrategy.java b/core/src/main/java/org/testcontainers/containers/startupcheck/IndefiniteWaitOneShotStartupCheckStrategy.java index f719cb1d476..a547b7885e3 100644 --- a/core/src/main/java/org/testcontainers/containers/startupcheck/IndefiniteWaitOneShotStartupCheckStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/startupcheck/IndefiniteWaitOneShotStartupCheckStrategy.java @@ -12,6 +12,7 @@ * It has to be assumed that the container will stop of its own accord, either with a success or failure exit code. */ public class IndefiniteWaitOneShotStartupCheckStrategy extends OneShotStartupCheckStrategy { + @Override public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { while (checkStartupState(dockerClient, containerId) == StartupStatus.NOT_YET_KNOWN) { diff --git a/core/src/main/java/org/testcontainers/containers/startupcheck/MinimumDurationRunningStartupCheckStrategy.java b/core/src/main/java/org/testcontainers/containers/startupcheck/MinimumDurationRunningStartupCheckStrategy.java index 3ce50446b77..ce29e0104e1 100644 --- a/core/src/main/java/org/testcontainers/containers/startupcheck/MinimumDurationRunningStartupCheckStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/startupcheck/MinimumDurationRunningStartupCheckStrategy.java @@ -35,5 +35,4 @@ public StartupStatus checkStartupState(DockerClient dockerClient, String contain } return StartupStatus.NOT_YET_KNOWN; } - } diff --git a/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java b/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java index d5931454212..50fdcdb8b9b 100644 --- a/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java @@ -10,20 +10,18 @@ import java.time.Duration; import java.util.concurrent.TimeUnit; -import static org.testcontainers.containers.GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC; - /** * Approach to determine whether a container has 'started up' correctly. */ public abstract class StartupCheckStrategy { private static final RateLimiter DOCKER_CLIENT_RATE_LIMITER = RateLimiterBuilder - .newBuilder() - .withRate(1, TimeUnit.SECONDS) - .withConstantThroughput() - .build(); + .newBuilder() + .withRate(1, TimeUnit.SECONDS) + .withConstantThroughput() + .build(); - private Duration timeout = Duration.ofSeconds(CONTAINER_RUNNING_TIMEOUT_SEC); + private Duration timeout = Duration.ofSeconds(GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC); @SuppressWarnings("unchecked") public SELF withTimeout(Duration timeout) { @@ -41,20 +39,27 @@ public boolean waitUntilStartupSuccessful(GenericContainer container) { } public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { - final Boolean[] startedOK = {null}; - Unreliables.retryUntilTrue((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> { - //noinspection CodeBlock2Expr - return DOCKER_CLIENT_RATE_LIMITER.getWhenReady(() -> { - StartupStatus state = checkStartupState(dockerClient, containerId); - switch (state) { - case SUCCESSFUL: startedOK[0] = true; - return true; - case FAILED: startedOK[0] = false; - return true; - default: return false; - } - }); - }); + final Boolean[] startedOK = { null }; + Unreliables.retryUntilTrue( + (int) timeout.toMillis(), + TimeUnit.MILLISECONDS, + () -> { + //noinspection CodeBlock2Expr + return DOCKER_CLIENT_RATE_LIMITER.getWhenReady(() -> { + StartupStatus state = checkStartupState(dockerClient, containerId); + switch (state) { + case SUCCESSFUL: + startedOK[0] = true; + return true; + case FAILED: + startedOK[0] = false; + return true; + default: + return false; + } + }); + } + ); return startedOK[0]; } @@ -65,6 +70,8 @@ protected InspectContainerResponse.ContainerState getCurrentState(DockerClient d } public enum StartupStatus { - NOT_YET_KNOWN, SUCCESSFUL, FAILED + NOT_YET_KNOWN, + SUCCESSFUL, + FAILED, } } diff --git a/core/src/main/java/org/testcontainers/containers/traits/LinkableContainer.java b/core/src/main/java/org/testcontainers/containers/traits/LinkableContainer.java index 76e71378969..4973c4dc9c1 100644 --- a/core/src/main/java/org/testcontainers/containers/traits/LinkableContainer.java +++ b/core/src/main/java/org/testcontainers/containers/traits/LinkableContainer.java @@ -7,6 +7,5 @@ */ @Deprecated public interface LinkableContainer { - String getContainerName(); } diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java index d543d952bbd..fbee9c2f9f4 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheck.java @@ -14,21 +14,25 @@ */ @RequiredArgsConstructor public class ExternalPortListeningCheck implements Callable { + private final ContainerState containerState; + private final Set externalLivenessCheckPorts; @Override public Boolean call() { String address = containerState.getHost(); - externalLivenessCheckPorts.parallelStream().forEach(externalPort -> { - try (Socket socket = new Socket()) { - InetSocketAddress inetSocketAddress = new InetSocketAddress(address, externalPort); - socket.connect(inetSocketAddress, 1000); - } catch (IOException e) { - throw new IllegalStateException("Socket not listening yet: " + externalPort); - } - }); + externalLivenessCheckPorts + .parallelStream() + .forEach(externalPort -> { + try (Socket socket = new Socket()) { + InetSocketAddress inetSocketAddress = new InetSocketAddress(address, externalPort); + socket.connect(inetSocketAddress, 1000); + } catch (IOException e) { + throw new IllegalStateException("Socket not listening yet: " + externalPort); + } + }); return true; } } diff --git a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java index 1eba8acbbd1..aeedbea1e3f 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java +++ b/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java @@ -10,8 +10,6 @@ import java.time.Instant; import java.util.Set; -import static java.lang.String.format; - /** * Mechanism for testing that a socket is listening when run from the container being checked. */ @@ -20,6 +18,7 @@ public class InternalCommandPortListeningCheck implements java.util.concurrent.Callable { private final WaitStrategyTarget waitStrategyTarget; + private final Set internalPorts; @Override @@ -29,19 +28,31 @@ public Boolean call() { for (int internalPort : internalPorts) { command.append(" && "); command.append(" ("); - command.append(format("grep -i ':0*%x' /proc/net/tcp*", internalPort)); + command.append(String.format("grep -i ':0*%x' /proc/net/tcp*", internalPort)); command.append(" || "); - command.append(format("nc -vz -w 1 localhost %d", internalPort)); + command.append(String.format("nc -vz -w 1 localhost %d", internalPort)); command.append(" || "); - command.append(format("/bin/bash -c ' externalLivenessCheckPorts = getLivenessCheckPorts(); if (externalLivenessCheckPorts.isEmpty()) { if (log.isDebugEnabled()) { - log.debug("Liveness check ports of {} is empty. Not waiting.", waitStrategyTarget.getContainerInfo().getName()); + log.debug( + "Liveness check ports of {} is empty. Not waiting.", + waitStrategyTarget.getContainerInfo().getName() + ); } return; } @@ -45,58 +48,69 @@ protected void waitUntilReady() { Callable internalCheck = new InternalCommandPortListeningCheck(waitStrategyTarget, internalPorts); - Callable externalCheck = new ExternalPortListeningCheck(waitStrategyTarget, externalLivenessCheckPorts); + Callable externalCheck = new ExternalPortListeningCheck( + waitStrategyTarget, + externalLivenessCheckPorts + ); try { - List> futures = EXECUTOR.invokeAll(Arrays.asList( - // Blocking - () -> { - Instant now = Instant.now(); - Boolean result = internalCheck.call(); - log.debug( - "Internal port check {} for {} in {}", - Boolean.TRUE.equals(result) ? "passed" : "failed", - internalPorts, - Duration.between(now, Instant.now()) - ); - return result; - }, - // Polling - () -> { - Instant now = Instant.now(); - Awaitility.await() - .pollInSameThread() - .pollInterval(Duration.ofMillis(100)) - .pollDelay(Duration.ZERO) - .ignoreExceptions() - .forever() - .until(externalCheck); + List> futures = EXECUTOR.invokeAll( + Arrays.asList( + // Blocking + () -> { + Instant now = Instant.now(); + Boolean result = internalCheck.call(); + log.debug( + "Internal port check {} for {} in {}", + Boolean.TRUE.equals(result) ? "passed" : "failed", + internalPorts, + Duration.between(now, Instant.now()) + ); + return result; + }, + // Polling + () -> { + Instant now = Instant.now(); + Awaitility + .await() + .pollInSameThread() + .pollInterval(Duration.ofMillis(100)) + .pollDelay(Duration.ZERO) + .ignoreExceptions() + .forever() + .until(externalCheck); - log.debug( - "External port check passed for {} mapped as {} in {}", - internalPorts, - externalLivenessCheckPorts, - Duration.between(now, Instant.now()) - ); - return true; - } - ), startupTimeout.getSeconds(), TimeUnit.SECONDS); + log.debug( + "External port check passed for {} mapped as {} in {}", + internalPorts, + externalLivenessCheckPorts, + Duration.between(now, Instant.now()) + ); + return true; + } + ), + startupTimeout.getSeconds(), + TimeUnit.SECONDS + ); for (Future future : futures) { future.get(0, TimeUnit.SECONDS); } } catch (CancellationException | ExecutionException | TimeoutException e) { - throw new ContainerLaunchException("Timed out waiting for container port to open (" + - waitStrategyTarget.getHost() + - " ports: " + - externalLivenessCheckPorts + - " should be listening)"); + throw new ContainerLaunchException( + "Timed out waiting for container port to open (" + + waitStrategyTarget.getHost() + + " ports: " + + externalLivenessCheckPorts + + " should be listening)" + ); } } private Set getInternalPorts(Set externalLivenessCheckPorts, List exposedPorts) { - return exposedPorts.stream() - .filter(it -> externalLivenessCheckPorts.contains(waitStrategyTarget.getMappedPort(it))) - .collect(Collectors.toSet()); + return exposedPorts + .stream() + .filter(it -> externalLivenessCheckPorts.contains(waitStrategyTarget.getMappedPort(it))) + .collect(Collectors.toSet()); } } diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java index d5d08ce6fd0..ccaef47a821 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java @@ -2,8 +2,6 @@ import com.google.common.base.Strings; import com.google.common.io.BaseEncoding; -import java.util.HashMap; -import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.rnorth.ducttape.TimeoutException; import org.testcontainers.containers.ContainerLaunchException; @@ -15,12 +13,14 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URL; -import java.time.Duration; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; +import java.time.Duration; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -48,16 +48,27 @@ public class HttpWaitStrategy extends AbstractWaitStrategy { private static final String AUTH_BASIC = "Basic "; private String path = "/"; + private String method = "GET"; + private Set statusCodes = new HashSet<>(); + private boolean tlsEnabled; + private String username; + private String password; + private final Map headers = new HashMap<>(); + private Predicate responsePredicate; + private Predicate statusCodePredicate = null; + private Optional livenessPort = Optional.empty(); + private Duration readTimeout = Duration.ofSeconds(1); + private boolean allowInsecure; /** @@ -196,14 +207,16 @@ public HttpWaitStrategy forResponsePredicate(Predicate responsePredicate protected void waitUntilReady() { final String containerName = waitStrategyTarget.getContainerInfo().getName(); - final Integer livenessCheckPort = livenessPort.map(waitStrategyTarget::getMappedPort).orElseGet(() -> { - final Set livenessCheckPorts = getLivenessCheckPorts(); - if (livenessCheckPorts == null || livenessCheckPorts.isEmpty()) { - log.warn("{}: No exposed ports or mapped ports - cannot wait for status", containerName); - return -1; - } - return livenessCheckPorts.iterator().next(); - }); + final Integer livenessCheckPort = livenessPort + .map(waitStrategyTarget::getMappedPort) + .orElseGet(() -> { + final Set livenessCheckPorts = getLivenessCheckPorts(); + if (livenessCheckPorts == null || livenessCheckPorts.isEmpty()) { + log.warn("{}: No exposed ports or mapped ports - cannot wait for status", containerName); + return -1; + } + return livenessCheckPorts.iterator().next(); + }); if (null == livenessCheckPort || -1 == livenessCheckPort) { return; @@ -213,11 +226,20 @@ protected void waitUntilReady() { try { // Un-map the port for logging - int originalPort = waitStrategyTarget.getExposedPorts().stream() + int originalPort = waitStrategyTarget + .getExposedPorts() + .stream() .filter(exposedPort -> rawUri.getPort() == waitStrategyTarget.getMappedPort(exposedPort)) .findFirst() .orElseThrow(() -> new IllegalStateException("Target port " + rawUri.getPort() + " is not exposed")); - log.info("{}: Waiting for {} seconds for URL: {} (where port {} maps to container port {})", containerName, startupTimeout.getSeconds(), uri, rawUri.getPort(), originalPort); + log.info( + "{}: Waiting for {} seconds for URL: {} (where port {} maps to container port {})", + containerName, + startupTimeout.getSeconds(), + uri, + rawUri.getPort(), + originalPort + ); } catch (RuntimeException e) { // do not allow a failure in logging to prevent progress, but log for diagnosis log.warn("Unexpected error occurred - will proceed to try to wait anyway", e); @@ -225,103 +247,114 @@ protected void waitUntilReady() { // try to connect to the URL try { - retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> { - getRateLimiter().doWhenReady(() -> { - try { - final HttpURLConnection connection = openConnection(uri); - connection.setReadTimeout(Math.toIntExact(readTimeout.toMillis())); - - // authenticate - if (!Strings.isNullOrEmpty(username)) { - connection.setRequestProperty(HEADER_AUTHORIZATION, buildAuthString(username, password)); - connection.setUseCaches(false); - } - - // Add user configured headers - this.headers.forEach(connection::setRequestProperty); - connection.setRequestMethod(method); - connection.connect(); - - log.trace("Get response code {}", connection.getResponseCode()); - - // Choose the statusCodePredicate strategy depending on what we defined. - Predicate predicate; - if (statusCodes.isEmpty() && statusCodePredicate == null) { - // We have no status code and no predicate so we expect a 200 OK response code - predicate = responseCode -> HttpURLConnection.HTTP_OK == responseCode; - } else if (!statusCodes.isEmpty() && statusCodePredicate == null) { - // We use the default status predicate checker when we only have status codes - predicate = responseCode -> statusCodes.contains(responseCode); - } else if (statusCodes.isEmpty()) { - // We only have a predicate - predicate = statusCodePredicate; - } else { - // We have both predicate and status code - predicate = statusCodePredicate.or(responseCode -> statusCodes.contains(responseCode)); - } - if (!predicate.test(connection.getResponseCode())) { - throw new RuntimeException(String.format("HTTP response code was: %s", - connection.getResponseCode())); - } - - if(responsePredicate != null) { - String responseBody = getResponseBody(connection); - - log.trace("Get response {}", responseBody); - - if(!responsePredicate.test(responseBody)) { - throw new RuntimeException(String.format("Response: %s did not match predicate", - responseBody)); + retryUntilSuccess( + (int) startupTimeout.getSeconds(), + TimeUnit.SECONDS, + () -> { + getRateLimiter() + .doWhenReady(() -> { + try { + final HttpURLConnection connection = openConnection(uri); + connection.setReadTimeout(Math.toIntExact(readTimeout.toMillis())); + + // authenticate + if (!Strings.isNullOrEmpty(username)) { + connection.setRequestProperty( + HEADER_AUTHORIZATION, + buildAuthString(username, password) + ); + connection.setUseCaches(false); + } + + // Add user configured headers + this.headers.forEach(connection::setRequestProperty); + connection.setRequestMethod(method); + connection.connect(); + + log.trace("Get response code {}", connection.getResponseCode()); + + // Choose the statusCodePredicate strategy depending on what we defined. + Predicate predicate; + if (statusCodes.isEmpty() && statusCodePredicate == null) { + // We have no status code and no predicate so we expect a 200 OK response code + predicate = responseCode -> HttpURLConnection.HTTP_OK == responseCode; + } else if (!statusCodes.isEmpty() && statusCodePredicate == null) { + // We use the default status predicate checker when we only have status codes + predicate = responseCode -> statusCodes.contains(responseCode); + } else if (statusCodes.isEmpty()) { + // We only have a predicate + predicate = statusCodePredicate; + } else { + // We have both predicate and status code + predicate = + statusCodePredicate.or(responseCode -> statusCodes.contains(responseCode)); + } + if (!predicate.test(connection.getResponseCode())) { + throw new RuntimeException( + String.format("HTTP response code was: %s", connection.getResponseCode()) + ); + } + + if (responsePredicate != null) { + String responseBody = getResponseBody(connection); + + log.trace("Get response {}", responseBody); + + if (!responsePredicate.test(responseBody)) { + throw new RuntimeException( + String.format("Response: %s did not match predicate", responseBody) + ); + } + } + } catch (IOException e) { + throw new RuntimeException(e); } - } - - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - return true; - }); - + }); + return true; + } + ); } catch (TimeoutException e) { - throw new ContainerLaunchException(String.format( - "Timed out waiting for URL to be accessible (%s should return HTTP %s)", uri, statusCodes.isEmpty() ? - HttpURLConnection.HTTP_OK : statusCodes)); + throw new ContainerLaunchException( + String.format( + "Timed out waiting for URL to be accessible (%s should return HTTP %s)", + uri, + statusCodes.isEmpty() ? HttpURLConnection.HTTP_OK : statusCodes + ) + ); } } private HttpURLConnection openConnection(final String uri) throws IOException, MalformedURLException { if (tlsEnabled) { - final HttpsURLConnection connection = (HttpsURLConnection)new URL(uri).openConnection(); + final HttpsURLConnection connection = (HttpsURLConnection) new URL(uri).openConnection(); if (allowInsecure) { - // Create a trust manager that does not validate certificate chains + // Create a trust manager that does not validate certificate chains // and trust all certificates - final TrustManager[] trustAllCerts = new TrustManager[] { + final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override - public X509Certificate[] getAcceptedIssuers() { + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - + @Override - public void checkClientTrusted(final X509Certificate[] certs, final String authType) { - } - + public void checkClientTrusted(final X509Certificate[] certs, final String authType) {} + @Override - public void checkServerTrusted(final X509Certificate[] certs, final String authType) { - } - } - }; + public void checkServerTrusted(final X509Certificate[] certs, final String authType) {} + }, + }; try { // Create custom SSL context and set the "trust all certificates" trust manager - final SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(new KeyManager[0], trustAllCerts, new SecureRandom()); + final SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(new KeyManager[0], trustAllCerts, new SecureRandom()); connection.setSSLSocketFactory(sc.getSocketFactory()); } catch (final NoSuchAlgorithmException | KeyManagementException ex) { throw new IOException("Unable to create custom SSL factory instance", ex); } } - + return connection; } else { return (HttpURLConnection) new URL(uri).openConnection(); diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java index 65370e51bfa..7a095d888f2 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java @@ -2,7 +2,6 @@ import com.github.dockerjava.api.command.LogContainerCmd; import lombok.SneakyThrows; -import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.output.FrameConsumerResultCallback; import org.testcontainers.containers.output.OutputFrame; @@ -13,9 +12,6 @@ import java.util.concurrent.TimeoutException; import java.util.function.Predicate; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; - public class LogMessageWaitStrategy extends AbstractWaitStrategy { private String regEx; @@ -27,22 +23,24 @@ public class LogMessageWaitStrategy extends AbstractWaitStrategy { protected void waitUntilReady() { WaitingConsumer waitingConsumer = new WaitingConsumer(); - LogContainerCmd cmd = waitStrategyTarget.getDockerClient().logContainerCmd(waitStrategyTarget.getContainerId()) + LogContainerCmd cmd = waitStrategyTarget + .getDockerClient() + .logContainerCmd(waitStrategyTarget.getContainerId()) .withFollowStream(true) .withSince(0) .withStdOut(true) .withStdErr(true); try (FrameConsumerResultCallback callback = new FrameConsumerResultCallback()) { - callback.addConsumer(STDOUT, waitingConsumer); - callback.addConsumer(STDERR, waitingConsumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, waitingConsumer); + callback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer); cmd.exec(callback); - Predicate waitPredicate = outputFrame -> + Predicate waitPredicate = outputFrame -> { // (?s) enables line terminator matching (equivalent to Pattern.DOTALL) - outputFrame.getUtf8String().matches("(?s)" + regEx); - + return outputFrame.getUtf8String().matches("(?s)" + regEx); + }; try { waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, times); } catch (TimeoutException e) { diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java index 034a83a2949..6c3b9e86aec 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java @@ -1,12 +1,11 @@ package org.testcontainers.containers.wait.strategy; -import java.net.HttpURLConnection; - /** * Convenience class with logic for building common {@link WaitStrategy} instances. * */ public class Wait { + /** * Convenience method to return the default WaitStrategy. * @@ -34,8 +33,7 @@ public static HostPortWaitStrategy forListeningPort() { * @see HttpWaitStrategy */ public static HttpWaitStrategy forHttp(String path) { - return new HttpWaitStrategy() - .forPath(path); + return new HttpWaitStrategy().forPath(path); } /** @@ -46,8 +44,7 @@ public static HttpWaitStrategy forHttp(String path) { * @see HttpWaitStrategy */ public static HttpWaitStrategy forHttps(String path) { - return forHttp(path) - .usingTls(); + return forHttp(path).usingTls(); } /** diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java index cebacb375b6..5c7530fc67f 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitAllStrategy.java @@ -1,16 +1,15 @@ package org.testcontainers.containers.wait.strategy; +import org.rnorth.ducttape.timeouts.Timeouts; + import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; -import org.rnorth.ducttape.timeouts.Timeouts; - public class WaitAllStrategy implements WaitStrategy { public enum Mode { - /** * This is the default mode: The timeout of the {@link WaitAllStrategy strategy} is applied to each individual * strategy, so that the container waits maximum for @@ -30,11 +29,13 @@ public enum Mode { * This is the original mode of this strategy: The inner strategies wait with their preconfigured timeout * individually and the wait all strategy kills them, if the outer limit is reached. */ - WITH_MAXIMUM_OUTER_TIMEOUT + WITH_MAXIMUM_OUTER_TIMEOUT, } private final Mode mode; + private final List strategies = new ArrayList<>(); + private Duration timeout = Duration.ofSeconds(30); public WaitAllStrategy() { @@ -50,9 +51,13 @@ public void waitUntilReady(WaitStrategyTarget waitStrategyTarget) { if (mode == Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) { waitUntilNestedStrategiesAreReady(waitStrategyTarget); } else { - Timeouts.doWithTimeout((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> { - waitUntilNestedStrategiesAreReady(waitStrategyTarget); - }); + Timeouts.doWithTimeout( + (int) timeout.toMillis(), + TimeUnit.MILLISECONDS, + () -> { + waitUntilNestedStrategiesAreReady(waitStrategyTarget); + } + ); } } @@ -63,7 +68,6 @@ private void waitUntilNestedStrategiesAreReady(WaitStrategyTarget waitStrategyTa } public WaitAllStrategy withStrategy(WaitStrategy strategy) { - if (mode == Mode.WITH_OUTER_TIMEOUT) { applyStartupTimeout(strategy); } @@ -74,10 +78,13 @@ public WaitAllStrategy withStrategy(WaitStrategy strategy) { @Override public WaitAllStrategy withStartupTimeout(Duration startupTimeout) { - if (mode == Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) { - throw new IllegalStateException(String.format( - "Changing startup timeout is not supported with mode %s", Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY)); + throw new IllegalStateException( + String.format( + "Changing startup timeout is not supported with mode %s", + Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY + ) + ); } this.timeout = startupTimeout; diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategy.java index 25703174502..ff371cf775f 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategy.java @@ -3,7 +3,6 @@ import java.time.Duration; public interface WaitStrategy { - void waitUntilReady(WaitStrategyTarget waitStrategyTarget); WaitStrategy withStartupTimeout(Duration startupTimeout); diff --git a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategyTarget.java b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategyTarget.java index 49f88fb7711..778c252009b 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategyTarget.java +++ b/core/src/main/java/org/testcontainers/containers/wait/strategy/WaitStrategyTarget.java @@ -6,13 +6,15 @@ import java.util.stream.Collectors; public interface WaitStrategyTarget extends ContainerState { - /** * @return the ports on which to check if the container is ready */ default Set getLivenessCheckPortNumbers() { - final Set result = getExposedPorts().stream() - .map(this::getMappedPort).distinct().collect(Collectors.toSet()); + final Set result = getExposedPorts() + .stream() + .map(this::getMappedPort) + .distinct() + .collect(Collectors.toSet()); result.addAll(getBoundPortNumbers()); return result; } diff --git a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java index 2dc88cad313..2b413aafaed 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuditLoggingDockerClient.java @@ -5,13 +5,12 @@ import lombok.experimental.Delegate; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; +import org.testcontainers.utility.AuditLogger; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; import java.util.function.BiConsumer; -import static org.testcontainers.utility.AuditLogger.doLog; - /** * Wrapper for {@link DockerClient} to facilitate 'audit logging' of potentially destruction actions using * {@link org.testcontainers.utility.AuditLogger}. @@ -30,97 +29,117 @@ public AuditLoggingDockerClient(DockerClient wrappedClient) { @Override public CreateContainerCmd createContainerCmd(@NotNull String image) { - return wrappedCommand(CreateContainerCmd.class, - wrappedClient.createContainerCmd(image), - (cmd, res) -> doLog("CREATE", image, res.getId(), cmd), - (cmd, e) -> doLog("CREATE", image, null, cmd, e)); - + return wrappedCommand( + CreateContainerCmd.class, + wrappedClient.createContainerCmd(image), + (cmd, res) -> AuditLogger.doLog("CREATE", image, res.getId(), cmd), + (cmd, e) -> AuditLogger.doLog("CREATE", image, null, cmd, e) + ); } @Override public StartContainerCmd startContainerCmd(@NotNull String containerId) { - return wrappedCommand(StartContainerCmd.class, - wrappedClient.startContainerCmd(containerId), - (cmd, res) -> doLog("START", null, containerId, cmd), - (cmd, e) -> doLog("START", null, containerId, cmd, e)); + return wrappedCommand( + StartContainerCmd.class, + wrappedClient.startContainerCmd(containerId), + (cmd, res) -> AuditLogger.doLog("START", null, containerId, cmd), + (cmd, e) -> AuditLogger.doLog("START", null, containerId, cmd, e) + ); } @Override public RemoveContainerCmd removeContainerCmd(@NotNull String containerId) { - return wrappedCommand(RemoveContainerCmd.class, - wrappedClient.removeContainerCmd(containerId), - (cmd, res) -> doLog("REMOVE", null, containerId, cmd), - (cmd, e) -> doLog("REMOVE", null, containerId, cmd, e)); + return wrappedCommand( + RemoveContainerCmd.class, + wrappedClient.removeContainerCmd(containerId), + (cmd, res) -> AuditLogger.doLog("REMOVE", null, containerId, cmd), + (cmd, e) -> AuditLogger.doLog("REMOVE", null, containerId, cmd, e) + ); } @Override public StopContainerCmd stopContainerCmd(@NotNull String containerId) { - return wrappedCommand(StopContainerCmd.class, - wrappedClient.stopContainerCmd(containerId), - (cmd, res) -> doLog("STOP", null, containerId, cmd), - (cmd, e) -> doLog("STOP", null, containerId, cmd, e)); + return wrappedCommand( + StopContainerCmd.class, + wrappedClient.stopContainerCmd(containerId), + (cmd, res) -> AuditLogger.doLog("STOP", null, containerId, cmd), + (cmd, e) -> AuditLogger.doLog("STOP", null, containerId, cmd, e) + ); } @Override public KillContainerCmd killContainerCmd(@NotNull String containerId) { - return wrappedCommand(KillContainerCmd.class, - wrappedClient.killContainerCmd(containerId), - (cmd, res) -> doLog("KILL", null, containerId, cmd), - (cmd, e) -> doLog("KILL", null, containerId, cmd, e)); + return wrappedCommand( + KillContainerCmd.class, + wrappedClient.killContainerCmd(containerId), + (cmd, res) -> AuditLogger.doLog("KILL", null, containerId, cmd), + (cmd, e) -> AuditLogger.doLog("KILL", null, containerId, cmd, e) + ); } @Override public CreateNetworkCmd createNetworkCmd() { - return wrappedCommand(CreateNetworkCmd.class, - wrappedClient.createNetworkCmd(), - (cmd, res) -> doLog("CREATE_NETWORK", null, null, cmd), - (cmd, e) -> doLog("CREATE_NETWORK", null, null, cmd, e)); + return wrappedCommand( + CreateNetworkCmd.class, + wrappedClient.createNetworkCmd(), + (cmd, res) -> AuditLogger.doLog("CREATE_NETWORK", null, null, cmd), + (cmd, e) -> AuditLogger.doLog("CREATE_NETWORK", null, null, cmd, e) + ); } @Override public RemoveNetworkCmd removeNetworkCmd(@NotNull String networkId) { - return wrappedCommand(RemoveNetworkCmd.class, - wrappedClient.removeNetworkCmd(networkId), - (cmd, res) -> doLog("REMOVE_NETWORK", null, null, cmd), - (cmd, e) -> doLog("REMOVE_NETWORK", null, null, cmd, e)); + return wrappedCommand( + RemoveNetworkCmd.class, + wrappedClient.removeNetworkCmd(networkId), + (cmd, res) -> AuditLogger.doLog("REMOVE_NETWORK", null, null, cmd), + (cmd, e) -> AuditLogger.doLog("REMOVE_NETWORK", null, null, cmd, e) + ); } - private , R> T wrappedCommand(Class clazz, - T cmd, - BiConsumer successConsumer, - BiConsumer failureConsumer) { - + private , R> T wrappedCommand( + Class clazz, + T cmd, + BiConsumer successConsumer, + BiConsumer failureConsumer + ) { return (T) Proxy.newProxyInstance( - clazz.getClassLoader(), - new Class[]{clazz}, - (proxy, method, args) -> { - - if (method.getName().equals("exec")) { - try { - R r = (R) method.invoke(cmd, args); - successConsumer.accept(cmd, r); - return r; - } catch (Exception e) { - if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) { - e = (Exception) e.getCause(); - } - failureConsumer.accept(cmd, e); - throw e; + clazz.getClassLoader(), + new Class[] { clazz }, + (proxy, method, args) -> { + if (method.getName().equals("exec")) { + try { + R r = (R) method.invoke(cmd, args); + successConsumer.accept(cmd, r); + return r; + } catch (Exception e) { + if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) { + e = (Exception) e.getCause(); } - } else { - return method.invoke(cmd, args); + failureConsumer.accept(cmd, e); + throw e; } - }); + } else { + return method.invoke(cmd, args); + } + } + ); } @SuppressWarnings("unused") private interface InterceptedMethods { CreateContainerCmd createContainerCmd(String image); + StartContainerCmd startContainerCmd(String containerId); + RemoveContainerCmd removeContainerCmd(String containerId); + StopContainerCmd stopContainerCmd(String containerId); + KillContainerCmd killContainerCmd(String containerId); + CreateNetworkCmd createNetworkCmd(); + RemoveNetworkCmd removeNetworkCmd(String networkId); } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java index 1f534eb59e5..5713d054e13 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java +++ b/core/src/main/java/org/testcontainers/dockerclient/AuthDelegatingDockerClientConfig.java @@ -4,11 +4,10 @@ import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.DockerClientConfigDelegate; import lombok.extern.slf4j.Slf4j; +import org.testcontainers.utility.AuthConfigUtil; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.RegistryAuthLocator; -import static org.testcontainers.utility.AuthConfigUtil.toSafeString; - /** * Facade implementation for {@link DockerClientConfig} which overrides how authentication * configuration is obtained. A delegate {@link DockerClientConfig} will be called first @@ -31,18 +30,21 @@ public AuthConfig effectiveAuthConfig(String imageName) { try { fallbackAuthConfig = super.effectiveAuthConfig(imageName); } catch (Exception e) { - log.debug("Delegate call to effectiveAuthConfig failed with cause: '{}'. " + + log.debug( + "Delegate call to effectiveAuthConfig failed with cause: '{}'. " + "Resolution of auth config will continue using RegistryAuthLocator.", - e.getMessage()); + e.getMessage() + ); fallbackAuthConfig = new AuthConfig(); } // try and obtain more accurate auth config using our resolution final DockerImageName parsed = DockerImageName.parse(imageName); - final AuthConfig effectiveAuthConfig = RegistryAuthLocator.instance() + final AuthConfig effectiveAuthConfig = RegistryAuthLocator + .instance() .lookupAuthConfig(parsed, fallbackAuthConfig); - log.debug("Effective auth config [{}]", toSafeString(effectiveAuthConfig)); + log.debug("Effective auth config [{}]", AuthConfigUtil.toSafeString(effectiveAuthConfig)); return effectiveAuthConfig; } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java index e393e59419f..7206a7e1452 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java @@ -8,8 +8,7 @@ import java.io.File; import java.net.URI; import java.util.Optional; - -import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.concurrent.TimeUnit; @Slf4j public class DockerClientConfigUtils { @@ -19,25 +18,31 @@ public class DockerClientConfigUtils { @Getter(lazy = true) private static final Optional defaultGateway = Optional - .ofNullable(DockerClientFactory.instance().runInsideDocker( + .ofNullable( + DockerClientFactory + .instance() + .runInsideDocker( cmd -> cmd.withCmd("sh", "-c", "ip route|awk '/default/ { print $3 }'"), (client, id) -> { try { LogToStringContainerCallback loggingCallback = new LogToStringContainerCallback(); - client.logContainerCmd(id).withStdOut(true) - .withFollowStream(true) - .exec(loggingCallback) - .awaitStarted(); - loggingCallback.awaitCompletion(3, SECONDS); + client + .logContainerCmd(id) + .withStdOut(true) + .withFollowStream(true) + .exec(loggingCallback) + .awaitStarted(); + loggingCallback.awaitCompletion(3, TimeUnit.SECONDS); return loggingCallback.toString(); } catch (Exception e) { log.warn("Can't parse the default gateway IP", e); return null; } } - )) - .map(StringUtils::trimToEmpty) - .filter(StringUtils::isNotBlank); + ) + ) + .map(StringUtils::trimToEmpty) + .filter(StringUtils::isNotBlank); /** * @deprecated use {@link DockerClientProviderStrategy#getDockerHostIpAddress()} diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 834e670438a..0d2aa3d08ed 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -27,7 +27,6 @@ import org.testcontainers.UnstableAPI; import org.testcontainers.utility.TestcontainersConfiguration; -import javax.net.SocketFactory; import java.io.File; import java.net.InetSocketAddress; import java.net.Socket; @@ -54,6 +53,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.net.SocketFactory; + /** * Mechanism to find a viable Docker client configuration according to the host system environment. */ @@ -68,10 +69,11 @@ public abstract class DockerClientProviderStrategy { @Getter private Info info; - private final RateLimiter PING_RATE_LIMITER = RateLimiterBuilder.newBuilder() - .withRate(10, TimeUnit.SECONDS) - .withConstantThroughput() - .build(); + private final RateLimiter PING_RATE_LIMITER = RateLimiterBuilder + .newBuilder() + .withRate(10, TimeUnit.SECONDS) + .withConstantThroughput() + .build(); private static final AtomicBoolean FAIL_FAST_ALWAYS = new AtomicBoolean(false); @@ -109,14 +111,18 @@ protected int getPriority() { public DockerClient getClient() { DockerClient dockerClient = getDockerClient(); try { - Unreliables.retryUntilSuccess(30, TimeUnit.SECONDS, () -> { - return PING_RATE_LIMITER.getWhenReady(() -> { - log.debug("Pinging docker daemon..."); - dockerClient.pingCmd().exec(); - log.debug("Pinged"); - return true; - }); - }); + Unreliables.retryUntilSuccess( + 30, + TimeUnit.SECONDS, + () -> { + return PING_RATE_LIMITER.getWhenReady(() -> { + log.debug("Pinging docker daemon..."); + dockerClient.pingCmd().exec(); + log.debug("Pinged"); + return true; + }); + } + ); } catch (TimeoutException e) { IOUtils.closeQuietly(dockerClient); throw e; @@ -143,7 +149,12 @@ protected boolean test() { if (sslConfig != null) { try { socketFactory = sslConfig.getSSLContext().getSocketFactory(); - } catch (KeyManagementException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) { + } catch ( + KeyManagementException + | UnrecoverableKeyException + | NoSuchAlgorithmException + | KeyStoreException e + ) { log.warn("Exception while creating SSLSocketFactory", e); return false; } @@ -157,16 +168,17 @@ protected boolean test() { log.debug("DOCKER_HOST socket file '{}' does not exist", dockerHost.getPath()); return false; } - socketProvider = () -> { - switch (dockerHost.getScheme()) { - case "unix": - return UnixSocket.get(dockerHost.getPath()); - case "npipe": - return new NamedPipeSocket(dockerHost.getPath()); - default: - throw new IllegalStateException("Unexpected scheme " + dockerHost.getScheme()); - } - }; + socketProvider = + () -> { + switch (dockerHost.getScheme()) { + case "unix": + return UnixSocket.get(dockerHost.getPath()); + case "npipe": + return new NamedPipeSocket(dockerHost.getPath()); + default: + throw new IllegalStateException("Unexpected scheme " + dockerHost.getScheme()); + } + }; socketAddress = new InetSocketAddress("localhost", 2375); break; default: @@ -176,7 +188,8 @@ protected boolean test() { try (Socket socket = socketProvider.call()) { Duration timeout = Duration.ofMillis(200); - Awaitility.await() + Awaitility + .await() .atMost(TestcontainersConfiguration.getInstance().getClientPingTimeout(), TimeUnit.SECONDS) .pollInterval(timeout) .pollDelay(Duration.ofSeconds(0)) // start checking immediately @@ -195,9 +208,10 @@ protected boolean test() { * @return a working DockerClientConfig, as determined by successful execution of a ping command */ public static DockerClientProviderStrategy getFirstValidStrategy(List strategies) { - if (FAIL_FAST_ALWAYS.get()) { - throw new IllegalStateException("Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration"); + throw new IllegalStateException( + "Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration" + ); } List configurationFailures = new ArrayList<>(); @@ -215,7 +229,6 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List allStrategies)); - Predicate distinctStrategyClassPredicate = new Predicate() { final Set> classes = new HashSet<>(); @@ -232,14 +245,18 @@ public boolean test(DockerClientProviderStrategy dockerClientProviderStrategy) { .filter(strategy -> tryOutStrategy(configurationFailures, strategy)) .findFirst() .orElseThrow(() -> { - log.error("Could not find a valid Docker environment. Please check configuration. Attempted configurations were:"); + log.error( + "Could not find a valid Docker environment. Please check configuration. Attempted configurations were:" + ); for (String failureMessage : configurationFailures) { log.error(" " + failureMessage); } log.error("As no valid configuration was found, execution cannot continue"); FAIL_FAST_ALWAYS.set(true); - return new IllegalStateException("Could not find a valid Docker environment. Please see logs and check configuration"); + return new IllegalStateException( + "Could not find a valid Docker environment. Please see logs and check configuration" + ); }); } @@ -270,30 +287,39 @@ private static boolean tryOutStrategy(List configurationFailures, Docker } if (strategy.isPersistable()) { - TestcontainersConfiguration.getInstance().updateUserConfig("docker.client.strategy", strategy.getClass().getName()); + TestcontainersConfiguration + .getInstance() + .updateUserConfig("docker.client.strategy", strategy.getClass().getName()); } return true; } catch (Exception | ExceptionInInitializerError | NoClassDefFoundError e) { - @Nullable String throwableMessage = e.getMessage(); + @Nullable + String throwableMessage = e.getMessage(); @SuppressWarnings("ThrowableResultOfMethodCallIgnored") Throwable rootCause = Throwables.getRootCause(e); - @Nullable String rootCauseMessage = rootCause.getMessage(); + @Nullable + String rootCauseMessage = rootCause.getMessage(); String failureDescription; if (throwableMessage != null && throwableMessage.equals(rootCauseMessage)) { - failureDescription = String.format("%s: failed with exception %s (%s)", + failureDescription = + String.format( + "%s: failed with exception %s (%s)", strategy.getClass().getSimpleName(), e.getClass().getSimpleName(), - throwableMessage); + throwableMessage + ); } else { - failureDescription = String.format("%s: failed with exception %s (%s). Root cause %s (%s)", + failureDescription = + String.format( + "%s: failed with exception %s (%s). Root cause %s (%s)", strategy.getClass().getSimpleName(), e.getClass().getSimpleName(), throwableMessage, rootCause.getClass().getSimpleName(), rootCauseMessage - ); + ); } configurationFailures.add(failureDescription); @@ -303,20 +329,28 @@ private static boolean tryOutStrategy(List configurationFailures, Docker } private static Optional loadConfiguredStrategy() { - String configuredDockerClientStrategyClassName = TestcontainersConfiguration.getInstance().getDockerClientStrategyClassName(); + String configuredDockerClientStrategyClassName = TestcontainersConfiguration + .getInstance() + .getDockerClientStrategyClassName(); return Stream .of(configuredDockerClientStrategyClassName) .filter(Objects::nonNull) .flatMap(it -> { try { - Class strategyClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(it); + Class strategyClass = (Class) Thread + .currentThread() + .getContextClassLoader() + .loadClass(it); return Stream.of(strategyClass.newInstance()); } catch (ClassNotFoundException e) { - log.warn("Can't instantiate a strategy from {} (ClassNotFoundException). " + + log.warn( + "Can't instantiate a strategy from {} (ClassNotFoundException). " + "This probably means that cached configuration refers to a client provider " + "class that is not available in this version of Testcontainers. Other " + - "strategies will be tried instead.", it); + "strategies will be tried instead.", + it + ); return Stream.empty(); } catch (InstantiationException | IllegalAccessException e) { log.warn("Can't instantiate a strategy from {}", it, e); @@ -325,7 +359,12 @@ private static Optional loadConfiguredSt }) // Ignore persisted strategy if it's not persistable anymore .filter(DockerClientProviderStrategy::isPersistable) - .peek(strategy -> log.info("Loaded {} from ~/.testcontainers.properties, will try it first", strategy.getClass().getName())) + .peek(strategy -> { + log.info( + "Loaded {} from ~/.testcontainers.properties, will try it first", + strategy.getClass().getName() + ); + }) .findFirst(); } @@ -335,10 +374,11 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) { String transportType = TestcontainersConfiguration.getInstance().getTransportType(); switch (transportType) { case "httpclient5": - dockerHttpClient = new ZerodepDockerHttpClient.Builder() - .dockerHost(transportConfig.getDockerHost()) - .sslConfig(transportConfig.getSslConfig()) - .build(); + dockerHttpClient = + new ZerodepDockerHttpClient.Builder() + .dockerHost(transportConfig.getDockerHost()) + .sslConfig(transportConfig.getSslConfig()) + .build(); break; default: throw new IllegalArgumentException("Unknown transport type '" + transportType + "'"); @@ -351,9 +391,7 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) { } return DockerClientImpl.getInstance( new AuthDelegatingDockerClientConfig( - configBuilder - .withDockerHost(transportConfig.getDockerHost().toString()) - .build() + configBuilder.withDockerHost(transportConfig.getDockerHost().toString()).build() ), new HeadersAddingDockerHttpClient( dockerHttpClient, @@ -384,7 +422,8 @@ static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost) { case "unix": case "npipe": if (DockerClientConfigUtils.IN_A_CONTAINER) { - return client.inspectNetworkCmd() + return client + .inspectNetworkCmd() .withNetworkId("bridge") .exec() .getIpam() diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java index 4de508ea808..7c05a11c198 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerMachineClientProviderStrategy.java @@ -1,6 +1,7 @@ package org.testcontainers.dockerclient; import com.github.dockerjava.core.LocalDirectorySSLConfig; +import com.google.common.base.Preconditions; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.testcontainers.utility.CommandLine; @@ -11,8 +12,6 @@ import java.util.Arrays; import java.util.Optional; -import static com.google.common.base.Preconditions.checkArgument; - /** * Use Docker machine (if available on the PATH) to locate a Docker environment. * @@ -27,10 +26,16 @@ public final class DockerMachineClientProviderStrategy extends DockerClientProvi private TransportConfig resolveTransportConfig() throws InvalidConfigurationException { boolean installed = DockerMachineClient.instance().isInstalled(); - checkArgument(installed, "docker-machine executable was not found on PATH (" + Arrays.toString(CommandLine.getSystemPath()) + ")"); + Preconditions.checkArgument( + installed, + "docker-machine executable was not found on PATH (" + Arrays.toString(CommandLine.getSystemPath()) + ")" + ); Optional machineNameOptional = DockerMachineClient.instance().getDefaultMachine(); - checkArgument(machineNameOptional.isPresent(), "docker-machine is installed but no default machine could be found"); + Preconditions.checkArgument( + machineNameOptional.isPresent(), + "docker-machine is installed but no default machine could be found" + ); String machineName = machineNameOptional.get(); log.info("Found docker-machine, and will use machine named {}", machineName); @@ -41,7 +46,8 @@ private TransportConfig resolveTransportConfig() throws InvalidConfigurationExce log.info("Docker daemon URL for docker machine {} is {}", machineName, dockerDaemonUrl); - return TransportConfig.builder() + return TransportConfig + .builder() .dockerHost(URI.create(dockerDaemonUrl)) .sslConfig( new LocalDirectorySSLConfig( @@ -55,7 +61,10 @@ private TransportConfig resolveTransportConfig() throws InvalidConfigurationExce protected boolean isApplicable() { boolean installed = DockerMachineClient.instance().isInstalled(); if (!installed) { - log.info("docker-machine executable was not found on PATH ({})", Arrays.toString(CommandLine.getSystemPath())); + log.info( + "docker-machine executable was not found on PATH ({})", + Arrays.toString(CommandLine.getSystemPath()) + ); return false; } diff --git a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java index 06fdf387d6a..969610373d1 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java @@ -35,7 +35,8 @@ public EnvironmentAndSystemPropertyClientProviderStrategy() { } EnvironmentAndSystemPropertyClientProviderStrategy(DefaultDockerClientConfig.Builder configBuilder) { - String dockerConfigSource = TestcontainersConfiguration.getInstance() + String dockerConfigSource = TestcontainersConfiguration + .getInstance() .getEnvVarOrProperty("dockerconfig.source", "auto"); switch (dockerConfigSource) { @@ -62,7 +63,8 @@ private Optional getSetting(final String name) { @Override public TransportConfig getTransportConfig() { - return TransportConfig.builder() + return TransportConfig + .builder() .dockerHost(dockerClientConfig.getDockerHost()) .sslConfig(dockerClientConfig.getSSLConfig()) .build(); @@ -75,7 +77,10 @@ protected int getPriority() { @Override public String getDescription() { - return "Environment variables, system properties and defaults. Resolved dockerHost=" + dockerClientConfig.getDockerHost(); + return ( + "Environment variables, system properties and defaults. Resolved dockerHost=" + + dockerClientConfig.getDockerHost() + ); } @Override diff --git a/core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java b/core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java index 59a51e19a80..7ff1b0b620c 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java +++ b/core/src/main/java/org/testcontainers/dockerclient/HeadersAddingDockerHttpClient.java @@ -19,9 +19,7 @@ class HeadersAddingDockerHttpClient implements DockerHttpClient { @Override public Response execute(Request request) { - request = Request.builder().from(request) - .putAllHeaders(headers) - .build(); + request = Request.builder().from(request).putAllHeaders(headers).build(); return delegate.execute(request); } } diff --git a/core/src/main/java/org/testcontainers/dockerclient/InvalidConfigurationException.java b/core/src/main/java/org/testcontainers/dockerclient/InvalidConfigurationException.java index ef834c9cec5..504378cb17e 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/InvalidConfigurationException.java +++ b/core/src/main/java/org/testcontainers/dockerclient/InvalidConfigurationException.java @@ -12,4 +12,4 @@ public InvalidConfigurationException(String s) { public InvalidConfigurationException(String message, Throwable cause) { super(message, cause); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java b/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java index d376b685a91..2c0716b65f0 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java +++ b/core/src/main/java/org/testcontainers/dockerclient/LogToStringContainerCallback.java @@ -9,6 +9,7 @@ */ @Deprecated public class LogToStringContainerCallback extends ResultCallback.Adapter { + private final StringBuffer log = new StringBuffer(); @Override diff --git a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java index 7f73e1d7675..0e1f641fe8a 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/NpipeSocketClientProviderStrategy.java @@ -12,15 +12,14 @@ public final class NpipeSocketClientProviderStrategy extends DockerClientProviderStrategy { protected static final String DOCKER_SOCK_PATH = "//./pipe/docker_engine"; + private static final String SOCKET_LOCATION = "npipe://" + DOCKER_SOCK_PATH; public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 20; @Override public TransportConfig getTransportConfig() { - return TransportConfig.builder() - .dockerHost(URI.create(SOCKET_LOCATION)) - .build(); + return TransportConfig.builder().dockerHost(URI.create(SOCKET_LOCATION)).build(); } @Override diff --git a/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java index 36d6b5f6123..a032c2b324d 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/RootlessDockerClientProviderStrategy.java @@ -29,13 +29,15 @@ public final class RootlessDockerClientProviderStrategy extends DockerClientProv private final Path socketPath = resolveSocketPath(); private Path resolveSocketPath() { - return tryEnv().orElseGet(() -> { - Path homePath = Paths.get(System.getProperty("user.home")).resolve(".docker").resolve("run"); - return tryFolder(homePath).orElseGet(() -> { - Path implicitPath = Paths.get("/run/user/" + LibC.INSTANCE.getuid()); - return tryFolder(implicitPath).orElse(null); + return tryEnv() + .orElseGet(() -> { + Path homePath = Paths.get(System.getProperty("user.home")).resolve(".docker").resolve("run"); + return tryFolder(homePath) + .orElseGet(() -> { + Path implicitPath = Paths.get("/run/user/" + LibC.INSTANCE.getuid()); + return tryFolder(implicitPath).orElse(null); + }); }); - }); } private Optional tryEnv() { @@ -72,9 +74,7 @@ private Optional tryFolder(Path path) { @Override public TransportConfig getTransportConfig() throws InvalidConfigurationException { - return TransportConfig.builder() - .dockerHost(URI.create("unix://" + getSocketPath().toString())) - .build(); + return TransportConfig.builder().dockerHost(URI.create("unix://" + getSocketPath().toString())).build(); } @Override @@ -93,10 +93,8 @@ protected int getPriority() { } private interface LibC extends Library { - LibC INSTANCE = Native.loadLibrary("c", LibC.class); int getuid(); } - } diff --git a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java index 4a85394155d..c262bda1db5 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/UnixSocketClientProviderStrategy.java @@ -14,8 +14,11 @@ */ @Deprecated public final class UnixSocketClientProviderStrategy extends DockerClientProviderStrategy { + protected static final String DOCKER_SOCK_PATH = "/var/run/docker.sock"; + private static final String SOCKET_LOCATION = "unix://" + DOCKER_SOCK_PATH; + private static final int SOCKET_FILE_MODE_MASK = 0xc000; public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 20; @@ -31,12 +34,12 @@ public TransportConfig getTransportConfig() throws InvalidConfigurationException } if ((mode & 0xc000) != SOCKET_FILE_MODE_MASK) { - throw new InvalidConfigurationException("Found docker unix domain socket but file mode was not as expected (expected: srwxr-xr-x). This problem is possibly due to occurrence of this issue in the past: https://github.com/docker/docker/issues/13121"); + throw new InvalidConfigurationException( + "Found docker unix domain socket but file mode was not as expected (expected: srwxr-xr-x). This problem is possibly due to occurrence of this issue in the past: https://github.com/docker/docker/issues/13121" + ); } - return TransportConfig.builder() - .dockerHost(URI.create(SOCKET_LOCATION)) - .build(); + return TransportConfig.builder().dockerHost(URI.create(SOCKET_LOCATION)).build(); } @Override diff --git a/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java b/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java index f5d75ad9617..1f9583ef4cf 100644 --- a/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java +++ b/core/src/main/java/org/testcontainers/images/AbstractImagePullPolicy.java @@ -36,7 +36,6 @@ public boolean shouldPull(DockerImageName imageName) { log.debug("Using locally available and not pulling image: {}", imageName); return false; } - } /** @@ -45,5 +44,5 @@ public boolean shouldPull(DockerImageName imageName) { * * @return {@code true} to update the locally available image, {@code false} to use local instead */ - abstract protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData); + protected abstract boolean shouldPullCached(DockerImageName imageName, ImageData localImageData); } diff --git a/core/src/main/java/org/testcontainers/images/ImageData.java b/core/src/main/java/org/testcontainers/images/ImageData.java index 345b5939268..e57be2dbbbd 100644 --- a/core/src/main/java/org/testcontainers/images/ImageData.java +++ b/core/src/main/java/org/testcontainers/images/ImageData.java @@ -17,14 +17,13 @@ public class ImageData { Instant createdAt; static ImageData from(InspectImageResponse inspectImageResponse) { - return ImageData.builder() + return ImageData + .builder() .createdAt(ZonedDateTime.parse(inspectImageResponse.getCreated()).toInstant()) .build(); } static ImageData from(Image image) { - return ImageData.builder() - .createdAt(Instant.ofEpochMilli(image.getCreated())) - .build(); + return ImageData.builder().createdAt(Instant.ofEpochMilli(image.getCreated())).build(); } } diff --git a/core/src/main/java/org/testcontainers/images/ImagePullPolicy.java b/core/src/main/java/org/testcontainers/images/ImagePullPolicy.java index e821e511795..a090c3f7b9c 100644 --- a/core/src/main/java/org/testcontainers/images/ImagePullPolicy.java +++ b/core/src/main/java/org/testcontainers/images/ImagePullPolicy.java @@ -3,7 +3,5 @@ import org.testcontainers.utility.DockerImageName; public interface ImagePullPolicy { - boolean shouldPull(DockerImageName imageName); - } diff --git a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java index 8791ecb6986..c98339e9f4c 100644 --- a/core/src/main/java/org/testcontainers/images/LocalImagesCache.java +++ b/core/src/main/java/org/testcontainers/images/LocalImagesCache.java @@ -79,14 +79,12 @@ private void populateFromList(List images) { } cache.putAll( - Stream.of(repoTags) + Stream + .of(repoTags) // Protection against some edge case where local image repository tags end up with duplicates // making toMap crash at merge time. .distinct() - .collect(Collectors.toMap( - DockerImageName::new, - it -> ImageData.from(image) - )) + .collect(Collectors.toMap(DockerImageName::new, it -> ImageData.from(image))) ); } } diff --git a/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java b/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java index 2ba8ba6df11..32e19090b5c 100644 --- a/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java +++ b/core/src/main/java/org/testcontainers/images/LoggedPullImageResultCallback.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.model.PullResponseItem; +import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import java.io.Closeable; @@ -9,21 +10,25 @@ import java.time.Instant; import java.util.*; -import static java.lang.String.format; -import static org.apache.commons.io.FileUtils.byteCountToDisplaySize; - /** * {@link PullImageResultCallback} with improved logging of pull progress. */ class LoggedPullImageResultCallback extends PullImageResultCallback { + private final Logger logger; private final Set allLayers = new HashSet<>(); + private final Set downloadedLayers = new HashSet<>(); + private final Set pulledLayers = new HashSet<>(); + private final Map totalSizes = new HashMap<>(); + private final Map currentSizes = new HashMap<>(); + private boolean completed; + private Instant start; LoggedPullImageResultCallback(final Logger logger) { @@ -69,8 +74,7 @@ public void onNext(final PullResponseItem item) { } } - if (statusLowercase.startsWith("pulling from" ) || statusLowercase.contains("complete" )) { - + if (statusLowercase.startsWith("pulling from") || statusLowercase.contains("complete")) { long totalSize = totalLayerSize(); long currentSize = downloadedLayerSize(); @@ -79,15 +83,17 @@ public void onNext(final PullResponseItem item) { if (pendingCount > 0) { friendlyTotalSize = "? MB"; } else { - friendlyTotalSize = byteCountToDisplaySize(totalSize); + friendlyTotalSize = FileUtils.byteCountToDisplaySize(totalSize); } - logger.info("Pulling image layers: {} pending, {} downloaded, {} extracted, ({}/{})", - format("%2d", pendingCount), - format("%2d", downloadedLayers.size()), - format("%2d", pulledLayers.size()), - byteCountToDisplaySize(currentSize), - friendlyTotalSize); + logger.info( + "Pulling image layers: {} pending, {} downloaded, {} extracted, ({}/{})", + String.format("%2d", pendingCount), + String.format("%2d", downloadedLayers.size()), + String.format("%2d", pulledLayers.size()), + FileUtils.byteCountToDisplaySize(currentSize), + friendlyTotalSize + ); } if (statusLowercase.contains("complete")) { @@ -103,11 +109,13 @@ public void onComplete() { final long duration = Duration.between(start, Instant.now()).getSeconds(); if (completed) { - logger.info("Pull complete. {} layers, pulled in {}s (downloaded {} at {}/s)", + logger.info( + "Pull complete. {} layers, pulled in {}s (downloaded {} at {}/s)", allLayers.size(), duration, - byteCountToDisplaySize(downloadedLayerSize), - byteCountToDisplaySize(downloadedLayerSize / duration)); + FileUtils.byteCountToDisplaySize(downloadedLayerSize), + FileUtils.byteCountToDisplaySize(downloadedLayerSize / duration) + ); } } diff --git a/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java b/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java index d4574d17c34..ed88c1a85ff 100644 --- a/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/ParsedDockerfile.java @@ -21,7 +21,10 @@ @Slf4j public class ParsedDockerfile { - private static final Pattern FROM_LINE_PATTERN = Pattern.compile("FROM (?--[^\\s]+\\s)*(?[^\\s]+).*", Pattern.CASE_INSENSITIVE); + private static final Pattern FROM_LINE_PATTERN = Pattern.compile( + "FROM (?--[^\\s]+\\s)*(?[^\\s]+).*", + Pattern.CASE_INSENSITIVE + ); private final Path dockerFilePath; @@ -54,11 +57,13 @@ private List read() { } private void parse(List lines) { - dependencyImageNames = lines.stream() - .map(FROM_LINE_PATTERN::matcher) - .filter(Matcher::matches) - .map(matcher -> matcher.group("image")) - .collect(Collectors.toSet()); + dependencyImageNames = + lines + .stream() + .map(FROM_LINE_PATTERN::matcher) + .filter(Matcher::matches) + .map(matcher -> matcher.group("image")) + .collect(Collectors.toSet()); if (!dependencyImageNames.isEmpty()) { log.debug("Found dependency images in Dockerfile {}: {}", dockerFilePath, dependencyImageNames); diff --git a/core/src/main/java/org/testcontainers/images/PullPolicy.java b/core/src/main/java/org/testcontainers/images/PullPolicy.java index 3dc2e452b8d..a8b8344a8c2 100644 --- a/core/src/main/java/org/testcontainers/images/PullPolicy.java +++ b/core/src/main/java/org/testcontainers/images/PullPolicy.java @@ -1,9 +1,9 @@ package org.testcontainers.images; -import java.time.Duration; - import lombok.experimental.UtilityClass; +import java.time.Duration; + /** * Convenience class with logic for building common {@link ImagePullPolicy} instances. * @@ -34,5 +34,4 @@ public static ImagePullPolicy alwaysPull() { public static ImagePullPolicy ageBased(Duration maxAge) { return new AgeBasedPullPolicy(maxAge); } - } diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index 3bf2243549a..7dbd7adec0b 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -62,7 +62,7 @@ public RemoteDockerImage(@NonNull Future imageFuture) { } @Override - @SneakyThrows({InterruptedException.class, ExecutionException.class}) + @SneakyThrows({ InterruptedException.class, ExecutionException.class }) protected final String resolve() { final DockerImageName imageName = getImageName(); Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); @@ -72,7 +72,10 @@ protected final String resolve() { } // The image is not available locally - pull it - logger.info("Pulling docker image: {}. Please be patient; this may take some time but only needs to be done once.", imageName); + logger.info( + "Pulling docker image: {}. Please be patient; this may take some time but only needs to be done once.", + imageName + ); Exception lastFailure = null; final Instant lastRetryAllowed = Instant.now().plus(PULL_RETRY_TIME_LIMIT); @@ -84,9 +87,7 @@ protected final String resolve() { .withTag(imageName.getVersionPart()); try { - pullImageCmd - .exec(new TimeLimitedLoggedPullImageResultCallback(logger)) - .awaitCompletion(); + pullImageCmd.exec(new TimeLimitedLoggedPullImageResultCallback(logger)).awaitCompletion(); } catch (DockerClientException e) { // Try to fallback to x86 pullImageCmd @@ -101,12 +102,19 @@ protected final String resolve() { } catch (InterruptedException | InternalServerErrorException e) { // these classes of exception often relate to timeout/connection errors so should be retried lastFailure = e; - logger.warn("Retrying pull for image: {} ({}s remaining)", + logger.warn( + "Retrying pull for image: {} ({}s remaining)", imageName, - Duration.between(Instant.now(), lastRetryAllowed).getSeconds()); + Duration.between(Instant.now(), lastRetryAllowed).getSeconds() + ); } } - logger.error("Failed to pull image: {}. Please check output of `docker pull {}`", imageName, imageName, lastFailure); + logger.error( + "Failed to pull image: {}. Please check output of `docker pull {}`", + imageName, + imageName, + lastFailure + ); throw new ContainerFetchException("Failed to pull image: " + imageName, lastFailure); } catch (DockerClientException e) { diff --git a/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java index b6d8539c3e8..88b8804dd8a 100644 --- a/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java +++ b/core/src/main/java/org/testcontainers/images/TimeLimitedLoggedPullImageResultCallback.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.model.PullResponseItem; import org.slf4j.Logger; +import org.testcontainers.DockerClientFactory; import org.testcontainers.utility.TestcontainersConfiguration; import java.io.Closeable; @@ -16,8 +17,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static org.testcontainers.DockerClientFactory.TESTCONTAINERS_THREAD_GROUP; - /** * {@link PullImageResultCallback} with improved logging of pull progress and a 'watchdog' which will abort the pull * if progress is not being made, to prevent a hanging test @@ -25,14 +24,21 @@ public class TimeLimitedLoggedPullImageResultCallback extends LoggedPullImageResultCallback { private static final AtomicInteger THREAD_ID = new AtomicInteger(0); - private static final ScheduledExecutorService PROGRESS_WATCHDOG_EXECUTOR = - Executors.newScheduledThreadPool(0, runnable -> { - Thread t = new Thread(TESTCONTAINERS_THREAD_GROUP, runnable); + + private static final ScheduledExecutorService PROGRESS_WATCHDOG_EXECUTOR = Executors.newScheduledThreadPool( + 0, + runnable -> { + Thread t = new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, runnable); t.setDaemon(true); t.setName("testcontainers-pull-watchdog-" + THREAD_ID.incrementAndGet()); return t; - }); - private static final Duration PULL_PAUSE_TOLERANCE = Duration.ofSeconds(TestcontainersConfiguration.getInstance().getImagePullPauseTimeout()); + } + ); + + private static final Duration PULL_PAUSE_TOLERANCE = Duration.ofSeconds( + TestcontainersConfiguration.getInstance().getImagePullPauseTimeout() + ); + private final Logger logger; // A future which, if it ever fires, will kill the pull @@ -85,27 +91,30 @@ public void onComplete() { super.onComplete(); } - /* * This method schedules a future task which will interrupt the waiting waiting threads if ever fired. * Every time this method is called (from onStart or onNext), the task is cancelled and recreated 30s in the future, * ensuring that it will only fire if the method stops being called regularly (e.g. if the pull has hung). */ private void resetProgressWatchdog(boolean isFinished) { - if (nextCheckForProgress != null && ! nextCheckForProgress.isCancelled()) { + if (nextCheckForProgress != null && !nextCheckForProgress.isCancelled()) { nextCheckForProgress.cancel(false); } if (!isFinished) { - nextCheckForProgress = PROGRESS_WATCHDOG_EXECUTOR.schedule( - this::abortPull, - PULL_PAUSE_TOLERANCE.getSeconds(), - TimeUnit.SECONDS - ); + nextCheckForProgress = + PROGRESS_WATCHDOG_EXECUTOR.schedule( + this::abortPull, + PULL_PAUSE_TOLERANCE.getSeconds(), + TimeUnit.SECONDS + ); } } private void abortPull() { - logger.error("Docker image pull has not made progress in {}s - aborting pull", PULL_PAUSE_TOLERANCE.getSeconds()); + logger.error( + "Docker image pull has not made progress in {}s - aborting pull", + PULL_PAUSE_TOLERANCE.getSeconds() + ); // Interrupt any threads that are waiting, before closing streams, because the stream can take // an indeterminate amount of time to close waitingThreads.forEach(Thread::interrupt); diff --git a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java index 000487bfa4d..201cf0fd058 100644 --- a/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java +++ b/core/src/main/java/org/testcontainers/images/builder/ImageFromDockerfile.java @@ -39,7 +39,9 @@ @Slf4j @Getter -public class ImageFromDockerfile extends LazyFuture implements +public class ImageFromDockerfile + extends LazyFuture + implements BuildContextBuilderTrait, ClasspathTrait, FilesTrait, @@ -51,9 +53,13 @@ public class ImageFromDockerfile extends LazyFuture implements private boolean deleteOnExit = true; private final Map transferables = new HashMap<>(); + private final Map buildArgs = new HashMap<>(); + private Optional dockerFilePath = Optional.empty(); + private Optional dockerfile = Optional.empty(); + private Set dependencyImageNames = Collections.emptySet(); public ImageFromDockerfile() { @@ -87,7 +93,6 @@ protected final String resolve() { DockerClient dockerClient = DockerClientFactory.instance().client(); try { - BuildImageResultCallback resultCallback = new BuildImageResultCallback() { @Override public void onNext(BuildResponseItem item) { @@ -102,8 +107,10 @@ public void onNext(BuildResponseItem item) { }; // We have to use pipes to avoid high memory consumption since users might want to build really big images - @Cleanup PipedInputStream in = new PipedInputStream(); - @Cleanup PipedOutputStream out = new PipedOutputStream(in); + @Cleanup + PipedInputStream in = new PipedInputStream(); + @Cleanup + PipedOutputStream out = new PipedOutputStream(in); BuildImageCmd buildImageCmd = dockerClient.buildImageCmd(in); configure(buildImageCmd); @@ -140,14 +147,17 @@ public void onNext(BuildResponseItem item) { } log.info("Transferred {} to Docker daemon", FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); - if (bytesToDockerDaemon > FileUtils.ONE_MB * 50) // warn if >50MB sent to docker daemon - log.warn("A large amount of data was sent to the Docker daemon ({}). Consider using a .dockerignore file for better performance.", - FileUtils.byteCountToDisplaySize(bytesToDockerDaemon)); + if (bytesToDockerDaemon > FileUtils.ONE_MB * 50) { + log.warn( // warn if >50MB sent to docker daemon + "A large amount of data was sent to the Docker daemon ({}). Consider using a .dockerignore file for better performance.", + FileUtils.byteCountToDisplaySize(bytesToDockerDaemon) + ); + } exec.awaitImageId(); return dockerImageName; - } catch(IOException e) { + } catch (IOException e) { throw new RuntimeException("Can't close DockerClient", e); } } @@ -156,15 +166,15 @@ protected void configure(BuildImageCmd buildImageCmd) { buildImageCmd.withTag(this.getDockerImageName()); this.dockerFilePath.ifPresent(buildImageCmd::withDockerfilePath); this.dockerfile.ifPresent(p -> { - buildImageCmd.withDockerfile(p.toFile()); - dependencyImageNames = new ParsedDockerfile(p).getDependencyImageNames(); + buildImageCmd.withDockerfile(p.toFile()); + dependencyImageNames = new ParsedDockerfile(p).getDependencyImageNames(); - if (dependencyImageNames.size() > 0) { - // if we'll be pre-pulling images, disable the built-in pull as it is not necessary and will fail for - // authenticated registries - buildImageCmd.withPull(false); - } - }); + if (dependencyImageNames.size() > 0) { + // if we'll be pre-pulling images, disable the built-in pull as it is not necessary and will fail for + // authenticated registries + buildImageCmd.withPull(false); + } + }); this.buildArgs.forEach(buildImageCmd::withBuildArg); } @@ -174,12 +184,19 @@ private void prePullDependencyImages(Set imagesToPull) { imagesToPull.forEach(imageName -> { try { - log.info("Pre-emptively checking local images for '{}', referenced via a Dockerfile. If not available, it will be pulled.", imageName); + log.info( + "Pre-emptively checking local images for '{}', referenced via a Dockerfile. If not available, it will be pulled.", + imageName + ); new RemoteDockerImage(DockerImageName.parse(imageName)) .withImageNameSubstitutor(ImageNameSubstitutor.noop()) .get(); } catch (Exception e) { - log.warn("Unable to pre-fetch an image ({}) depended upon by Dockerfile - image build will continue but may fail. Exception message was: {}", imageName, e.getMessage()); + log.warn( + "Unable to pre-fetch an image ({}) depended upon by Dockerfile - image build will continue but may fail. Exception message was: {}", + imageName, + e.getMessage() + ); } }); } @@ -218,5 +235,4 @@ public ImageFromDockerfile withDockerfile(Path dockerfile) { this.dockerfile = Optional.of(dockerfile); return this; } - } diff --git a/core/src/main/java/org/testcontainers/images/builder/Transferable.java b/core/src/main/java/org/testcontainers/images/builder/Transferable.java index 8ec26c8c3da..e98dbc2ad11 100644 --- a/core/src/main/java/org/testcontainers/images/builder/Transferable.java +++ b/core/src/main/java/org/testcontainers/images/builder/Transferable.java @@ -9,7 +9,6 @@ import java.util.zip.Checksum; public interface Transferable { - int DEFAULT_FILE_MODE = 0100644; int DEFAULT_DIR_MODE = 040755; diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/DockerfileBuilder.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/DockerfileBuilder.java index 17b13b3bac0..0ce794e778f 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/DockerfileBuilder.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/DockerfileBuilder.java @@ -10,7 +10,9 @@ @Data @Slf4j -public class DockerfileBuilder implements DockerfileBuilderTrait, +public class DockerfileBuilder + implements + DockerfileBuilderTrait, FromStatementTrait, AddStatementTrait, CopyStatementTrait, @@ -27,7 +29,6 @@ public class DockerfileBuilder implements DockerfileBuilderTrait statements = new ArrayList<>(); public String build() { - StringBuilder builder = new StringBuilder(); for (Statement statement : statements) { diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/statement/Statement.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/statement/Statement.java index b36811a974d..2b9b005a579 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/statement/Statement.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/statement/Statement.java @@ -7,5 +7,5 @@ public abstract class Statement { final String type; - abstract public void appendArguments(StringBuilder dockerfileStringBuilder); + public abstract void appendArguments(StringBuilder dockerfileStringBuilder); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/AddStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/AddStatementTrait.java index 44a35d68ba2..85b6b9ad6ea 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/AddStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/AddStatementTrait.java @@ -3,7 +3,6 @@ import org.testcontainers.images.builder.dockerfile.statement.MultiArgsStatement; public interface AddStatementTrait & DockerfileBuilderTrait> { - default SELF add(String source, String destination) { return ((SELF) this).withStatement(new MultiArgsStatement("ADD", source, destination)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CmdStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CmdStatementTrait.java index 054656af4d1..c9cc93c96c1 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CmdStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CmdStatementTrait.java @@ -4,7 +4,6 @@ import org.testcontainers.images.builder.dockerfile.statement.SingleArgumentStatement; public interface CmdStatementTrait & DockerfileBuilderTrait> { - default SELF cmd(String command) { return ((SELF) this).withStatement(new SingleArgumentStatement("CMD", command)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CopyStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CopyStatementTrait.java index 03e0cc7b461..0bdb2ef29ab 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CopyStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/CopyStatementTrait.java @@ -3,7 +3,6 @@ import org.testcontainers.images.builder.dockerfile.statement.MultiArgsStatement; public interface CopyStatementTrait & DockerfileBuilderTrait> { - default SELF copy(String source, String destination) { return ((SELF) this).withStatement(new MultiArgsStatement("COPY", source, destination)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/DockerfileBuilderTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/DockerfileBuilderTrait.java index 7a422da27d5..5fdc74ce1de 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/DockerfileBuilderTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/DockerfileBuilderTrait.java @@ -5,7 +5,6 @@ import java.util.List; public interface DockerfileBuilderTrait> { - List getStatements(); default SELF withStatement(Statement statement) { diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EntryPointStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EntryPointStatementTrait.java index c974e58e384..79a6e6315a0 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EntryPointStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EntryPointStatementTrait.java @@ -4,7 +4,6 @@ import org.testcontainers.images.builder.dockerfile.statement.SingleArgumentStatement; public interface EntryPointStatementTrait & DockerfileBuilderTrait> { - default SELF entryPoint(String command) { return ((SELF) this).withStatement(new SingleArgumentStatement("ENTRYPOINT", command)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EnvStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EnvStatementTrait.java index b02c8e71ec7..c1380304a34 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EnvStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/EnvStatementTrait.java @@ -6,7 +6,6 @@ import java.util.Map; public interface EnvStatementTrait & DockerfileBuilderTrait> { - default SELF env(String key, String value) { return env(Collections.singletonMap(key, value)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/ExposeStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/ExposeStatementTrait.java index bebe243c8de..22dcbeee32b 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/ExposeStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/ExposeStatementTrait.java @@ -6,8 +6,12 @@ import java.util.stream.Stream; public interface ExposeStatementTrait & DockerfileBuilderTrait> { - default SELF expose(Integer... ports) { - return ((SELF) this).withStatement(new SingleArgumentStatement("EXPOSE", Stream.of(ports).map(Object::toString).collect(Collectors.joining(" ")))); + return ((SELF) this).withStatement( + new SingleArgumentStatement( + "EXPOSE", + Stream.of(ports).map(Object::toString).collect(Collectors.joining(" ")) + ) + ); } } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java index 07077259df8..1ea411d206e 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/FromStatementTrait.java @@ -4,7 +4,6 @@ import org.testcontainers.utility.DockerImageName; public interface FromStatementTrait & DockerfileBuilderTrait> { - default SELF from(String dockerImageName) { DockerImageName.parse(dockerImageName).assertValid(); diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/LabelStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/LabelStatementTrait.java index 0b423453b33..4ed527051dd 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/LabelStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/LabelStatementTrait.java @@ -6,7 +6,6 @@ import java.util.Map; public interface LabelStatementTrait & DockerfileBuilderTrait> { - default SELF label(String key, String value) { return label(Collections.singletonMap(key, value)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/RunStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/RunStatementTrait.java index 74dfe1b00ab..f8fb064fb32 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/RunStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/RunStatementTrait.java @@ -4,7 +4,6 @@ import org.testcontainers.images.builder.dockerfile.statement.SingleArgumentStatement; public interface RunStatementTrait & DockerfileBuilderTrait> { - default SELF run(String... commandParts) { return ((SELF) this).withStatement(new MultiArgsStatement("RUN", commandParts)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/UserStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/UserStatementTrait.java index 57419ad7c5d..ca44d2d03be 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/UserStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/UserStatementTrait.java @@ -3,7 +3,6 @@ import org.testcontainers.images.builder.dockerfile.statement.SingleArgumentStatement; public interface UserStatementTrait & DockerfileBuilderTrait> { - default SELF user(String user) { return ((SELF) this).withStatement(new SingleArgumentStatement("USER", user)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/VolumeStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/VolumeStatementTrait.java index 2709adf32da..a8cd8621ee6 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/VolumeStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/VolumeStatementTrait.java @@ -3,7 +3,6 @@ import org.testcontainers.images.builder.dockerfile.statement.MultiArgsStatement; public interface VolumeStatementTrait & DockerfileBuilderTrait> { - default SELF volume(String... volumes) { return ((SELF) this).withStatement(new MultiArgsStatement("VOLUME", volumes)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/WorkdirStatementTrait.java b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/WorkdirStatementTrait.java index c4fd5386af8..ea2aaa1412c 100644 --- a/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/WorkdirStatementTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/dockerfile/traits/WorkdirStatementTrait.java @@ -3,7 +3,6 @@ import org.testcontainers.images.builder.dockerfile.statement.SingleArgumentStatement; public interface WorkdirStatementTrait & DockerfileBuilderTrait> { - default SELF workDir(String workdir) { return ((SELF) this).withStatement(new SingleArgumentStatement("WORKDIR", workdir)); } diff --git a/core/src/main/java/org/testcontainers/images/builder/traits/BuildContextBuilderTrait.java b/core/src/main/java/org/testcontainers/images/builder/traits/BuildContextBuilderTrait.java index 5ddee327cee..74ddf68b365 100644 --- a/core/src/main/java/org/testcontainers/images/builder/traits/BuildContextBuilderTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/traits/BuildContextBuilderTrait.java @@ -7,6 +7,5 @@ * */ public interface BuildContextBuilderTrait> { - SELF withFileFromTransferable(String path, Transferable transferable); } diff --git a/core/src/main/java/org/testcontainers/images/builder/traits/ClasspathTrait.java b/core/src/main/java/org/testcontainers/images/builder/traits/ClasspathTrait.java index 5617365f2cd..aadc3ccf7b9 100644 --- a/core/src/main/java/org/testcontainers/images/builder/traits/ClasspathTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/traits/ClasspathTrait.java @@ -9,7 +9,6 @@ * */ public interface ClasspathTrait & BuildContextBuilderTrait & FilesTrait> { - default SELF withFileFromClasspath(String path, String resourcePath) { final MountableFile mountableFile = MountableFile.forClasspathResource(resourcePath); diff --git a/core/src/main/java/org/testcontainers/images/builder/traits/DockerfileTrait.java b/core/src/main/java/org/testcontainers/images/builder/traits/DockerfileTrait.java index 07ed13ed0fb..293b76a7c5c 100644 --- a/core/src/main/java/org/testcontainers/images/builder/traits/DockerfileTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/traits/DockerfileTrait.java @@ -10,29 +10,31 @@ * BuildContextBuilder's trait for Dockerfile-based resources. * */ -public interface DockerfileTrait & BuildContextBuilderTrait & StringsTrait> { - +public interface DockerfileTrait< + SELF extends DockerfileTrait & BuildContextBuilderTrait & StringsTrait +> { default SELF withDockerfileFromBuilder(Consumer builderConsumer) { - DockerfileBuilder builder = new DockerfileBuilder(); builderConsumer.accept(builder); // return Transferable because we want to build Dockerfile's content lazily - return ((SELF) this).withFileFromTransferable("Dockerfile", new Transferable() { - - @Getter(lazy = true) - private final byte[] bytes = builder.build().getBytes(); - - @Override - public long getSize() { - return getBytes().length; - } - - @Override - public String getDescription() { - return "Dockerfile: " + builder; - } - }); + return ((SELF) this).withFileFromTransferable( + "Dockerfile", + new Transferable() { + @Getter(lazy = true) + private final byte[] bytes = builder.build().getBytes(); + + @Override + public long getSize() { + return getBytes().length; + } + + @Override + public String getDescription() { + return "Dockerfile: " + builder; + } + } + ); } } diff --git a/core/src/main/java/org/testcontainers/images/builder/traits/FilesTrait.java b/core/src/main/java/org/testcontainers/images/builder/traits/FilesTrait.java index 61524b59f8a..4c1204f752a 100644 --- a/core/src/main/java/org/testcontainers/images/builder/traits/FilesTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/traits/FilesTrait.java @@ -10,7 +10,6 @@ * */ public interface FilesTrait & BuildContextBuilderTrait> { - /** * Adds file to tarball copied into container. * @param path in tarball diff --git a/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java b/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java index 2b23551ee58..68de3d67c14 100644 --- a/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java +++ b/core/src/main/java/org/testcontainers/images/builder/traits/StringsTrait.java @@ -9,22 +9,23 @@ * */ public interface StringsTrait & BuildContextBuilderTrait> { - default SELF withFileFromString(String path, String content) { - return ((SELF) this).withFileFromTransferable(path, new Transferable() { - - @Getter - byte[] bytes = content.getBytes(); + return ((SELF) this).withFileFromTransferable( + path, + new Transferable() { + @Getter + byte[] bytes = content.getBytes(); - @Override - public long getSize() { - return bytes.length; - } + @Override + public long getSize() { + return bytes.length; + } - @Override - public String getDescription() { - return "String: " + StringUtils.abbreviate(content, 100); - } - }); + @Override + public String getDescription() { + return "String: " + StringUtils.abbreviate(content, 100); + } + } + ); } } diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startable.java b/core/src/main/java/org/testcontainers/lifecycle/Startable.java index 3e73968d06e..2ffa423d2e3 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/Startable.java +++ b/core/src/main/java/org/testcontainers/lifecycle/Startable.java @@ -4,7 +4,6 @@ import java.util.Set; public interface Startable extends AutoCloseable { - default Set getDependencies() { return Collections.emptySet(); } diff --git a/core/src/main/java/org/testcontainers/lifecycle/Startables.java b/core/src/main/java/org/testcontainers/lifecycle/Startables.java index 5ec46f1edb9..daa63931a88 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/Startables.java +++ b/core/src/main/java/org/testcontainers/lifecycle/Startables.java @@ -1,8 +1,8 @@ package org.testcontainers.lifecycle; -import java.util.Arrays; import lombok.experimental.UtilityClass; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -17,17 +17,18 @@ @UtilityClass public class Startables { - private static final Executor EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() { - - private final AtomicLong COUNTER = new AtomicLong(0); + private static final Executor EXECUTOR = Executors.newCachedThreadPool( + new ThreadFactory() { + private final AtomicLong COUNTER = new AtomicLong(0); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, "testcontainers-lifecycle-" + COUNTER.getAndIncrement()); - thread.setDaemon(true); - return thread; + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "testcontainers-lifecycle-" + COUNTER.getAndIncrement()); + thread.setDaemon(true); + return thread; + } } - }); + ); /** * @see #deepStart(Stream) @@ -77,15 +78,22 @@ public CompletableFuture deepStart(Stream startables) * @param started an intermediate storage for already started {@link Startable}s to prevent multiple starts. * @param startables a {@link Stream} of {@link Startable}s to start and scan for transitive dependencies. */ - private CompletableFuture deepStart(Map> started, Stream startables) { + private CompletableFuture deepStart( + Map> started, + Stream startables + ) { CompletableFuture[] futures = startables .sequential() .map(it -> { // avoid a recursive update in `computeIfAbsent` Map> subStarted = new HashMap<>(started); - CompletableFuture future = started.computeIfAbsent(it, startable -> { - return deepStart(subStarted, startable.getDependencies().stream()).thenRunAsync(startable::start, EXECUTOR); - }); + CompletableFuture future = started.computeIfAbsent( + it, + startable -> { + return deepStart(subStarted, startable.getDependencies().stream()) + .thenRunAsync(startable::start, EXECUTOR); + } + ); started.putAll(subStarted); return future; }) diff --git a/core/src/main/java/org/testcontainers/lifecycle/TestDescription.java b/core/src/main/java/org/testcontainers/lifecycle/TestDescription.java index c27f59fb0fc..3787707509a 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/TestDescription.java +++ b/core/src/main/java/org/testcontainers/lifecycle/TestDescription.java @@ -1,7 +1,6 @@ package org.testcontainers.lifecycle; public interface TestDescription { - String getTestId(); String getFilesystemFriendlyName(); diff --git a/core/src/main/java/org/testcontainers/lifecycle/TestLifecycleAware.java b/core/src/main/java/org/testcontainers/lifecycle/TestLifecycleAware.java index 178e081c083..1e5a0258f14 100644 --- a/core/src/main/java/org/testcontainers/lifecycle/TestLifecycleAware.java +++ b/core/src/main/java/org/testcontainers/lifecycle/TestLifecycleAware.java @@ -3,12 +3,7 @@ import java.util.Optional; public interface TestLifecycleAware { + default void beforeTest(TestDescription description) {} - default void beforeTest(TestDescription description) { - - } - - default void afterTest(TestDescription description, Optional throwable) { - - } + default void afterTest(TestDescription description, Optional throwable) {} } diff --git a/core/src/main/java/org/testcontainers/utility/AuditLogger.java b/core/src/main/java/org/testcontainers/utility/AuditLogger.java index f6c4559485d..518144c4302 100644 --- a/core/src/main/java/org/testcontainers/utility/AuditLogger.java +++ b/core/src/main/java/org/testcontainers/utility/AuditLogger.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.command.DockerCmd; +import com.google.common.base.Strings; import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -12,8 +13,6 @@ import java.util.List; -import static com.google.common.base.Strings.nullToEmpty; - /** * Logger for tracking potentially destructive actions, intended for usage in a shared Docker environment where * traceability is needed. This class uses SLF4J, logging at TRACE level and capturing common fields as MDC fields. @@ -26,34 +25,36 @@ public class AuditLogger { private static final ObjectMapper objectMapper = new ObjectMapper(); - public static final String MDC_PREFIX = AuditLogger.class.getCanonicalName(); - public static void doLog(@NotNull String action, - @Nullable String image, - @Nullable String containerId, - @NotNull DockerCmd cmd) { + public static final String MDC_PREFIX = AuditLogger.class.getCanonicalName(); + public static void doLog( + @NotNull String action, + @Nullable String image, + @Nullable String containerId, + @NotNull DockerCmd cmd + ) { doLog(action, image, containerId, cmd, null); } - public static void doLog(@NotNull String action, - @Nullable String image, - @Nullable String containerId, - @NotNull DockerCmd cmd, - @Nullable Exception e) { - - if (! log.isTraceEnabled()) { + public static void doLog( + @NotNull String action, + @Nullable String image, + @Nullable String containerId, + @NotNull DockerCmd cmd, + @Nullable Exception e + ) { + if (!log.isTraceEnabled()) { return; } - MDC.put(MDC_PREFIX + ".Action", nullToEmpty(action)); - MDC.put(MDC_PREFIX + ".Image", nullToEmpty(image)); - MDC.put(MDC_PREFIX + ".ContainerId", nullToEmpty(containerId)); + MDC.put(MDC_PREFIX + ".Action", Strings.nullToEmpty(action)); + MDC.put(MDC_PREFIX + ".Image", Strings.nullToEmpty(image)); + MDC.put(MDC_PREFIX + ".ContainerId", Strings.nullToEmpty(containerId)); try { MDC.put(MDC_PREFIX + ".Command", objectMapper.writeValueAsString(cmd)); - } catch (JsonProcessingException ignored) { - } + } catch (JsonProcessingException ignored) {} if (e != null) { MDC.put(MDC_PREFIX + ".Exception", e.getLocalizedMessage()); @@ -69,10 +70,8 @@ public static void doLog(@NotNull String action, MDC.remove(MDC_PREFIX + ".Exception"); } - public static void doComposeLog(@NotNull String[] commandParts, - @Nullable List env) { - - if (! log.isTraceEnabled()) { + public static void doComposeLog(@NotNull String[] commandParts, @Nullable List env) { + if (!log.isTraceEnabled()) { return; } diff --git a/core/src/main/java/org/testcontainers/utility/AuthConfigUtil.java b/core/src/main/java/org/testcontainers/utility/AuthConfigUtil.java index 77b670d374b..8ed91a5e34e 100644 --- a/core/src/main/java/org/testcontainers/utility/AuthConfigUtil.java +++ b/core/src/main/java/org/testcontainers/utility/AuthConfigUtil.java @@ -2,22 +2,23 @@ import com.github.dockerjava.api.model.AuthConfig; import com.google.common.base.MoreObjects; +import com.google.common.base.Strings; import lombok.experimental.UtilityClass; import org.jetbrains.annotations.NotNull; -import static com.google.common.base.Strings.isNullOrEmpty; - /** * TODO: Javadocs */ @UtilityClass public class AuthConfigUtil { + public static String toSafeString(AuthConfig authConfig) { if (authConfig == null) { return "null"; } - return MoreObjects.toStringHelper(authConfig) + return MoreObjects + .toStringHelper(authConfig) .add("username", authConfig.getUsername()) .add("password", obfuscated(authConfig.getPassword())) .add("auth", obfuscated(authConfig.getAuth())) @@ -29,6 +30,6 @@ public static String toSafeString(AuthConfig authConfig) { @NotNull private static String obfuscated(String value) { - return isNullOrEmpty(value) ? "blank" : "hidden non-blank value"; + return Strings.isNullOrEmpty(value) ? "blank" : "hidden non-blank value"; } } diff --git a/core/src/main/java/org/testcontainers/utility/Base58.java b/core/src/main/java/org/testcontainers/utility/Base58.java index 1f56978c7cc..2cbfc751f4d 100644 --- a/core/src/main/java/org/testcontainers/utility/Base58.java +++ b/core/src/main/java/org/testcontainers/utility/Base58.java @@ -7,8 +7,7 @@ */ public class Base58 { - private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" - .toCharArray(); + private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); private static final SecureRandom RANDOM = new SecureRandom(); diff --git a/core/src/main/java/org/testcontainers/utility/ClasspathScanner.java b/core/src/main/java/org/testcontainers/utility/ClasspathScanner.java index 76716cfdb7c..0c8addc2874 100644 --- a/core/src/main/java/org/testcontainers/utility/ClasspathScanner.java +++ b/core/src/main/java/org/testcontainers/utility/ClasspathScanner.java @@ -40,11 +40,7 @@ private static Integer filesFileSchemeFirst(final URL t) { * context classloader. Results are currently alphabetically sorted. */ static Stream scanFor(final String name) { - return scanFor( - name, - ClasspathScanner.class.getClassLoader(), - Thread.currentThread().getContextClassLoader() - ); + return scanFor(name, ClasspathScanner.class.getClassLoader(), Thread.currentThread().getContextClassLoader()); } @Nullable diff --git a/core/src/main/java/org/testcontainers/utility/CommandLine.java b/core/src/main/java/org/testcontainers/utility/CommandLine.java index a217823c40f..1bb8f827148 100644 --- a/core/src/main/java/org/testcontainers/utility/CommandLine.java +++ b/core/src/main/java/org/testcontainers/utility/CommandLine.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.zeroturnaround.exec.InvalidExitValueException; import org.zeroturnaround.exec.ProcessExecutor; import org.zeroturnaround.exec.ProcessResult; @@ -14,14 +15,12 @@ import java.util.concurrent.TimeoutException; import java.util.regex.Pattern; -import static org.slf4j.LoggerFactory.getLogger; - /** * Process execution utility methods. */ public class CommandLine { - private static final Logger LOGGER = getLogger(CommandLine.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CommandLine.class); /** * Run a shell command synchronously. @@ -30,16 +29,11 @@ public class CommandLine { * @return the stdout output of the command */ public static String runShellCommand(String... command) { - String joinedCommand = String.join(" ", command); LOGGER.debug("Executing shell command: `{}`", joinedCommand); try { - ProcessResult result = new ProcessExecutor() - .command(command) - .readOutput(true) - .exitValueNormal() - .execute(); + ProcessResult result = new ProcessExecutor().command(command).readOutput(true).exitValueNormal().execute(); return result.outputUTF8().trim(); } catch (IOException | InterruptedException | TimeoutException | InvalidExitValueException e) { @@ -55,7 +49,6 @@ public static String runShellCommand(String... command) { * @return whether the executable exists and is executable */ public static boolean executableExists(String executable) { - // First check if we've been given the full path already File directFile = new File(executable); if (directFile.exists() && directFile.canExecute()) { @@ -78,6 +71,7 @@ public static String[] getSystemPath() { } private static class ShellCommandException extends RuntimeException { + public ShellCommandException(String message, Exception e) { super(message, e); } diff --git a/core/src/main/java/org/testcontainers/utility/ComparableVersion.java b/core/src/main/java/org/testcontainers/utility/ComparableVersion.java index d3e3d9eb958..999c4b40b3b 100644 --- a/core/src/main/java/org/testcontainers/utility/ComparableVersion.java +++ b/core/src/main/java/org/testcontainers/utility/ComparableVersion.java @@ -1,12 +1,11 @@ package org.testcontainers.utility; -import java.util.ArrayList; -import java.util.List; - import com.google.common.annotations.VisibleForTesting; - import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + public final class ComparableVersion implements Comparable { private final int[] parts; @@ -19,7 +18,7 @@ public ComparableVersion(String version) { @Override public int compareTo(@NotNull ComparableVersion other) { - for (int i=0; i otherPart) { @@ -71,5 +70,4 @@ static int[] parseVersion(final String version) { return ret; } - } diff --git a/core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java index 530d5a76118..ee7ab1d95b6 100644 --- a/core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java +++ b/core/src/main/java/org/testcontainers/utility/ConfigurationFileImageNameSubstitutor.java @@ -28,7 +28,8 @@ public DockerImageName apply(final DockerImageName original) { .asCompatibleSubstituteFor(original); if (!result.equals(original)) { - log.warn("Image name {} was substituted by configuration to {}. This approach is deprecated and will be removed in the future", + log.warn( + "Image name {} was substituted by configuration to {}. This approach is deprecated and will be removed in the future", original, result ); diff --git a/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java index 840b8a77b40..a7755f8eea8 100644 --- a/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java +++ b/core/src/main/java/org/testcontainers/utility/DefaultImageNameSubstitutor.java @@ -11,6 +11,7 @@ final class DefaultImageNameSubstitutor extends ImageNameSubstitutor { private final ConfigurationFileImageNameSubstitutor configurationFileImageNameSubstitutor; + private final PrefixingImageNameSubstitutor prefixingImageNameSubstitutor; public DefaultImageNameSubstitutor() { @@ -29,13 +30,17 @@ public DefaultImageNameSubstitutor() { @Override public DockerImageName apply(final DockerImageName original) { - return configurationFileImageNameSubstitutor - .andThen(prefixingImageNameSubstitutor) - .apply(original); + return configurationFileImageNameSubstitutor.andThen(prefixingImageNameSubstitutor).apply(original); } @Override protected String getDescription() { - return "DefaultImageNameSubstitutor (composite of '" + configurationFileImageNameSubstitutor.getDescription() + "' and '" + prefixingImageNameSubstitutor.getDescription() + "')"; + return ( + "DefaultImageNameSubstitutor (composite of '" + + configurationFileImageNameSubstitutor.getDescription() + + "' and '" + + prefixingImageNameSubstitutor.getDescription() + + "')" + ); } } diff --git a/core/src/main/java/org/testcontainers/utility/DockerImageName.java b/core/src/main/java/org/testcontainers/utility/DockerImageName.java index b9d266a41ca..9fca02aad6f 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerImageName.java +++ b/core/src/main/java/org/testcontainers/utility/DockerImageName.java @@ -1,6 +1,5 @@ package org.testcontainers.utility; - import com.google.common.net.HostAndPort; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -20,16 +19,29 @@ public final class DockerImageName { /* Regex patterns used for validation */ private static final String ALPHA_NUMERIC = "[a-z0-9]+"; + private static final String SEPARATOR = "([.]|_{1,2}|-+)"; + private static final String REPO_NAME_PART = ALPHA_NUMERIC + "(" + SEPARATOR + ALPHA_NUMERIC + ")*"; + private static final Pattern REPO_NAME = Pattern.compile(REPO_NAME_PART + "(/" + REPO_NAME_PART + ")*"); private final String rawName; - @With @Getter private final String registry; - @With @Getter private final String repository; - @NotNull @With(AccessLevel.PRIVATE) + + @With + @Getter + private final String registry; + + @With + @Getter + private final String repository; + + @NotNull + @With(AccessLevel.PRIVATE) private final Versioning versioning; - @Nullable @With(AccessLevel.PRIVATE) + + @Nullable + @With(AccessLevel.PRIVATE) private final DockerImageName compatibleSubstituteFor; /** @@ -57,10 +69,14 @@ public DockerImageName(String fullImageName) { final int slashIndex = fullImageName.indexOf('/'); String remoteName; - if (slashIndex == -1 || - (!fullImageName.substring(0, slashIndex).contains(".") && + if ( + slashIndex == -1 || + ( + !fullImageName.substring(0, slashIndex).contains(".") && !fullImageName.substring(0, slashIndex).contains(":") && - !fullImageName.substring(0, slashIndex).equals("localhost"))) { + !fullImageName.substring(0, slashIndex).equals("localhost") + ) + ) { registry = ""; remoteName = fullImageName; } else { @@ -99,10 +115,14 @@ public DockerImageName(String nameWithoutTag, @NotNull String version) { final int slashIndex = nameWithoutTag.indexOf('/'); String remoteName; - if (slashIndex == -1 || - (!nameWithoutTag.substring(0, slashIndex).contains(".") && + if ( + slashIndex == -1 || + ( + !nameWithoutTag.substring(0, slashIndex).contains(".") && !nameWithoutTag.substring(0, slashIndex).contains(":") && - !nameWithoutTag.substring(0, slashIndex).equals("localhost"))) { + !nameWithoutTag.substring(0, slashIndex).equals("localhost") + ) + ) { registry = ""; remoteName = nameWithoutTag; } else { @@ -163,7 +183,9 @@ public void assertValid() { throw new IllegalArgumentException(repository + " is not a valid Docker image name (in " + rawName + ")"); } if (!versioning.isValid()) { - throw new IllegalArgumentException(versioning + " is not a valid image versioning identifier (in " + rawName + ")"); + throw new IllegalArgumentException( + versioning + " is not a valid image versioning identifier (in " + rawName + ")" + ); } } @@ -246,18 +268,16 @@ public void assertCompatibleWith(DockerImageName... anyOthers) { throw new IllegalStateException( String.format( - "Failed to verify that image '%s' is a compatible substitute for '%s'. This generally means that " - + - "you are trying to use an image that Testcontainers has not been designed to use. If this is " - + - "deliberate, and if you are confident that the image is compatible, you should declare " - + - "compatibility in code using the `asCompatibleSubstituteFor` method. For example:\n" - + - " DockerImageName myImage = DockerImageName.parse(\"%s\").asCompatibleSubstituteFor(\"%s\");\n" - + - "and then use `myImage` instead.", - this.rawName, exampleOther.rawName, this.rawName, exampleOther.rawName + "Failed to verify that image '%s' is a compatible substitute for '%s'. This generally means that " + + "you are trying to use an image that Testcontainers has not been designed to use. If this is " + + "deliberate, and if you are confident that the image is compatible, you should declare " + + "compatibility in code using the `asCompatibleSubstituteFor` method. For example:\n" + + " DockerImageName myImage = DockerImageName.parse(\"%s\").asCompatibleSubstituteFor(\"%s\");\n" + + "and then use `myImage` instead.", + this.rawName, + exampleOther.rawName, + this.rawName, + exampleOther.rawName ) ); } diff --git a/core/src/main/java/org/testcontainers/utility/DockerLoggerFactory.java b/core/src/main/java/org/testcontainers/utility/DockerLoggerFactory.java index 69f7b998da2..c372c3cea3e 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerLoggerFactory.java +++ b/core/src/main/java/org/testcontainers/utility/DockerLoggerFactory.java @@ -9,7 +9,6 @@ public final class DockerLoggerFactory { public static Logger getLogger(String dockerImageName) { - final String abbreviatedName; if (dockerImageName.contains("@sha256")) { abbreviatedName = dockerImageName.substring(0, dockerImageName.indexOf("@sha256") + 14) + "..."; diff --git a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java index 6f1e2c9d50b..1a2b4aafe74 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java +++ b/core/src/main/java/org/testcontainers/utility/DockerMachineClient.java @@ -3,44 +3,42 @@ import lombok.NonNull; import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Arrays; import java.util.List; import java.util.Optional; -import static java.util.Arrays.asList; -import static org.slf4j.LoggerFactory.getLogger; -import static org.testcontainers.utility.CommandLine.executableExists; -import static org.testcontainers.utility.CommandLine.runShellCommand; - /** * Created by rnorth on 27/10/2015. */ public class DockerMachineClient { private static DockerMachineClient instance; - private static final Logger LOGGER = getLogger(DockerMachineClient.class); + + private static final Logger LOGGER = LoggerFactory.getLogger(DockerMachineClient.class); private static final String executableName; + static { - if(SystemUtils.IS_OS_WINDOWS) { - executableName = "docker-machine.exe"; - } else { - executableName = "docker-machine"; - } + if (SystemUtils.IS_OS_WINDOWS) { + executableName = "docker-machine.exe"; + } else { + executableName = "docker-machine"; + } } /** * Private constructor */ - private DockerMachineClient() { - } + private DockerMachineClient() {} /** * Obtain an instance of the DockerMachineClient wrapper. * * @return the singleton instance of DockerMachineClient */ - public synchronized static DockerMachineClient instance() { + public static synchronized DockerMachineClient instance() { if (instance == null) { instance = new DockerMachineClient(); } @@ -49,12 +47,12 @@ public synchronized static DockerMachineClient instance() { } public boolean isInstalled() { - return executableExists(executableName); + return CommandLine.executableExists(executableName); } public Optional getDefaultMachine() { - String ls = runShellCommand(executableName, "ls", "-q"); - List machineNames = asList(ls.split("\n")); + String ls = CommandLine.runShellCommand(executableName, "ls", "-q"); + List machineNames = Arrays.asList(ls.split("\n")); String envMachineName = System.getenv("DOCKER_MACHINE_NAME"); @@ -65,7 +63,10 @@ public Optional getDefaultMachine() { LOGGER.debug("DOCKER_MACHINE_NAME is not set; Using 'default' docker-machine", envMachineName); return Optional.of("default"); } else if (machineNames.size() > 0) { - LOGGER.debug("DOCKER_MACHINE_NAME is not set and no machine named 'default' found; Using first machine found with `docker-machine ls`: {}", machineNames.get(0)); + LOGGER.debug( + "DOCKER_MACHINE_NAME is not set and no machine named 'default' found; Using first machine found with `docker-machine ls`: {}", + machineNames.get(0) + ); return Optional.of(machineNames.get(0)); } else { return Optional.empty(); @@ -75,7 +76,7 @@ public Optional getDefaultMachine() { public void ensureMachineRunning(@NonNull String machineName) { if (!isMachineRunning(machineName)) { LOGGER.info("Docker-machine '{}' is not running. Will start it now", machineName); - runShellCommand("docker-machine", "start", machineName); + CommandLine.runShellCommand("docker-machine", "start", machineName); } } @@ -84,15 +85,15 @@ public void ensureMachineRunning(@NonNull String machineName) { */ @Deprecated public String getDockerDaemonIpAddress(@NonNull String machineName) { - return runShellCommand(executableName, "ip", machineName); + return CommandLine.runShellCommand(executableName, "ip", machineName); } public String getDockerDaemonUrl(@NonNull String machineName) { - return runShellCommand(executableName, "url", machineName); + return CommandLine.runShellCommand(executableName, "url", machineName); } public boolean isMachineRunning(String machineName) { - String status = runShellCommand("docker-machine", "status", machineName); + String status = CommandLine.runShellCommand("docker-machine", "status", machineName); return status.trim().equalsIgnoreCase("running"); } diff --git a/core/src/main/java/org/testcontainers/utility/DockerStatus.java b/core/src/main/java/org/testcontainers/utility/DockerStatus.java index a410597dcfb..00f71249dd1 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerStatus.java +++ b/core/src/main/java/org/testcontainers/utility/DockerStatus.java @@ -33,15 +33,16 @@ public class DockerStatus { * @param now the time to consider as the current time * @return true if we can conclude that the container is running, false otherwise */ - public static boolean isContainerRunning(InspectContainerResponse.ContainerState state, - Duration minimumRunningDuration, - Instant now) { + public static boolean isContainerRunning( + InspectContainerResponse.ContainerState state, + Duration minimumRunningDuration, + Instant now + ) { if (state.getRunning()) { if (minimumRunningDuration == null) { return true; } - Instant startedAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse( - state.getStartedAt(), Instant::from); + Instant startedAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(state.getStartedAt(), Instant::from); if (startedAt.isBefore(now.minus(minimumRunningDuration))) { return true; @@ -57,7 +58,6 @@ public static boolean isContainerRunning(InspectContainerResponse.ContainerState * @return true if we can conclude that the container has started but is now stopped, false otherwise. */ public static boolean isContainerStopped(InspectContainerResponse.ContainerState state) { - // get some preconditions out of the way if (state.getRunning() || state.getPaused()) { return false; @@ -72,10 +72,12 @@ public static boolean isContainerStopped(InspectContainerResponse.ContainerState public static boolean isDockerTimestampNonEmpty(String dockerTimestamp) { // This is a defensive approach. Current versions of Docker use the DOCKER_TIMESTAMP_ZERO value, but // that could change. - return dockerTimestamp != null - && !dockerTimestamp.isEmpty() - && !dockerTimestamp.equals(DOCKER_TIMESTAMP_ZERO) - && DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(dockerTimestamp, Instant::from).getEpochSecond() >= 0L; + return ( + dockerTimestamp != null && + !dockerTimestamp.isEmpty() && + !dockerTimestamp.equals(DOCKER_TIMESTAMP_ZERO) && + DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(dockerTimestamp, Instant::from).getEpochSecond() >= 0L + ); } public static boolean isContainerExitCodeSuccess(InspectContainerResponse.ContainerState state) { diff --git a/core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java b/core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java index 1252fb2c3a1..043befe04bb 100644 --- a/core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java +++ b/core/src/main/java/org/testcontainers/utility/DynamicPollInterval.java @@ -15,6 +15,7 @@ public class DynamicPollInterval implements PollInterval { final Duration interval; + Instant lastTimestamp; private DynamicPollInterval(Duration interval) { diff --git a/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java index a1cb2492204..dae3f178230 100644 --- a/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java +++ b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java @@ -24,7 +24,7 @@ public abstract class ImageNameSubstitutor implements Function> filters) { - String[] labels = filters.stream() + String[] labels = filters + .stream() .filter(it -> "label".equals(it.getKey())) .map(Map.Entry::getValue) .toArray(String[]::new); switch (pruneType) { // Docker only prunes stopped containers, so we have to do it manually case CONTAINERS: - List containers = dockerClient.listContainersCmd() + List containers = dockerClient + .listContainersCmd() .withFilter("label", Arrays.asList(labels)) .withShowAll(true) .exec(); - containers.parallelStream().forEach(container -> { - dockerClient.removeContainerCmd(container.getId()) - .withForce(true) - .withRemoveVolumes(true) - .exec(); - }); + containers + .parallelStream() + .forEach(container -> { + dockerClient + .removeContainerCmd(container.getId()) + .withForce(true) + .withRemoveVolumes(true) + .exec(); + }); break; default: dockerClient.pruneCmd(pruneType).withLabelFilter(labels).exec(); diff --git a/core/src/main/java/org/testcontainers/utility/LazyFuture.java b/core/src/main/java/org/testcontainers/utility/LazyFuture.java index 758082f5185..bde9feb69ec 100644 --- a/core/src/main/java/org/testcontainers/utility/LazyFuture.java +++ b/core/src/main/java/org/testcontainers/utility/LazyFuture.java @@ -17,7 +17,7 @@ public abstract class LazyFuture implements Future { @Getter(value = AccessLevel.MODULE, lazy = true) private final T resolvedValue = resolve(); - abstract protected T resolve(); + protected abstract T resolve(); @Override public boolean cancel(boolean mayInterruptIfRunning) { diff --git a/core/src/main/java/org/testcontainers/utility/LicenseAcceptance.java b/core/src/main/java/org/testcontainers/utility/LicenseAcceptance.java index 55037d8978c..9fe8d9db8e6 100644 --- a/core/src/main/java/org/testcontainers/utility/LicenseAcceptance.java +++ b/core/src/main/java/org/testcontainers/utility/LicenseAcceptance.java @@ -27,10 +27,17 @@ public static void assertLicenseAccepted(final String imageName) { // suppressed } - throw new IllegalStateException("The image " + imageName + " requires you to accept a license agreement. " + - "Please place a file at the root of the classpath named " + ACCEPTANCE_FILE_NAME + ", e.g. at " + - "src/test/resources/" + ACCEPTANCE_FILE_NAME + ". This file should contain the line:\n " + - imageName); - + throw new IllegalStateException( + "The image " + + imageName + + " requires you to accept a license agreement. " + + "Please place a file at the root of the classpath named " + + ACCEPTANCE_FILE_NAME + + ", e.g. at " + + "src/test/resources/" + + ACCEPTANCE_FILE_NAME + + ". This file should contain the line:\n " + + imageName + ); } } diff --git a/core/src/main/java/org/testcontainers/utility/LogUtils.java b/core/src/main/java/org/testcontainers/utility/LogUtils.java index ce27387490f..e5912563cd9 100644 --- a/core/src/main/java/org/testcontainers/utility/LogUtils.java +++ b/core/src/main/java/org/testcontainers/utility/LogUtils.java @@ -13,9 +13,6 @@ import java.io.IOException; import java.util.function.Consumer; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; - /** * Provides utility methods for logging. */ @@ -31,11 +28,12 @@ public class LogUtils { * @param consumer a consumer of {@link OutputFrame}s * @param types types of {@link OutputFrame} to receive */ - public void followOutput(DockerClient dockerClient, - String containerId, - Consumer consumer, - OutputFrame.OutputType... types) { - + public void followOutput( + DockerClient dockerClient, + String containerId, + Consumer consumer, + OutputFrame.OutputType... types + ) { attachConsumer(dockerClient, containerId, consumer, true, types); } @@ -47,11 +45,8 @@ public void followOutput(DockerClient dockerClient, * @param containerId container ID to attach to * @param consumer a consumer of {@link OutputFrame}s */ - public void followOutput(DockerClient dockerClient, - String containerId, - Consumer consumer) { - - followOutput(dockerClient, containerId, consumer, STDOUT, STDERR); + public void followOutput(DockerClient dockerClient, String containerId, Consumer consumer) { + followOutput(dockerClient, containerId, consumer, OutputFrame.OutputType.STDOUT, OutputFrame.OutputType.STDERR); } /** @@ -63,16 +58,13 @@ public void followOutput(DockerClient dockerClient, * @return all previous output frames (stdout/stderr being separated by newline characters) */ @SneakyThrows(IOException.class) - public String getOutput(DockerClient dockerClient, - String containerId, - OutputFrame.OutputType... types) { - + public String getOutput(DockerClient dockerClient, String containerId, OutputFrame.OutputType... types) { if (containerId == null) { return ""; } if (types.length == 0) { - types = new OutputFrame.OutputType[] { STDOUT, STDERR }; + types = new OutputFrame.OutputType[] { OutputFrame.OutputType.STDOUT, OutputFrame.OutputType.STDERR }; } final ToStringConsumer consumer = new ToStringConsumer(); @@ -90,16 +82,20 @@ private static Closeable attachConsumer( boolean followStream, OutputFrame.OutputType... types ) { - - final LogContainerCmd cmd = dockerClient.logContainerCmd(containerId) + final LogContainerCmd cmd = dockerClient + .logContainerCmd(containerId) .withFollowStream(followStream) .withSince(0); final FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); for (OutputFrame.OutputType type : types) { callback.addConsumer(type, consumer); - if (type == STDOUT) cmd.withStdOut(true); - if (type == STDERR) cmd.withStdErr(true); + if (type == OutputFrame.OutputType.STDOUT) { + cmd.withStdOut(true); + } + if (type == OutputFrame.OutputType.STDERR) { + cmd.withStdErr(true); + } } return cmd.exec(callback); diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index 81cc37adeab..a8a9f465a19 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -1,7 +1,7 @@ package org.testcontainers.utility; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; +import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -34,23 +34,24 @@ import java.util.stream.Stream; import java.util.zip.Checksum; -import static lombok.AccessLevel.PACKAGE; -import static org.testcontainers.utility.PathUtils.recursiveDeleteDir; - /** * An abstraction over files and classpath resources aimed at encapsulating all the complexity of generating * a path that the Docker daemon is about to create a volume mount for. */ -@RequiredArgsConstructor(access = PACKAGE) +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) @Slf4j public class MountableFile implements Transferable { private static final String TESTCONTAINERS_TMP_DIR_PREFIX = ".testcontainers-tmp-"; + private static final String OS_MAC_TMP_DIR = "/tmp"; + private static final int BASE_FILE_MODE = 0100000; + private static final int BASE_DIR_MODE = 0040000; private final String path; + private final Integer forcedFileMode; @Getter(lazy = true) @@ -124,10 +125,11 @@ public static MountableFile forHostPath(final Path path, Integer mode) { return new MountableFile(path.toAbsolutePath().toString(), mode); } - @NotNull - private static URL getClasspathResource(@NotNull final String resourcePath, @NotNull final Set classLoaders) { - + private static URL getClasspathResource( + @NotNull final String resourcePath, + @NotNull final Set classLoaders + ) { final Set classLoadersToSearch = new HashSet<>(classLoaders); // try context and system classloaders as well classLoadersToSearch.add(Thread.currentThread().getContextClassLoader()); @@ -153,16 +155,22 @@ private static URL getClasspathResource(@NotNull final String resourcePath, @Not } } - throw new IllegalArgumentException("Resource with path " + resourcePath + " could not be found on any of these classloaders: " + classLoadersToSearch); + throw new IllegalArgumentException( + "Resource with path " + + resourcePath + + " could not be found on any of these classloaders: " + + classLoadersToSearch + ); } private static String unencodeResourceURIToFilePath(@NotNull final String resource) { try { // Convert any url-encoded characters (e.g. spaces) back into unencoded form - return URLDecoder.decode(resource.replaceAll("\\+", "%2B"), Charsets.UTF_8.name()) - .replaceFirst("jar:", "") - .replaceFirst("file:", "") - .replaceAll("!.*", ""); + return URLDecoder + .decode(resource.replaceAll("\\+", "%2B"), Charsets.UTF_8.name()) + .replaceFirst("jar:", "") + .replaceFirst("file:", "") + .replaceAll("!.*", ""); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } @@ -237,15 +245,19 @@ private String extractClassPathResourceToTempLocation(final String hostPath) { JarEntry entry = entries.nextElement(); final String name = entry.getName(); if (name.startsWith(internalPath)) { - log.debug("Copying classpath resource(s) from {} to {} to permit Docker to bind", - hostPath, - tmpLocation); + log.debug( + "Copying classpath resource(s) from {} to {} to permit Docker to bind", + hostPath, + tmpLocation + ); copyFromJarToLocation(jarFile, entry, internalPath, tmpLocation); } } - } catch (IOException e) { - throw new IllegalStateException("Failed to process JAR file when extracting classpath resource: " + hostPath, e); + throw new IllegalStateException( + "Failed to process JAR file when extracting classpath resource: " + hostPath, + e + ); } // Mark temporary files/dirs for deletion at JVM shutdown @@ -264,23 +276,22 @@ private File createTempDirectory() { return Files.createTempDirectory(Paths.get(OS_MAC_TMP_DIR), TESTCONTAINERS_TMP_DIR_PREFIX).toFile(); } return Files.createTempDirectory(TESTCONTAINERS_TMP_DIR_PREFIX).toFile(); - } catch (IOException e) { + } catch (IOException e) { return new File(TESTCONTAINERS_TMP_DIR_PREFIX + Base58.randomString(5)); } } @SuppressWarnings("ResultOfMethodCallIgnored") - private void copyFromJarToLocation(final JarFile jarFile, - final JarEntry entry, - final String fromRoot, - final File toRoot) throws IOException { - + private void copyFromJarToLocation( + final JarFile jarFile, + final JarEntry entry, + final String fromRoot, + final File toRoot + ) throws IOException { String destinationName = entry.getName().replaceFirst(fromRoot, ""); File newFile = new File(toRoot, destinationName); - log.debug("Copying resource {} from JAR file {}", - fromRoot, - jarFile.getName()); + log.debug("Copying resource {} from JAR file {}", fromRoot, jarFile.getName()); if (!entry.isDirectory()) { // Create parent directories @@ -291,14 +302,21 @@ private void copyFromJarToLocation(final JarFile jarFile, try (InputStream is = jarFile.getInputStream(entry)) { Files.copy(is, newFile.toPath()); } catch (IOException e) { - log.error("Failed to extract classpath resource " + entry.getName() + " from JAR file " + jarFile.getName(), e); + log.error( + "Failed to extract classpath resource " + entry.getName() + " from JAR file " + jarFile.getName(), + e + ); throw e; } } } private void deleteOnExit(final Path path) { - Runtime.getRuntime().addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> recursiveDeleteDir(path))); + Runtime + .getRuntime() + .addShutdownHook( + new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> PathUtils.recursiveDeleteDir(path)) + ); } /** @@ -312,11 +330,20 @@ public void transferTo(final TarArchiveOutputStream outputStream, String destina /* * Recursively copies a file/directory into a TarArchiveOutputStream */ - private void recursiveTar(String entryFilename, String rootPath, String itemPath, TarArchiveOutputStream tarArchive) { + private void recursiveTar( + String entryFilename, + String rootPath, + String itemPath, + TarArchiveOutputStream tarArchive + ) { try { - final File sourceFile = new File(itemPath).getCanonicalFile(); // e.g. /foo/bar/baz - final File sourceRootFile = new File(rootPath).getCanonicalFile(); // e.g. /foo - final String relativePathToSourceFile = sourceRootFile.toPath().relativize(sourceFile.toPath()).toFile().toString(); // e.g. /bar/baz + final File sourceFile = new File(itemPath).getCanonicalFile(); // e.g. /foo/bar/baz + final File sourceRootFile = new File(rootPath).getCanonicalFile(); // e.g. /foo + final String relativePathToSourceFile = sourceRootFile + .toPath() + .relativize(sourceFile.toPath()) + .toFile() + .toString(); // e.g. /bar/baz final String tarEntryFilename; if (relativePathToSourceFile.isEmpty()) { @@ -341,7 +368,12 @@ private void recursiveTar(String entryFilename, String rootPath, String itemPath if (children != null) { // recurse into child files/directories for (final File child : children) { - recursiveTar(entryFilename, sourceRootFile.getCanonicalPath(), child.getCanonicalPath(), tarArchive); + recursiveTar( + entryFilename, + sourceRootFile.getCanonicalPath(), + child.getCanonicalPath(), + tarArchive + ); } } } catch (IOException e) { @@ -352,7 +384,6 @@ private void recursiveTar(String entryFilename, String rootPath, String itemPath @Override public long getSize() { - final File file = new File(this.getResolvedPath()); if (file.isFile()) { return file.length(); @@ -378,9 +409,11 @@ private void checksumFile(File file, Checksum checksum) { checksum.update(MountableFile.getUnixFileMode(path)); if (file.isDirectory()) { try (Stream stream = Files.walk(path)) { - stream.filter(it -> it != path).forEach(it -> { - checksumFile(it.toFile(), checksum); - }); + stream + .filter(it -> it != path) + .forEach(it -> { + checksumFile(it.toFile(), checksum); + }); } } else { FileUtils.checksum(file, checksum); @@ -405,9 +438,11 @@ public static int getUnixFileMode(final Path path) { try { int unixMode = (int) Files.readAttributes(path, "unix:mode").get("mode"); // Truncate mode bits for z/OS - if ("OS/390".equals(SystemUtils.OS_NAME) || + if ( + "OS/390".equals(SystemUtils.OS_NAME) || "z/OS".equals(SystemUtils.OS_NAME) || - "zOS".equals(SystemUtils.OS_NAME) ) { + "zOS".equals(SystemUtils.OS_NAME) + ) { unixMode &= TarConstants.MAXID; unixMode |= Files.isDirectory(path) ? 040000 : 0100000; } diff --git a/core/src/main/java/org/testcontainers/utility/PathUtils.java b/core/src/main/java/org/testcontainers/utility/PathUtils.java index 2dcf9db8a8d..7f8b5925689 100644 --- a/core/src/main/java/org/testcontainers/utility/PathUtils.java +++ b/core/src/main/java/org/testcontainers/utility/PathUtils.java @@ -23,21 +23,23 @@ public class PathUtils { */ public static void recursiveDeleteDir(final @NonNull Path directory) { try { - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - Files.delete(dir); - return FileVisitResult.CONTINUE; - } + Files.walkFileTree( + directory, + new SimpleFileVisitor() { + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } } - }); - } catch (IOException ignored) { - } + ); + } catch (IOException ignored) {} } /** @@ -66,8 +68,10 @@ public static String createMinGWPath(String path) { } // drive-letter must be lower case - mingwPath = "//" + Character.toLowerCase(mingwPath.charAt(driveLetterIndex)) + - mingwPath.substring(driveLetterIndex + 1); + mingwPath = + "//" + + Character.toLowerCase(mingwPath.charAt(driveLetterIndex)) + + mingwPath.substring(driveLetterIndex + 1); mingwPath = mingwPath.replace(":", ""); return mingwPath; } diff --git a/core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java index c720416deac..7cf082000a4 100644 --- a/core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java +++ b/core/src/main/java/org/testcontainers/utility/PrefixingImageNameSubstitutor.java @@ -38,11 +38,7 @@ public DockerImageName apply(DockerImageName original) { return original; } - log.debug( - "Applying changes to image name {}: applying prefix '{}'", - original, - configuredPrefix - ); + log.debug("Applying changes to image name {}: applying prefix '{}'", original, configuredPrefix); DockerImageName prefixAsImage = DockerImageName.parse(configuredPrefix); diff --git a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java index e487bda686b..0001b926059 100644 --- a/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java +++ b/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java @@ -7,6 +7,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testcontainers.DockerClientFactory; import org.zeroturnaround.exec.InvalidResultException; import org.zeroturnaround.exec.ProcessExecutor; @@ -23,23 +24,23 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.slf4j.LoggerFactory.getLogger; -import static org.testcontainers.utility.AuthConfigUtil.toSafeString; - /** * Utility to look up registry authentication information for an image. */ public class RegistryAuthLocator { - private static final Logger log = getLogger(RegistryAuthLocator.class); + private static final Logger log = LoggerFactory.getLogger(RegistryAuthLocator.class); + private static final String DEFAULT_REGISTRY_NAME = "https://index.docker.io/v1/"; + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static RegistryAuthLocator instance; private final String commandPathPrefix; + private final String commandExtension; + private final File configFile; private final Map> cache = new ConcurrentHashMap<>(); @@ -51,8 +52,12 @@ public class RegistryAuthLocator { private final Map CREDENTIALS_HELPERS_NOT_FOUND_MESSAGE_CACHE; @VisibleForTesting - RegistryAuthLocator(File configFile, String commandPathPrefix, String commandExtension, - Map notFoundMessageHolderReference) { + RegistryAuthLocator( + File configFile, + String commandPathPrefix, + String commandExtension, + Map notFoundMessageHolderReference + ) { this.configFile = configFile; this.commandPathPrefix = commandPathPrefix; this.commandExtension = commandExtension; @@ -63,8 +68,9 @@ public class RegistryAuthLocator { /** */ protected RegistryAuthLocator() { - final String dockerConfigLocation = System.getenv().getOrDefault("DOCKER_CONFIG", - System.getProperty("user.home") + "/.docker"); + final String dockerConfigLocation = System + .getenv() + .getOrDefault("DOCKER_CONFIG", System.getProperty("user.home") + "/.docker"); this.configFile = new File(dockerConfigLocation + "/config.json"); this.commandPathPrefix = ""; this.commandExtension = ""; @@ -72,7 +78,7 @@ protected RegistryAuthLocator() { this.CREDENTIALS_HELPERS_NOT_FOUND_MESSAGE_CACHE = new HashMap<>(); } - public synchronized static RegistryAuthLocator instance() { + public static synchronized RegistryAuthLocator instance() { if (instance == null) { instance = new RegistryAuthLocator(); } @@ -106,23 +112,31 @@ public AuthConfig lookupAuthConfig(DockerImageName dockerImageName, AuthConfig d final String registryName = effectiveRegistryName(dockerImageName); log.debug("Looking up auth config for image: {} at registry: {}", dockerImageName, registryName); - final Optional cachedAuth = cache.computeIfAbsent(registryName, __ -> lookupUncachedAuthConfig(registryName, dockerImageName)); + final Optional cachedAuth = cache.computeIfAbsent( + registryName, + __ -> lookupUncachedAuthConfig(registryName, dockerImageName) + ); if (cachedAuth.isPresent()) { - log.debug("Cached auth found: [{}]", toSafeString(cachedAuth.get())); + log.debug("Cached auth found: [{}]", AuthConfigUtil.toSafeString(cachedAuth.get())); return cachedAuth.get(); } else { - log.debug("No matching Auth Configs - falling back to defaultAuthConfig [{}]", toSafeString(defaultAuthConfig)); + log.debug( + "No matching Auth Configs - falling back to defaultAuthConfig [{}]", + AuthConfigUtil.toSafeString(defaultAuthConfig) + ); // otherwise, defaultAuthConfig should already contain any credentials available return defaultAuthConfig; } } private Optional lookupUncachedAuthConfig(String registryName, DockerImageName dockerImageName) { - log.debug("RegistryAuthLocator has configFile: {} ({}) and commandPathPrefix: {}", + log.debug( + "RegistryAuthLocator has configFile: {} ({}) and commandPathPrefix: {}", configFile, configFile.exists() ? "exists" : "does not exist", - commandPathPrefix); + commandPathPrefix + ); try { final JsonNode config = OBJECT_MAPPER.readTree(configFile); @@ -131,32 +145,33 @@ private Optional lookupUncachedAuthConfig(String registryName, Docke // use helper preferentially (per https://docs.docker.com/engine/reference/commandline/cli/) final AuthConfig helperAuthConfig = authConfigUsingHelper(config, registryName); if (helperAuthConfig != null) { - log.debug("found helper auth config [{}]", toSafeString(helperAuthConfig)); + log.debug("found helper auth config [{}]", AuthConfigUtil.toSafeString(helperAuthConfig)); return Optional.of(helperAuthConfig); } // no credsHelper to use, using credsStore: final AuthConfig storeAuthConfig = authConfigUsingStore(config, registryName); if (storeAuthConfig != null) { - log.debug("found creds store auth config [{}]", toSafeString(storeAuthConfig)); + log.debug("found creds store auth config [{}]", AuthConfigUtil.toSafeString(storeAuthConfig)); return Optional.of(storeAuthConfig); } // fall back to base64 encoded auth hardcoded in config file final AuthConfig existingAuthConfig = findExistingAuthConfig(config, registryName); if (existingAuthConfig != null) { - log.debug("found existing auth config [{}]", toSafeString(existingAuthConfig)); + log.debug("found existing auth config [{}]", AuthConfigUtil.toSafeString(existingAuthConfig)); return Optional.of(existingAuthConfig); } } catch (Exception e) { - log.info("Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: {}, configFile: {}. Falling back to docker-java default behaviour. Exception message: {}", + log.info( + "Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: {}, configFile: {}. Falling back to docker-java default behaviour. Exception message: {}", dockerImageName, configFile, - e.getMessage()); + e.getMessage() + ); } return Optional.empty(); } private AuthConfig findExistingAuthConfig(final JsonNode config, final String reposName) throws Exception { - final Map.Entry entry = findAuthNode(config, reposName); if (entry != null && entry.getValue() != null && entry.getValue().size() > 0) { @@ -164,10 +179,11 @@ private AuthConfig findExistingAuthConfig(final JsonNode config, final String re .treeToValue(entry.getValue(), AuthConfig.class) .withRegistryAddress(entry.getKey()); - if (isBlank(deserializedAuth.getUsername()) && - isBlank(deserializedAuth.getPassword()) && - !isBlank(deserializedAuth.getAuth())) { - + if ( + StringUtils.isBlank(deserializedAuth.getUsername()) && + StringUtils.isBlank(deserializedAuth.getPassword()) && + !StringUtils.isBlank(deserializedAuth.getAuth()) + ) { final String rawAuth = new String(Base64.getDecoder().decode(deserializedAuth.getAuth())); final String[] splitRawAuth = rawAuth.split(":", 2); @@ -198,7 +214,7 @@ private AuthConfig authConfigUsingStore(final JsonNode config, final String repo final JsonNode credsStoreNode = config.get("credsStore"); if (credsStoreNode != null && !credsStoreNode.isMissingNode() && credsStoreNode.isTextual()) { final String credsStore = credsStoreNode.asText(); - if (isBlank(credsStore)) { + if (StringUtils.isBlank(credsStore)) { log.warn("Docker auth config credsStore field will be ignored, because value is blank"); return null; } @@ -222,8 +238,7 @@ private Map.Entry findAuthNode(final JsonNode config, final St } private AuthConfig runCredentialProvider(String hostName, String helperOrStoreName) throws Exception { - - if (isBlank(hostName)) { + if (StringUtils.isBlank(hostName)) { log.debug("There is no point in locating AuthConfig for blank hostName. Returning NULL to allow fallback"); return null; } @@ -231,28 +246,34 @@ private AuthConfig runCredentialProvider(String hostName, String helperOrStoreNa final String credentialProgramName = getCredentialProgramName(helperOrStoreName); final String data; - log.debug("Executing docker credential provider: {} to locate auth config for: {}", - credentialProgramName, hostName); + log.debug( + "Executing docker credential provider: {} to locate auth config for: {}", + credentialProgramName, + hostName + ); try { data = runCredentialProgram(hostName, credentialProgramName); } catch (InvalidResultException e) { - final String responseErrorMsg = extractCredentialProviderErrorMessage(e); - if (!isBlank(responseErrorMsg)) { + if (!StringUtils.isBlank(responseErrorMsg)) { String credentialsNotFoundMsg = getGenericCredentialsNotFoundMsg(credentialProgramName); if (credentialsNotFoundMsg != null && credentialsNotFoundMsg.equals(responseErrorMsg)) { - log.info("Credential helper/store ({}) does not have credentials for {}", + log.info( + "Credential helper/store ({}) does not have credentials for {}", credentialProgramName, - hostName); + hostName + ); return null; } - log.debug("Failure running docker credential helper/store ({}) with output '{}'", - credentialProgramName, responseErrorMsg); - + log.debug( + "Failure running docker credential helper/store ({}) with output '{}'", + credentialProgramName, + responseErrorMsg + ); } else { log.debug("Failure running docker credential helper/store ({})", credentialProgramName); } @@ -296,7 +317,7 @@ private String effectiveRegistryName(DockerImageName dockerImageName) { private String getGenericCredentialsNotFoundMsg(String credentialHelperName) { if (!CREDENTIALS_HELPERS_NOT_FOUND_MESSAGE_CACHE.containsKey(credentialHelperName)) { String credentialsNotFoundMsg = discoverCredentialsHelperNotFoundMessage(credentialHelperName); - if (!isBlank(credentialsNotFoundMsg)) { + if (!StringUtils.isBlank(credentialsNotFoundMsg)) { CREDENTIALS_HELPERS_NOT_FOUND_MESSAGE_CACHE.put(credentialHelperName, credentialsNotFoundMsg); } } @@ -317,19 +338,26 @@ private String discoverCredentialsHelperNotFoundMessage(String credentialHelperN runCredentialProgram(notExistentFakeHostName, credentialHelperName); // should not reach here - log.warn("Failure running docker credential helper ({}) with fake call, expected 'credentials not found' response", - credentialHelperName); - } catch(Exception e) { + log.warn( + "Failure running docker credential helper ({}) with fake call, expected 'credentials not found' response", + credentialHelperName + ); + } catch (Exception e) { if (e instanceof InvalidResultException) { - credentialsNotFoundMsg = extractCredentialProviderErrorMessage((InvalidResultException)e); + credentialsNotFoundMsg = extractCredentialProviderErrorMessage((InvalidResultException) e); } - if (isBlank(credentialsNotFoundMsg)) { - log.warn("Failure running docker credential helper ({}) with fake call, expected 'credentials not found' response. Exception message: {}", + if (StringUtils.isBlank(credentialsNotFoundMsg)) { + log.warn( + "Failure running docker credential helper ({}) with fake call, expected 'credentials not found' response. Exception message: {}", credentialHelperName, - e.getMessage()); + e.getMessage() + ); } else { - log.debug("Got credentials not found error message from docker credential helper - {}", credentialsNotFoundMsg); + log.debug( + "Got credentials not found error message from docker credential helper - {}", + credentialsNotFoundMsg + ); } } @@ -345,16 +373,17 @@ private String extractCredentialProviderErrorMessage(InvalidResultException inva private String runCredentialProgram(String hostName, String credentialHelperName) throws InvalidResultException, InterruptedException, TimeoutException, IOException { - - String[] command = SystemUtils.IS_OS_WINDOWS ? new String[] {"cmd", "/c", credentialHelperName, "get"} : new String[]{credentialHelperName, "get"}; + String[] command = SystemUtils.IS_OS_WINDOWS + ? new String[] { "cmd", "/c", credentialHelperName, "get" } + : new String[] { credentialHelperName, "get" }; return new ProcessExecutor() - .command(command) - .redirectInput(new ByteArrayInputStream(hostName.getBytes())) - .readOutput(true) - .exitValueNormal() - .timeout(30, TimeUnit.SECONDS) - .execute() - .outputUTF8() - .trim(); + .command(command) + .redirectInput(new ByteArrayInputStream(hostName.getBytes())) + .readOutput(true) + .exitValueNormal() + .timeout(30, TimeUnit.SECONDS) + .execute() + .outputUTF8() + .trim(); } } diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index d916579db35..ad0c949f6e7 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -49,29 +49,30 @@ public class ResourceReaper { static final List>> DEATH_NOTE = new ArrayList<>( Arrays.asList( Stream - .concat( - DockerClientFactory.DEFAULT_LABELS.entrySet().stream(), - MARKER_LABELS.entrySet().stream() - ) + .concat(DockerClientFactory.DEFAULT_LABELS.entrySet().stream(), MARKER_LABELS.entrySet().stream()) .>map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())) .collect(Collectors.toList()) ) ); private static ResourceReaper instance; + final DockerClient dockerClient = DockerClientFactory.lazyClient(); + private Map registeredContainers = new ConcurrentHashMap<>(); + private Set registeredNetworks = Sets.newConcurrentHashSet(); + private Set registeredImages = Sets.newConcurrentHashSet(); + private AtomicBoolean hookIsSet = new AtomicBoolean(false); /** * Internal constructor to avoid custom implementations */ - ResourceReaper() { - } + ResourceReaper() {} - public synchronized static ResourceReaper instance() { + public static synchronized ResourceReaper instance() { if (instance == null) { boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); if (useRyuk) { @@ -117,7 +118,9 @@ public void registerFilterForCleanup(List> filter) { */ public void registerLabelsFilterForCleanup(Map labels) { registerFilterForCleanup( - labels.entrySet().stream() + labels + .entrySet() + .stream() .map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())) .collect(Collectors.toList()) ); @@ -172,9 +175,11 @@ private void removeContainer(String containerId, String imageName) { LOGGER.trace("Was going to stop container but it apparently no longer exists: {}", containerId); return; } catch (Exception e) { - LOGGER.trace("Error encountered when checking container for shutdown (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", + LOGGER.trace( + "Error encountered when checking container for shutdown (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", containerId, - Throwables.getRootCause(e).getMessage()); + Throwables.getRootCause(e).getMessage() + ); return; } @@ -184,9 +189,11 @@ private void removeContainer(String containerId, String imageName) { dockerClient.killContainerCmd(containerId).exec(); LOGGER.trace("Stopped container: {}", imageName); } catch (Exception e) { - LOGGER.trace("Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", + LOGGER.trace( + "Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", containerId, - Throwables.getRootCause(e).getMessage()); + Throwables.getRootCause(e).getMessage() + ); } } @@ -202,9 +209,11 @@ private void removeContainer(String containerId, String imageName) { dockerClient.removeContainerCmd(containerId).withRemoveVolumes(true).withForce(true).exec(); LOGGER.debug("Removed container and associated volume(s): {}", imageName); } catch (Exception e) { - LOGGER.trace("Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", + LOGGER.trace( + "Error encountered shutting down container (ID: {}) - it may not have been stopped, or may already be stopped. Root cause: {}", containerId, - Throwables.getRootCause(e).getMessage()); + Throwables.getRootCause(e).getMessage() + ); } } @@ -227,10 +236,9 @@ public void registerNetworkIdForCleanup(String id) { */ @Deprecated public void removeNetworkById(String id) { - removeNetwork(id); + removeNetwork(id); } - private void removeNetwork(String id) { try { List networks; @@ -239,7 +247,10 @@ private void removeNetwork(String id) { // Listing by ID first prevents docker-java logging an error if we just go blindly into removeNetworkCmd networks = dockerClient.listNetworksCmd().withIdFilter(id).exec(); } catch (Exception e) { - LOGGER.trace("Error encountered when looking up network for removal (name: {}) - it may not have been removed", id); + LOGGER.trace( + "Error encountered when looking up network for removal (name: {}) - it may not have been removed", + id + ); return; } @@ -251,7 +262,10 @@ private void removeNetwork(String id) { registeredNetworks.remove(network.getId()); LOGGER.debug("Removed network: {}", id); } catch (Exception e) { - LOGGER.trace("Error encountered removing network (name: {}) - it may not have been removed", network.getName()); + LOGGER.trace( + "Error encountered removing network (name: {}) - it may not have been removed", + network.getName() + ); } } } finally { @@ -296,7 +310,9 @@ private void removeImage(String dockerImageName) { void setHook() { if (hookIsSet.compareAndSet(false, true)) { // If the JVM stops without containers being stopped, try and stop the container. - Runtime.getRuntime().addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, this::performCleanup)); + Runtime + .getRuntime() + .addShutdownHook(new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, this::performCleanup)); } } @@ -323,8 +339,7 @@ public CreateContainerCmd register(GenericContainer container, CreateContaine * @deprecated internal API */ @Deprecated - public void init() { - } + public void init() {} static class FilterRegistry { @@ -332,6 +347,7 @@ static class FilterRegistry { static final String ACKNOWLEDGMENT = "ACK"; private final BufferedReader in; + private final OutputStream out; FilterRegistry(InputStream ryukInputStream, OutputStream ryukOutputStream) { @@ -347,10 +363,13 @@ static class FilterRegistry { * @throws IOException if communication with Ryuk fails */ protected boolean register(List> filters) throws IOException { - String query = filters.stream() + String query = filters + .stream() .map(it -> { try { - return URLEncoder.encode(it.getKey(), "UTF-8") + "=" + URLEncoder.encode(it.getValue(), "UTF-8"); + return ( + URLEncoder.encode(it.getKey(), "UTF-8") + "=" + URLEncoder.encode(it.getValue(), "UTF-8") + ); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } @@ -372,6 +391,5 @@ private static boolean waitForAcknowledgment(BufferedReader in) throws IOExcepti } return ACKNOWLEDGMENT.equalsIgnoreCase(line); } - } } diff --git a/core/src/main/java/org/testcontainers/utility/RyukContainer.java b/core/src/main/java/org/testcontainers/utility/RyukContainer.java index 1e18c14157a..511e6ccac17 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukContainer.java +++ b/core/src/main/java/org/testcontainers/utility/RyukContainer.java @@ -10,15 +10,20 @@ class RyukContainer extends GenericContainer { RyukContainer() { super("testcontainers/ryuk:0.3.3"); - withExposedPorts(8080); withCreateContainerCmdModifier(cmd -> { cmd.withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID); cmd.withHostConfig( - cmd.getHostConfig() + cmd + .getHostConfig() .withAutoRemove(true) .withPrivileged(TestcontainersConfiguration.getInstance().isRyukPrivileged()) - .withBinds(new Bind(DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), new Volume("/var/run/docker.sock"))) + .withBinds( + new Bind( + DockerClientFactory.instance().getRemoteDockerUnixSocketPath(), + new Volume("/var/run/docker.sock") + ) + ) ); }); diff --git a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java index 6ce9c372fd2..999b1cbbffb 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java @@ -90,7 +90,10 @@ private synchronized void maybeStart() { // not set the read timeout, as Ryuk would not send anything unless a new filter is submitted, meaning that we would get a timeout exception pretty quick try (Socket clientSocket = new Socket()) { clientSocket.connect(new InetSocketAddress(host, ryukPort), 5 * 1000); - ResourceReaper.FilterRegistry registry = new ResourceReaper.FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); + ResourceReaper.FilterRegistry registry = new ResourceReaper.FilterRegistry( + clientSocket.getInputStream(), + clientSocket.getOutputStream() + ); synchronized (ResourceReaper.DEATH_NOTE) { while (true) { diff --git a/core/src/main/java/org/testcontainers/utility/TestEnvironment.java b/core/src/main/java/org/testcontainers/utility/TestEnvironment.java index dbd8e45a98f..ee58199540b 100644 --- a/core/src/main/java/org/testcontainers/utility/TestEnvironment.java +++ b/core/src/main/java/org/testcontainers/utility/TestEnvironment.java @@ -8,8 +8,7 @@ */ public class TestEnvironment { - private TestEnvironment() { - } + private TestEnvironment() {} public static boolean dockerApiAtLeast(String minimumVersion) { ComparableVersion min = new ComparableVersion(minimumVersion); @@ -29,4 +28,3 @@ public static boolean dockerIsDockerMachine() { return DockerClientFactory.instance().isUsing(DockerMachineClientProviderStrategy.class); } } - diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index c9dfd543ad6..e647a8d50b3 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -50,18 +50,29 @@ public class TestcontainersConfiguration { private static File USER_CONFIG_FILE = new File(System.getProperty("user.home"), "." + PROPERTIES_FILE_NAME); private static final String AMBASSADOR_IMAGE = "richnorth/ambassador"; + private static final String SOCAT_IMAGE = "alpine/socat"; + private static final String VNC_RECORDER_IMAGE = "testcontainers/vnc-recorder"; + private static final String COMPOSE_IMAGE = "docker/compose"; + private static final String ALPINE_IMAGE = "alpine"; + private static final String RYUK_IMAGE = "testcontainers/ryuk"; + private static final String KAFKA_IMAGE = "confluentinc/cp-kafka"; + private static final String PULSAR_IMAGE = "apachepulsar/pulsar"; + private static final String LOCALSTACK_IMAGE = "localstack/localstack"; + private static final String SSHD_IMAGE = "testcontainers/sshd"; + private static final String ORACLE_IMAGE = "gvenzl/oracle-xe"; - private static final ImmutableMap CONTAINER_MAPPING = ImmutableMap.builder() + private static final ImmutableMap CONTAINER_MAPPING = ImmutableMap + .builder() .put(DockerImageName.parse(AMBASSADOR_IMAGE), "ambassador.container.image") .put(DockerImageName.parse(SOCAT_IMAGE), "socat.container.image") .put(DockerImageName.parse(VNC_RECORDER_IMAGE), "vncrecorder.container.image") @@ -78,7 +89,7 @@ public class TestcontainersConfiguration { @Getter(lazy = true) private static final TestcontainersConfiguration instance = loadConfiguration(); - @SuppressWarnings({"ConstantConditions", "unchecked", "rawtypes"}) + @SuppressWarnings({ "ConstantConditions", "unchecked", "rawtypes" }) @VisibleForTesting static AtomicReference getInstanceField() { // Lazy Getter from Lombok changes the field's type to AtomicReference @@ -86,10 +97,16 @@ static AtomicReference getInstanceField() { } private final Properties userProperties; + private final Properties classpathProperties; + private final Map environment; - TestcontainersConfiguration(Properties userProperties, Properties classpathProperties, final Map environment) { + TestcontainersConfiguration( + Properties userProperties, + Properties classpathProperties, + final Map environment + ) { this.userProperties = userProperties; this.classpathProperties = classpathProperties; this.environment = environment; @@ -121,8 +138,7 @@ public String getTinyImage() { } public boolean isRyukPrivileged() { - return Boolean - .parseBoolean(getEnvVarOrProperty("ryuk.container.privileged", "false")); + return Boolean.parseBoolean(getEnvVarOrProperty("ryuk.container.privileged", "false")); } @Deprecated @@ -203,7 +219,11 @@ public Integer getClientPingTimeout() { @Nullable @Contract("_, !null, _ -> !null") - private String getConfigurable(@NotNull final String propertyName, @Nullable final String defaultValue, Properties... propertiesSources) { + private String getConfigurable( + @NotNull final String propertyName, + @Nullable final String defaultValue, + Properties... propertiesSources + ) { String envVarName = propertyName.replaceAll("\\.", "_").toUpperCase(); if (!envVarName.startsWith("TESTCONTAINERS_") && !envVarName.startsWith("DOCKER_")) { envVarName = "TESTCONTAINERS_" + envVarName; @@ -279,11 +299,15 @@ public String getUserProperty(@NotNull final String propertyName, @Nullable fina */ @Deprecated public Properties getProperties() { - return Stream.of(userProperties, classpathProperties) - .reduce(new Properties(), (a, b) -> { - a.putAll(b); - return a; - }); + return Stream + .of(userProperties, classpathProperties) + .reduce( + new Properties(), + (a, b) -> { + a.putAll(b); + return a; + } + ); } @Deprecated @@ -318,15 +342,20 @@ public boolean updateUserConfig(@NonNull String prop, @NonNull String value) { private static TestcontainersConfiguration loadConfiguration() { return new TestcontainersConfiguration( readProperties(USER_CONFIG_FILE.toURI().toURL()), - ClasspathScanner.scanFor(PROPERTIES_FILE_NAME) + ClasspathScanner + .scanFor(PROPERTIES_FILE_NAME) .map(TestcontainersConfiguration::readProperties) - .reduce(new Properties(), (a, b) -> { - // first-write-wins merging - URLs appearing first on the classpath alphabetically will take priority. - // Note that this means that file: URLs will always take priority over jar: URLs. - b.putAll(a); - return b; - }), - System.getenv()); + .reduce( + new Properties(), + (a, b) -> { + // first-write-wins merging - URLs appearing first on the classpath alphabetically will take priority. + // Note that this means that file: URLs will always take priority over jar: URLs. + b.putAll(a); + return b; + } + ), + System.getenv() + ); } private static Properties readProperties(URL url) { @@ -335,9 +364,17 @@ private static Properties readProperties(URL url) { try (InputStream inputStream = url.openStream()) { properties.load(inputStream); } catch (FileNotFoundException e) { - log.warn("Attempted to read Testcontainers configuration file at {} but the file was not found. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); + log.warn( + "Attempted to read Testcontainers configuration file at {} but the file was not found. Exception message: {}", + url, + ExceptionUtils.getRootCauseMessage(e) + ); } catch (IOException e) { - log.warn("Attempted to read Testcontainers configuration file at {} but could it not be loaded. Exception message: {}", url, ExceptionUtils.getRootCauseMessage(e)); + log.warn( + "Attempted to read Testcontainers configuration file at {} but could it not be loaded. Exception message: {}", + url, + ExceptionUtils.getRootCauseMessage(e) + ); } return properties; } @@ -349,14 +386,14 @@ private DockerImageName getImage(final String defaultValue) { DockerImageName getConfiguredSubstituteImage(DockerImageName original) { for (final Map.Entry entry : CONTAINER_MAPPING.entrySet()) { if (original.isCompatibleWith(entry.getKey())) { - return - Optional.ofNullable(entry.getValue()) - .map(propertyName -> getEnvVarOrProperty(propertyName, null)) - .map(String::valueOf) - .map(String::trim) - .map(DockerImageName::parse) - .orElse(original) - .asCompatibleSubstituteFor(original); + return Optional + .ofNullable(entry.getValue()) + .map(propertyName -> getEnvVarOrProperty(propertyName, null)) + .map(String::valueOf) + .map(String::trim) + .map(DockerImageName::parse) + .orElse(original) + .asCompatibleSubstituteFor(original); } } return original; diff --git a/core/src/main/java/org/testcontainers/utility/ThrowingFunction.java b/core/src/main/java/org/testcontainers/utility/ThrowingFunction.java index 6b2cef907e1..a8138f9dda0 100644 --- a/core/src/main/java/org/testcontainers/utility/ThrowingFunction.java +++ b/core/src/main/java/org/testcontainers/utility/ThrowingFunction.java @@ -1,6 +1,5 @@ package org.testcontainers.utility; public interface ThrowingFunction { - R apply(T t) throws Exception; } diff --git a/core/src/main/java/org/testcontainers/utility/Versioning.java b/core/src/main/java/org/testcontainers/utility/Versioning.java index 4b1da407440..372a105518f 100644 --- a/core/src/main/java/org/testcontainers/utility/Versioning.java +++ b/core/src/main/java/org/testcontainers/utility/Versioning.java @@ -45,8 +45,11 @@ public int hashCode() { @EqualsAndHashCode class TagVersioning implements Versioning { + public static final String TAG_REGEX = "[\\w][\\w.\\-]{0,127}"; + static final TagVersioning LATEST = new TagVersioning("latest"); + private final String tag; TagVersioning(String tag) { @@ -71,7 +74,9 @@ public String toString() { @EqualsAndHashCode class Sha256Versioning implements Versioning { + public static final String HASH_REGEX = "[0-9a-fA-F]{32,}"; + private final String hash; Sha256Versioning(String hash) { diff --git a/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java b/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java index e4197c7c1f6..168932106fb 100644 --- a/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java +++ b/core/src/test/java/alt/testcontainers/images/OutOfPackageImagePullPolicyTest.java @@ -1,29 +1,30 @@ package alt.testcontainers.images; import org.junit.Test; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.images.AbstractImagePullPolicy; import org.testcontainers.images.ImageData; import org.testcontainers.utility.DockerImageName; -import static org.testcontainers.TestImages.TINY_IMAGE; - public class OutOfPackageImagePullPolicyTest { + @Test public void shouldSupportCustomPoliciesOutOfTestContainersPackage() { try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) - .withImagePullPolicy(new AbstractImagePullPolicy() { - @Override - protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { - return false; + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) + .withImagePullPolicy( + new AbstractImagePullPolicy() { + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + return false; + } } - }) + ) ) { container.withStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); } } - } diff --git a/core/src/test/java/org/testcontainers/DaemonTest.java b/core/src/test/java/org/testcontainers/DaemonTest.java index f08614c8cdc..c1a1c20d60a 100644 --- a/core/src/test/java/org/testcontainers/DaemonTest.java +++ b/core/src/test/java/org/testcontainers/DaemonTest.java @@ -10,7 +10,6 @@ import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; -import static org.testcontainers.TestImages.TINY_IMAGE; /** * This test forks a new JVM, otherwise it's not possible to reliably diff the threads @@ -23,7 +22,7 @@ public static void main(String[] args) { GenericContainer genericContainer = null; try { - genericContainer = new GenericContainer<>(TINY_IMAGE).withCommand("top"); + genericContainer = new GenericContainer<>(TestImages.TINY_IMAGE).withCommand("top"); genericContainer.start(); Set threads = new HashSet<>(Thread.getAllStackTraces().keySet()); @@ -34,11 +33,14 @@ public static void main(String[] args) { if (nonDaemonThreads.isEmpty()) { VisibleAssertions.pass("All threads marked as daemon"); } else { - String nonDaemonThreadNames = nonDaemonThreads.stream() + String nonDaemonThreadNames = nonDaemonThreads + .stream() .map(Thread::getName) .collect(Collectors.joining("\n", "\n", "")); - VisibleAssertions.fail("Expected all threads to be daemons but the following are not:\n" + nonDaemonThreadNames); + VisibleAssertions.fail( + "Expected all threads to be daemons but the following are not:\n" + nonDaemonThreadNames + ); } } finally { if (genericContainer != null) { diff --git a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java index a889764579f..794bbbc37c9 100644 --- a/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java +++ b/core/src/test/java/org/testcontainers/DockerClientFactoryTest.java @@ -28,11 +28,13 @@ public void runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally() { dockFactory.runInsideDocker( imageName, cmd -> cmd.withCmd("sh", "-c", "echo 'SUCCESS'"), - (client, id) -> - client.logContainerCmd(id) + (client, id) -> { + return client + .logContainerCmd(id) .withStdOut(true) .exec(new LogToStringContainerCallback()) - .toString() + .toString(); + } ); } } diff --git a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java index 4018b2b954d..a907c674386 100644 --- a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java +++ b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java @@ -51,22 +51,30 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { WaitingConsumer waitingConsumer = new WaitingConsumer(); resultCallback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer); - dockerClient.logContainerCmd(containerInfo.getId()) + dockerClient + .logContainerCmd(containerInfo.getId()) .withStdErr(true) .withFollowStream(true) .exec(resultCallback); - Pattern pattern = Pattern.compile(".*listening on .*:(\\d+).*", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); - waitingConsumer.waitUntil(it -> { - String s = it.getUtf8String(); - Matcher matcher = pattern.matcher(s); - if (matcher.matches()) { - port.set(Integer.parseInt(matcher.group(1))); - return true; - } else { - return false; - } - }, 10, TimeUnit.SECONDS); + Pattern pattern = Pattern.compile( + ".*listening on .*:(\\d+).*", + Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE + ); + waitingConsumer.waitUntil( + it -> { + String s = it.getUtf8String(); + Matcher matcher = pattern.matcher(s); + if (matcher.matches()) { + port.set(Integer.parseInt(matcher.group(1))); + return true; + } else { + return false; + } + }, + 10, + TimeUnit.SECONDS + ); } endpoint = getHost() + ":" + port.get(); @@ -87,12 +95,15 @@ public DockerImageName createImage(String originalImage, String tag) { String dummyImageId = client.inspectImageCmd(originalImage).exec().getId(); - DockerImageName imageName = DockerImageName.parse(getEndpoint() + "/" + Base58.randomString(6).toLowerCase()).withTag(tag); + DockerImageName imageName = DockerImageName + .parse(getEndpoint() + "/" + Base58.randomString(6).toLowerCase()) + .withTag(tag); // push the image to the registry client.tagImageCmd(dummyImageId, imageName.asCanonicalNameString(), tag).exec(); - client.pushImageCmd(imageName.asCanonicalNameString()) + client + .pushImageCmd(imageName.asCanonicalNameString()) .exec(new ResultCallback.Adapter<>()) .awaitCompletion(1, TimeUnit.MINUTES); diff --git a/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java index 52296678fd4..4909e908713 100644 --- a/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java +++ b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java @@ -5,10 +5,9 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import java.util.Collections; import java.util.List; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -18,21 +17,22 @@ public class ContainerStateTest { @Parameterized.Parameters(name = "{0} ({1} -> {2})") public static Object[][] params() { - return new Object[][]{ - new Object[]{"regular mapping", "80:8080/tcp", singletonList(80),}, - new Object[]{"regular mapping with host", "127.0.0.1:80:8080/tcp", singletonList(80),}, - new Object[]{"zero port without host", ":0:8080/tcp", emptyList(),}, - new Object[]{"missing port with host", "0.0.0.0:0:8080/tcp", emptyList(),}, - new Object[]{"zero port (synthetic case)", "0:8080/tcp", emptyList(),}, - new Object[]{"missing port", ":8080/tcp", emptyList(), - } + return new Object[][] { + new Object[] { "regular mapping", "80:8080/tcp", Collections.singletonList(80) }, + new Object[] { "regular mapping with host", "127.0.0.1:80:8080/tcp", Collections.singletonList(80) }, + new Object[] { "zero port without host", ":0:8080/tcp", Collections.emptyList() }, + new Object[] { "missing port with host", "0.0.0.0:0:8080/tcp", Collections.emptyList() }, + new Object[] { "zero port (synthetic case)", "0:8080/tcp", Collections.emptyList() }, + new Object[] { "missing port", ":8080/tcp", Collections.emptyList() }, }; } @Parameterized.Parameter(0) public String name; + @Parameterized.Parameter(1) public String testSet; + @Parameterized.Parameter(2) public List expectedResult; @@ -41,7 +41,7 @@ public void test() { ContainerState containerState = mock(ContainerState.class); doCallRealMethod().when(containerState).getBoundPortNumbers(); - when(containerState.getPortBindings()).thenReturn(singletonList(testSet)); + when(containerState.getPortBindings()).thenReturn(Collections.singletonList(testSet)); List result = containerState.getBoundPortNumbers(); Assertions.assertThat(result).hasSameElementsAs(expectedResult); diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java index 8927972e642..8f056de98fa 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java @@ -9,17 +9,20 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; - public class DockerComposeContainerWithServicesTest { - public static final File SIMPLE_COMPOSE_FILE = new File("src/test/resources/compose-scaling-multiple-containers.yml"); - public static final File COMPOSE_FILE_WITH_INLINE_SCALE = new File("src/test/resources/compose-with-inline-scale-test.yml"); + public static final File SIMPLE_COMPOSE_FILE = new File( + "src/test/resources/compose-scaling-multiple-containers.yml" + ); + + public static final File COMPOSE_FILE_WITH_INLINE_SCALE = new File( + "src/test/resources/compose-with-inline-scale-test.yml" + ); @Test public void testDesiredSubsetOfServicesAreStarted() { try ( - DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) - .withServices("redis") + DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE).withServices("redis") ) { compose.start(); @@ -67,9 +70,7 @@ public void testDesiredSubsetOfSpecifiedOrScaledServicesAreStarted() { @Test public void testAllServicesAreStartedIfNotSpecified() { - try ( - DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) - ) { + try (DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE)) { compose.start(); verifyStartedContainers(compose, "redis_1", "other_1"); @@ -78,9 +79,7 @@ public void testAllServicesAreStartedIfNotSpecified() { @Test public void testScaleInComposeFileIsRespected() { - try ( - DockerComposeContainer compose = new DockerComposeContainer<>(COMPOSE_FILE_WITH_INLINE_SCALE) - ) { + try (DockerComposeContainer compose = new DockerComposeContainer<>(COMPOSE_FILE_WITH_INLINE_SCALE)) { compose.start(); // the compose file includes `scale: 3` for the redis container @@ -89,17 +88,20 @@ public void testScaleInComposeFileIsRespected() { } private void verifyStartedContainers(final DockerComposeContainer compose, final String... names) { - final List containerNames = compose.listChildContainers().stream() + final List containerNames = compose + .listChildContainers() + .stream() .flatMap(container -> Stream.of(container.getNames())) .collect(Collectors.toList()); - assertEquals("number of running services of docker-compose is the same as length of listOfServices", - names.length, containerNames.size()); + assertEquals( + "number of running services of docker-compose is the same as length of listOfServices", + names.length, + containerNames.size() + ); for (final String expectedName : names) { - final long matches = containerNames.stream() - .filter(foundName -> foundName.endsWith(expectedName)) - .count(); + final long matches = containerNames.stream().filter(foundName -> foundName.endsWith(expectedName)).count(); assertEquals("container with name starting '" + expectedName + "' should be running", 1L, matches); } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java index c47db0c4b66..6e1630f005f 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java @@ -1,25 +1,33 @@ package org.testcontainers.containers; - import com.google.common.collect.Lists; -import java.io.File; import org.assertj.core.api.Assertions; import org.junit.Test; +import java.io.File; + public class DockerComposeFilesTest { + @Test public void shouldGetDependencyImages() { - DockerComposeFiles dockerComposeFiles = new DockerComposeFiles(Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"))); - Assertions.assertThat(dockerComposeFiles.getDependencyImages()) + DockerComposeFiles dockerComposeFiles = new DockerComposeFiles( + Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-parsing-v2.yml")) + ); + Assertions + .assertThat(dockerComposeFiles.getDependencyImages()) .containsExactlyInAnyOrder("postgres:latest", "redis:latest", "mysql:latest"); } @Test public void shouldGetDependencyImagesWhenOverriding() { DockerComposeFiles dockerComposeFiles = new DockerComposeFiles( - Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-overriding-a.yml"), - new File("src/test/resources/docker-compose-imagename-overriding-b.yml"))); - Assertions.assertThat(dockerComposeFiles.getDependencyImages()) + Lists.newArrayList( + new File("src/test/resources/docker-compose-imagename-overriding-a.yml"), + new File("src/test/resources/docker-compose-imagename-overriding-b.yml") + ) + ); + Assertions + .assertThat(dockerComposeFiles.getDependencyImages()) .containsExactlyInAnyOrder("alpine:3.14", "redis:b", "mysql:b", "aservice:latest"); } } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java index 9e9eb27b509..6207ae5ff45 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java @@ -8,7 +8,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.rnorth.ducttape.unreliables.Unreliables; -import org.testcontainers.containers.DockerComposeContainer; import java.io.BufferedReader; import java.io.File; @@ -24,14 +23,23 @@ public class DockerComposeOverridesTest { private static final File BASE_COMPOSE_FILE = new File("src/test/resources/docker-compose-base.yml"); + private static final String BASE_ENV_VAR = "bar=base"; - private static final File OVERRIDE_COMPOSE_FILE = new File("src/test/resources/docker-compose-non-default-override.yml"); + + private static final File OVERRIDE_COMPOSE_FILE = new File( + "src/test/resources/docker-compose-non-default-override.yml" + ); + private static final String OVERRIDE_ENV_VAR = "bar=overwritten"; + private static final int SERVICE_PORT = 3000; + private static final String SERVICE_NAME = "alpine_1"; private final boolean localMode; + private final String expectedEnvVar; + private final File[] composeFiles; public DockerComposeOverridesTest(boolean localMode, String expectedEnvVar, File... composeFiles) { @@ -42,18 +50,21 @@ public DockerComposeOverridesTest(boolean localMode, String expectedEnvVar, File @Parameters(name = "{index}: local[{0}], composeFiles[{2}], expectedEnvVar[{1}]") public static Iterable data() { - return Arrays.asList(new Object[][]{ - {true, BASE_ENV_VAR, new File[]{BASE_COMPOSE_FILE}}, - {true, OVERRIDE_ENV_VAR, new File[]{BASE_COMPOSE_FILE, OVERRIDE_COMPOSE_FILE}}, - {false, BASE_ENV_VAR, new File[]{BASE_COMPOSE_FILE}}, - {false, OVERRIDE_ENV_VAR, new File[]{BASE_COMPOSE_FILE, OVERRIDE_COMPOSE_FILE}}, - }); + return Arrays.asList( + new Object[][] { + { true, BASE_ENV_VAR, new File[] { BASE_COMPOSE_FILE } }, + { true, OVERRIDE_ENV_VAR, new File[] { BASE_COMPOSE_FILE, OVERRIDE_COMPOSE_FILE } }, + { false, BASE_ENV_VAR, new File[] { BASE_COMPOSE_FILE } }, + { false, OVERRIDE_ENV_VAR, new File[] { BASE_COMPOSE_FILE, OVERRIDE_COMPOSE_FILE } }, + } + ); } @Before public void setUp() { if (localMode) { - Assumptions.assumeThat(LocalDockerCompose.executableExists()) + Assumptions + .assumeThat(LocalDockerCompose.executableExists()) .as("docker-compose executable exists") .isTrue(); } @@ -61,33 +72,43 @@ public void setUp() { @Test public void test() { - try (DockerComposeContainer compose = - new DockerComposeContainer(composeFiles) - .withLocalCompose(localMode) - .withExposedService(SERVICE_NAME, SERVICE_PORT)) { - + try ( + DockerComposeContainer compose = new DockerComposeContainer(composeFiles) + .withLocalCompose(localMode) + .withExposedService(SERVICE_NAME, SERVICE_PORT) + ) { compose.start(); - BufferedReader br = Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { - Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); + BufferedReader br = Unreliables.retryUntilSuccess( + 10, + TimeUnit.SECONDS, + () -> { + Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); - Socket socket = new Socket(compose.getServiceHost(SERVICE_NAME, SERVICE_PORT), compose.getServicePort(SERVICE_NAME, SERVICE_PORT)); - return new BufferedReader(new InputStreamReader(socket.getInputStream())); - }); + Socket socket = new Socket( + compose.getServiceHost(SERVICE_NAME, SERVICE_PORT), + compose.getServicePort(SERVICE_NAME, SERVICE_PORT) + ); + return new BufferedReader(new InputStreamReader(socket.getInputStream())); + } + ); - Unreliables.retryUntilTrue(10, TimeUnit.SECONDS, () -> { - while (br.ready()) { - String line = br.readLine(); - if (line.contains(expectedEnvVar)) { - pass("Mapped environment variable was found"); - return true; + Unreliables.retryUntilTrue( + 10, + TimeUnit.SECONDS, + () -> { + while (br.ready()) { + String line = br.readLine(); + if (line.contains(expectedEnvVar)) { + pass("Mapped environment variable was found"); + return true; + } } + info("Mapped environment variable was not found yet - process probably not ready"); + Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); + return false; } - info("Mapped environment variable was not found yet - process probably not ready"); - Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); - return false; - }); + ); } } - } diff --git a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java index 38005014662..4afddeaa5dd 100644 --- a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java +++ b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java @@ -7,13 +7,13 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.testcontainers.TestImages; import org.testcontainers.Testcontainers; import java.io.OutputStream; import java.net.InetSocketAddress; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.TestImages.TINY_IMAGE; public class ExposedHostTest { @@ -22,14 +22,17 @@ public class ExposedHostTest { @BeforeClass public static void setUpClass() throws Exception { server = HttpServer.create(new InetSocketAddress(0), 0); - server.createContext("/", exchange -> { - byte[] content = "Hello World!".getBytes(); - exchange.sendResponseHeaders(200, content.length); - try (OutputStream responseBody = exchange.getResponseBody()) { - responseBody.write(content); - responseBody.flush(); + server.createContext( + "/", + exchange -> { + byte[] content = "Hello World!".getBytes(); + exchange.sendResponseHeaders(200, content.length); + try (OutputStream responseBody = exchange.getResponseBody()) { + responseBody.write(content); + responseBody.flush(); + } } - }); + ); server.start(); } @@ -47,7 +50,7 @@ public void tearDown() { @Test public void testExposedHostAfterContainerIsStarted() { try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withCommand("top") .withAccessToHost(true) ) { @@ -60,14 +63,17 @@ public void testExposedHostAfterContainerIsStarted() { @Test public void testExposedHost() throws Exception { Testcontainers.exposeHostPorts(server.getAddress().getPort()); - assertResponse(new GenericContainer<>(TINY_IMAGE).withCommand("top"), server.getAddress().getPort()); + assertResponse(new GenericContainer<>(TestImages.TINY_IMAGE).withCommand("top"), server.getAddress().getPort()); } @Test public void testExposedHostWithNetwork() throws Exception { Testcontainers.exposeHostPorts(server.getAddress().getPort()); try (Network network = Network.newNetwork()) { - assertResponse(new GenericContainer<>(TINY_IMAGE).withNetwork(network).withCommand("top"), server.getAddress().getPort()); + assertResponse( + new GenericContainer<>(TestImages.TINY_IMAGE).withNetwork(network).withCommand("top"), + server.getAddress().getPort() + ); } } @@ -76,8 +82,8 @@ public void testExposedHostPortOnFixedInternalPorts() throws Exception { Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 80)); Testcontainers.exposeHostPorts(ImmutableMap.of(server.getAddress().getPort(), 81)); - assertResponse(new GenericContainer<>(TINY_IMAGE).withCommand("top"), 80); - assertResponse(new GenericContainer<>(TINY_IMAGE).withCommand("top"), 81); + assertResponse(new GenericContainer<>(TestImages.TINY_IMAGE).withCommand("top"), 80); + assertResponse(new GenericContainer<>(TestImages.TINY_IMAGE).withCommand("top"), 81); } @SneakyThrows @@ -85,7 +91,9 @@ protected void assertResponse(GenericContainer container, int port) { try { container.start(); - String response = container.execInContainer("wget", "-O", "-", "http://host.testcontainers.internal:" + port).getStdout(); + String response = container + .execInContainer("wget", "-O", "-", "http://host.testcontainers.internal:" + port) + .getStdout(); assertEquals("received response", "Hello World!", response); } finally { diff --git a/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java b/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java index 63993bc24ff..c743fcf6a43 100644 --- a/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java +++ b/core/src/test/java/org/testcontainers/containers/FailureDetectingExternalResourceTest.java @@ -25,5 +25,4 @@ public void finishedIsCalledForCleanupIfStartingThrows() throws Throwable { verify(res).starting(any()); verify(res).finished(any()); } - } diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 0c30d522cd9..fdd8ac1b146 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -17,13 +17,10 @@ import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.DockerClientFactory; import org.testcontainers.TestImages; -import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.images.builder.Transferable; - -import java.nio.charset.StandardCharsets; import org.testcontainers.images.builder.ImageFromDockerfile; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.MountableFile; import java.util.Arrays; @@ -34,11 +31,9 @@ import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.hamcrest.CoreMatchers.equalTo; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.TINY_IMAGE; public class GenericContainerTest { @@ -52,7 +47,8 @@ public void shouldReportOOMAfterWait() { .withStartupCheckStrategy(new NoopStartupCheckStrategy()) .waitingFor(new WaitForExitedState(ContainerState::getOOMKilled)) .withCreateContainerCmdModifier(it -> { - it.getHostConfig() + it + .getHostConfig() .withMemory(20 * FileUtils.ONE_MB) .withMemorySwappiness(0L) .withMemorySwap(0L) @@ -61,8 +57,7 @@ public void shouldReportOOMAfterWait() { }) .withCommand("sh", "-c", "A='0123456789'; for i in $(seq 0 32); do A=$A$A; done; sleep 10m") ) { - assertThatThrownBy(container::start) - .hasStackTraceContaining("Container crashed with out-of-memory"); + assertThatThrownBy(container::start).hasStackTraceContaining("Container crashed with out-of-memory"); } } @@ -74,8 +69,7 @@ public void shouldReportErrorAfterWait() { .waitingFor(new WaitForExitedState(state -> state.getExitCode() > 0)) .withCommand("sh", "-c", "usleep 100; exit 123") ) { - assertThatThrownBy(container::start) - .hasStackTraceContaining("Container exited with code 123"); + assertThatThrownBy(container::start).hasStackTraceContaining("Container exited with code 123"); } } @@ -88,8 +82,7 @@ public void shouldCopyTransferableAsFile() { .waitingFor(new WaitForExitedState(state -> state.getExitCodeLong() > 0)) .withCommand("sh", "-c", "grep -q test /tmp/test && exit 100") ) { - assertThatThrownBy(container::start) - .hasStackTraceContaining("Container exited with code 100"); + assertThatThrownBy(container::start).hasStackTraceContaining("Container exited with code 100"); } } @@ -98,34 +91,31 @@ public void shouldCopyTransferableAfterMountableFile() { try ( GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new NoopStartupCheckStrategy()) - .withCopyFileToContainer( - MountableFile.forClasspathResource("test_copy_to_container.txt"), - "/tmp/test" - ) + .withCopyFileToContainer(MountableFile.forClasspathResource("test_copy_to_container.txt"), "/tmp/test") .withCopyToContainer(Transferable.of("test"), "/tmp/test") .waitingFor(new WaitForExitedState(state -> state.getExitCodeLong() > 0)) .withCommand("sh", "-c", "grep -q test /tmp/test && exit 100") ) { - assertThatThrownBy(container::start) - .hasStackTraceContaining("Container exited with code 100"); + assertThatThrownBy(container::start).hasStackTraceContaining("Container exited with code 100"); } } @Test public void shouldOnlyPublishExposedPorts() { ImageFromDockerfile image = new ImageFromDockerfile("publish-multiple") - .withDockerfileFromBuilder(builder -> + .withDockerfileFromBuilder(builder -> { builder - .from("testcontainers/helloworld:1.1.0") + .from("testcontainers/helloworld:1.1.0") // .expose(8080, 8081) - .build() - ); + .build(); + }); try (GenericContainer container = new GenericContainer<>(image).withExposedPorts(8080)) { container.start(); InspectContainerResponse inspectedContainer = container.getContainerInfo(); - List exposedPorts = Arrays.stream(inspectedContainer.getConfig().getExposedPorts()) + List exposedPorts = Arrays + .stream(inspectedContainer.getConfig().getExposedPorts()) .map(ExposedPort::getPort) .collect(Collectors.toList()); @@ -135,18 +125,14 @@ public void shouldOnlyPublishExposedPorts() { exposedPorts ); - Map hostBindings = inspectedContainer.getHostConfig().getPortBindings().getBindings(); - assertEquals( - "only 1 port is bound on the host (published)", - 1, - hostBindings.size() - ); + Map hostBindings = inspectedContainer + .getHostConfig() + .getPortBindings() + .getBindings(); + assertEquals("only 1 port is bound on the host (published)", 1, hostBindings.size()); Integer mappedPort = container.getMappedPort(8080); - assertTrue( - "port 8080 is bound to a different port on the host", - mappedPort != 8080 - ); + assertTrue("port 8080 is bound to a different port on the host", mappedPort != 8080); assertThrows( "trying to get a non-bound port mapping fails", @@ -160,21 +146,19 @@ public void shouldOnlyPublishExposedPorts() { @Test public void shouldWaitUntilExposedPortIsMapped() { - ImageFromDockerfile image = new ImageFromDockerfile("publish-multiple") - .withDockerfileFromBuilder(builder -> + .withDockerfileFromBuilder(builder -> { builder .from("testcontainers/helloworld:1.1.0") .expose(8080, 8081) // one additional port exposed in image - .build() - ); + .build(); + }); try ( GenericContainer container = new GenericContainer<>(image) .withExposedPorts(8080) .withCreateContainerCmdModifier(it -> it.withExposedPorts(ExposedPort.tcp(8082))) // another port exposed by modifier ) { - container.start(); assertEquals("Only withExposedPort should be exposed", 1, container.getExposedPorts().size()); @@ -200,16 +184,20 @@ static class WaitForExitedState extends AbstractWaitStrategy { @Override @SneakyThrows protected void waitUntilReady() { - Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, () -> { - ContainerState state = waitStrategyTarget.getCurrentContainerInfo().getState(); - - log.debug("Current state: {}", state); - if (!"exited".equalsIgnoreCase(state.getStatus())) { - Thread.sleep(100); - return false; + Unreliables.retryUntilTrue( + 5, + TimeUnit.SECONDS, + () -> { + ContainerState state = waitStrategyTarget.getCurrentContainerInfo().getState(); + + log.debug("Current state: {}", state); + if (!"exited".equalsIgnoreCase(state.getStatus())) { + Thread.sleep(100); + return false; + } + return predicate.test(state); } - return predicate.test(state); - }); + ); throw new IllegalStateException("Nope!"); } diff --git a/core/src/test/java/org/testcontainers/containers/NetworkTest.java b/core/src/test/java/org/testcontainers/containers/NetworkTest.java index a39f0552a5a..d783f95e6d1 100644 --- a/core/src/test/java/org/testcontainers/containers/NetworkTest.java +++ b/core/src/test/java/org/testcontainers/containers/NetworkTest.java @@ -10,7 +10,6 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; -import static org.testcontainers.containers.Network.newNetwork; @RunWith(Enclosed.class) public class NetworkTest { @@ -18,18 +17,18 @@ public class NetworkTest { public static class WithRules { @Rule - public Network network = newNetwork(); + public Network network = Network.newNetwork(); @Rule public GenericContainer foo = new GenericContainer<>(TestImages.TINY_IMAGE) - .withNetwork(network) - .withNetworkAliases("foo") - .withCommand("/bin/sh", "-c", "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done"); + .withNetwork(network) + .withNetworkAliases("foo") + .withCommand("/bin/sh", "-c", "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done"); @Rule public GenericContainer bar = new GenericContainer<>(TestImages.TINY_IMAGE) - .withNetwork(network) - .withCommand("top"); + .withNetwork(network) + .withCommand("top"); @Test public void testNetworkSupport() throws Exception { @@ -44,16 +43,18 @@ public static class WithoutRules { public void testNetworkSupport() throws Exception { // useCustomNetwork { try ( - Network network = Network.newNetwork(); - - GenericContainer foo = new GenericContainer<>(TestImages.TINY_IMAGE) - .withNetwork(network) - .withNetworkAliases("foo") - .withCommand("/bin/sh", "-c", "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done"); - - GenericContainer bar = new GenericContainer<>(TestImages.TINY_IMAGE) - .withNetwork(network) - .withCommand("top") + Network network = Network.newNetwork(); + GenericContainer foo = new GenericContainer<>(TestImages.TINY_IMAGE) + .withNetwork(network) + .withNetworkAliases("foo") + .withCommand( + "/bin/sh", + "-c", + "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done" + ); + GenericContainer bar = new GenericContainer<>(TestImages.TINY_IMAGE) + .withNetwork(network) + .withCommand("top") ) { foo.start(); bar.start(); @@ -66,16 +67,12 @@ public void testNetworkSupport() throws Exception { @Test public void testBuilder() { - try ( - Network network = Network.builder() - .driver("macvlan") - .build() - ) { + try (Network network = Network.builder().driver("macvlan").build()) { String id = network.getId(); assertEquals( - "Flag is set", - "macvlan", - DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() + "Flag is set", + "macvlan", + DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() ); } } @@ -83,15 +80,13 @@ public void testBuilder() { @Test public void testModifiers() { try ( - Network network = Network.builder() - .createNetworkCmdModifier(cmd -> cmd.withDriver("macvlan")) - .build() + Network network = Network.builder().createNetworkCmdModifier(cmd -> cmd.withDriver("macvlan")).build() ) { String id = network.getId(); assertEquals( - "Flag is set", - "macvlan", - DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() + "Flag is set", + "macvlan", + DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() ); } } @@ -101,16 +96,22 @@ public void testReusability() { try (Network network = Network.newNetwork()) { String firstId = network.getId(); assertNotNull( - "Network exists", - DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(firstId).exec() + "Network exists", + DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(firstId).exec() ); network.close(); assertNotEquals( - "New network created", - firstId, - DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(network.getId()).exec().getId() + "New network created", + firstId, + DockerClientFactory + .instance() + .client() + .inspectNetworkCmd() + .withNetworkId(network.getId()) + .exec() + .getId() ); } } diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java index ef70d06ada1..61955de98ba 100644 --- a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -6,9 +6,9 @@ import org.junit.Test; import java.io.File; +import java.util.Collections; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.entry; public class ParsedDockerComposeFileValidationTest { @@ -16,8 +16,7 @@ public class ParsedDockerComposeFileValidationTest { @Test public void shouldValidate() { File file = new File("src/test/resources/docker-compose-container-name-v1.yml"); - Assertions - .assertThatThrownBy(() -> { + assertThatThrownBy(() -> { new ParsedDockerComposeFile(file); }) .hasMessageContaining(file.getAbsolutePath()) @@ -26,25 +25,23 @@ public void shouldValidate() { @Test public void shouldRejectContainerNameV1() { - Assertions - .assertThatThrownBy(() -> { - new ParsedDockerComposeFile(ImmutableMap.of( - "redis", ImmutableMap.of("container_name", "redis") - )); + assertThatThrownBy(() -> { + new ParsedDockerComposeFile(ImmutableMap.of("redis", ImmutableMap.of("container_name", "redis"))); }) .hasMessageContaining("'container_name' property set for service 'redis'"); } @Test public void shouldRejectContainerNameV2() { - Assertions - .assertThatThrownBy(() -> { - new ParsedDockerComposeFile(ImmutableMap.of( - "version", "2", - "services", ImmutableMap.of( - "redis", ImmutableMap.of("container_name", "redis") + assertThatThrownBy(() -> { + new ParsedDockerComposeFile( + ImmutableMap.of( + "version", + "2", + "services", + ImmutableMap.of("redis", ImmutableMap.of("container_name", "redis")) ) - )); + ); }) .hasMessageContaining("'container_name' property set for service 'redis'"); } @@ -52,35 +49,29 @@ public void shouldRejectContainerNameV2() { @Test public void shouldIgnoreUnknownStructure() { // Everything is a list - new ParsedDockerComposeFile(emptyMap()); + new ParsedDockerComposeFile(Collections.emptyMap()); // services is not a map but List - new ParsedDockerComposeFile(ImmutableMap.of( - "version", "2", - "services", emptyList() - )); + new ParsedDockerComposeFile(ImmutableMap.of("version", "2", "services", Collections.emptyList())); // services is not a collection - new ParsedDockerComposeFile(ImmutableMap.of( - "version", "2", - "services", true - )); + new ParsedDockerComposeFile(ImmutableMap.of("version", "2", "services", true)); // no services while version is defined - new ParsedDockerComposeFile(ImmutableMap.of( - "version", "9000" - )); + new ParsedDockerComposeFile(ImmutableMap.of("version", "9000")); } @Test public void shouldObtainImageNamesV1() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v1.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + Assertions + .assertThat(parsedFile.getServiceNameToImageNames()) .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("postgres"))) + entry("custom", Sets.newHashSet("postgres")) + ) .as("all defined images are found"); // redis, mysql from compose file, postgres from Dockerfile build } @@ -88,11 +79,13 @@ public void shouldObtainImageNamesV1() { public void shouldObtainImageNamesV2() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + Assertions + .assertThat(parsedFile.getServiceNameToImageNames()) .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("postgres"))) + entry("custom", Sets.newHashSet("postgres")) + ) .as("all defined images are found"); } @@ -100,11 +93,13 @@ public void shouldObtainImageNamesV2() { public void shouldObtainImageFromDockerfileBuild() { File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + Assertions + .assertThat(parsedFile.getServiceNameToImageNames()) .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.14"))) + entry("custom", Sets.newHashSet("alpine:3.14")) + ) .as("all defined images are found"); // r/ redis, mysql from compose file, alpine:3.14 from Dockerfile build } @@ -112,11 +107,13 @@ public void shouldObtainImageFromDockerfileBuild() { public void shouldObtainImageFromDockerfileBuildWithContext() { File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions.assertThat(parsedFile.getServiceNameToImageNames()) + Assertions + .assertThat(parsedFile.getServiceNameToImageNames()) .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.14"))) + entry("custom", Sets.newHashSet("alpine:3.14")) + ) .as("all defined images are found"); // redis, mysql from compose file, alpine:3.14 from Dockerfile build } } diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 9aad97d7e7b..7aafb0149bd 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -27,9 +27,9 @@ import org.mockito.stubbing.Answer; import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory; +import org.testcontainers.TestImages; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.MockTestcontainersConfigurationRule; import org.testcontainers.utility.MountableFile; import org.testcontainers.utility.TestcontainersConfiguration; @@ -53,7 +53,6 @@ import static org.assertj.core.api.Assumptions.assumeThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -import static org.testcontainers.TestImages.TINY_IMAGE; @RunWith(Enclosed.class) public class ReusabilityUnitTests { @@ -66,8 +65,8 @@ public static class CanBeReusedTest { @Parameterized.Parameters(name = "{0}") public static Object[][] data() { return new Object[][] { - { "generic", new GenericContainer<>(TINY_IMAGE), true }, - { "anonymous generic", new GenericContainer(TINY_IMAGE) {}, true }, + { "generic", new GenericContainer<>(TestImages.TINY_IMAGE), true }, + { "anonymous generic", new GenericContainer(TestImages.TINY_IMAGE) {}, true }, { "custom", new CustomContainer(), true }, { "anonymous custom", new CustomContainer() {}, true }, { "custom with containerIsCreated", new CustomContainerWithContainerIsCreated(), false }, @@ -90,15 +89,17 @@ public void shouldBeReusable() { } static class CustomContainer extends GenericContainer { + CustomContainer() { - super(TINY_IMAGE); + super(TestImages.TINY_IMAGE); } } - static class CustomContainerWithContainerIsCreated extends GenericContainer { + static class CustomContainerWithContainerIsCreated + extends GenericContainer { CustomContainerWithContainerIsCreated() { - super(TINY_IMAGE); + super(TestImages.TINY_IMAGE); } @Override @@ -114,29 +115,30 @@ public static class HooksTest extends AbstractReusabilityTest { List script = new ArrayList<>(); - GenericContainer container = makeReusable(new GenericContainer(TINY_IMAGE) { - - @Override - protected boolean canBeReused() { - // Because we override "containerIsCreated" - return true; - } + GenericContainer container = makeReusable( + new GenericContainer(TestImages.TINY_IMAGE) { + @Override + protected boolean canBeReused() { + // Because we override "containerIsCreated" + return true; + } - @Override - protected void containerIsCreated(String containerId) { - script.add("containerIsCreated"); - } + @Override + protected void containerIsCreated(String containerId) { + script.add("containerIsCreated"); + } - @Override - protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { - script.add("containerIsStarting(reused=" + reused + ")"); - } + @Override + protected void containerIsStarting(InspectContainerResponse containerInfo, boolean reused) { + script.add("containerIsStarting(reused=" + reused + ")"); + } - @Override - protected void containerIsStarted(InspectContainerResponse containerInfo, boolean reused) { - script.add("containerIsStarted(reused=" + reused + ")"); + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo, boolean reused) { + script.add("containerIsStarted(reused=" + reused + ")"); + } } - }); + ); @Test public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { @@ -149,11 +151,12 @@ public void shouldSetLabelsIfEnvironmentDoesNotSupportReuse() { when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); container.start(); - assertThat(script).containsExactly( - "containerIsCreated", - "containerIsStarting(reused=false)", - "containerIsStarted(reused=false)" - ); + assertThat(script) + .containsExactly( + "containerIsCreated", + "containerIsStarting(reused=false)", + "containerIsStarted(reused=false)" + ); } @Test @@ -166,10 +169,7 @@ public void shouldCallHookIfReused() { when(client.inspectContainerCmd(existingContainerId)).then(inspectContainerAnswer()); container.start(); - assertThat(script).containsExactly( - "containerIsStarting(reused=true)", - "containerIsStarted(reused=true)" - ); + assertThat(script).containsExactly("containerIsStarting(reused=true)", "containerIsStarted(reused=true)"); } @Test @@ -181,11 +181,12 @@ public void shouldNotCallHookIfNotReused() { when(client.inspectContainerCmd(containerId)).then(inspectContainerAnswer()); container.start(); - assertThat(script).containsExactly( - "containerIsCreated", - "containerIsStarting(reused=false)", - "containerIsStarted(reused=false)" - ); + assertThat(script) + .containsExactly( + "containerIsCreated", + "containerIsStarting(reused=false)", + "containerIsStarted(reused=false)" + ); } } @@ -193,12 +194,14 @@ public void shouldNotCallHookIfNotReused() { @FieldDefaults(makeFinal = true) public static class HashTest extends AbstractReusabilityTest { - protected GenericContainer container = makeReusable(new GenericContainer(TINY_IMAGE) { - @Override - public void copyFileToContainer(MountableFile mountableFile, String containerPath) { - // NOOP + protected GenericContainer container = makeReusable( + new GenericContainer(TestImages.TINY_IMAGE) { + @Override + public void copyFileToContainer(MountableFile mountableFile, String containerPath) { + // NOOP + } } - }); + ); @Test public void shouldStartIfListReturnsEmpty() { @@ -260,8 +263,7 @@ public void shouldSetCopiedFilesHashLabel() { container.start(); assertThat(commandRef).isNotNull(); - assertThat(commandRef.get().getLabels()) - .containsKeys(GenericContainer.COPIED_FILES_HASH_LABEL); + assertThat(commandRef.get().getLabels()).containsKeys(GenericContainer.COPIED_FILES_HASH_LABEL); } @Test @@ -292,15 +294,20 @@ public void shouldHashCopiedFiles() { ); container.start(); - assertThat(commandRef.get().getLabels()).hasEntrySatisfying(GenericContainer.COPIED_FILES_HASH_LABEL, newHash -> { - assertThat(newHash).as("new hash").isNotEqualTo(oldHash); - }); + assertThat(commandRef.get().getLabels()) + .hasEntrySatisfying( + GenericContainer.COPIED_FILES_HASH_LABEL, + newHash -> { + assertThat(newHash).as("new hash").isNotEqualTo(oldHash); + } + ); } } @RunWith(Parameterized.class) @FieldDefaults(makeFinal = true) public static class CopyFilesHashTest { + private final TestStrategy strategy; interface TestStrategy { @@ -310,6 +317,7 @@ interface TestStrategy { } private static class MountableFileTestStrategy implements TestStrategy { + private final GenericContainer container; private MountableFileTestStrategy(GenericContainer container) { @@ -328,6 +336,7 @@ public void clear() { } private static class TransferableTestStrategy implements TestStrategy { + private final GenericContainer container; private TransferableTestStrategy(GenericContainer container) { @@ -350,8 +359,7 @@ public static List, TestStrategy>> strategies() { return Arrays.asList(MountableFileTestStrategy::new, TransferableTestStrategy::new); } - - GenericContainer container = new GenericContainer<>(TINY_IMAGE); + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE); public CopyFilesHashTest(Function, TestStrategy> strategyFactory) { this.strategy = strategyFactory.apply(container); @@ -499,7 +507,7 @@ public void folderPermissions() throws Exception { } @FieldDefaults(makeFinal = true) - public static abstract class AbstractReusabilityTest { + public abstract static class AbstractReusabilityTest { @Rule public MockTestcontainersConfigurationRule configurationMock = new MockTestcontainersConfigurationRule(); @@ -509,25 +517,26 @@ public static abstract class AbstractReusabilityTest { protected > T makeReusable(T container) { container.dockerClient = client; container.withNetworkMode("none"); // to disable the port forwarding - container.withStartupCheckStrategy(new StartupCheckStrategy() { - - @Override - public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { - // Skip DockerClient rate limiter - return true; + container.withStartupCheckStrategy( + new StartupCheckStrategy() { + @Override + public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { + // Skip DockerClient rate limiter + return true; + } + + @Override + public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { + return StartupStatus.SUCCESSFUL; + } } - - @Override - public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) { - return StartupStatus.SUCCESSFUL; - } - }); - container.waitingFor(new AbstractWaitStrategy() { - @Override - protected void waitUntilReady() { - + ); + container.waitingFor( + new AbstractWaitStrategy() { + @Override + protected void waitUntilReady() {} } - }); + ); container.withReuse(true); return container; } @@ -539,12 +548,11 @@ protected String randomContainerId() { protected Answer listContainersAnswer(String... ids) { return invocation -> { ListContainersCmd.Exec exec = command -> { - return new ObjectMapper().convertValue( - Stream.of(ids) - .map(id -> Collections.singletonMap("Id", id)) - .collect(Collectors.toList()), - new TypeReference>() {} - ); + return new ObjectMapper() + .convertValue( + Stream.of(ids).map(id -> Collections.singletonMap("Id", id)).collect(Collectors.toList()), + new TypeReference>() {} + ); }; return new ListContainersCmdImpl(exec); }; @@ -554,7 +562,10 @@ protected Answer createContainerAnswer(String containerId) { return createContainerAnswer(containerId, command -> {}); } - protected Answer createContainerAnswer(String containerId, Consumer cmdConsumer) { + protected Answer createContainerAnswer( + String containerId, + Consumer cmdConsumer + ) { return invocation -> { CreateContainerCmd.Exec exec = command -> { cmdConsumer.accept(command); @@ -578,7 +589,10 @@ protected Answer startContainerAnswer() { protected Answer inspectContainerAnswer() { return invocation -> { InspectContainerCmd.Exec exec = command -> { - InspectContainerResponse stubResponse = Mockito.mock(InspectContainerResponse.class, Answers.RETURNS_DEEP_STUBS); + InspectContainerResponse stubResponse = Mockito.mock( + InspectContainerResponse.class, + Answers.RETURNS_DEEP_STUBS + ); when(stubResponse.getNetworkSettings().getPorts().getBindings()).thenReturn(Collections.emptyMap()); return stubResponse; }; diff --git a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java index 05ef7373293..a860b7802ec 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java @@ -2,14 +2,12 @@ import org.junit.Ignore; import org.junit.Test; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.ALPINE_IMAGE; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; public class ContainerLogsTest { @@ -43,7 +41,7 @@ public void getLogsReturnsStdOutToDate() { container.start(); // docsGetStdOut { - final String logs = container.getLogs(STDOUT); + final String logs = container.getLogs(OutputFrame.OutputType.STDOUT); // } assertTrue("stdout is reflected in the returned logs", logs.contains("stdout")); } @@ -55,7 +53,7 @@ public void getLogsReturnsStdErrToDate() { container.start(); // docsGetStdErr { - final String logs = container.getLogs(STDERR); + final String logs = container.getLogs(OutputFrame.OutputType.STDERR); // } assertTrue("stderr is reflected in the returned logs", logs.contains("stderr")); } @@ -68,19 +66,18 @@ public void getLogsForLongRunningContainer() throws InterruptedException { Thread.sleep(1000L); - final String logs = container.getLogs(STDOUT); + final String logs = container.getLogs(OutputFrame.OutputType.STDOUT); assertTrue("stdout is reflected in the returned logs for a running container", logs.contains("seq=0")); } } private static GenericContainer shortLivedContainer() { - return new GenericContainer<>(ALPINE_IMAGE) + return new GenericContainer<>(TestImages.ALPINE_IMAGE) .withCommand("/bin/sh", "-c", "echo -n 'stdout' && echo -n 'stderr' 1>&2") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); } private static GenericContainer longRunningContainer() { - return new GenericContainer<>(ALPINE_IMAGE) - .withCommand("ping -c 100 127.0.0.1"); + return new GenericContainer<>(TestImages.ALPINE_IMAGE).withCommand("ping -c 100 127.0.0.1"); } } diff --git a/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java b/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java index 325cccdd378..5282712b733 100644 --- a/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java @@ -12,17 +12,19 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.testcontainers.containers.output.OutputFrame.OutputType; public class FrameConsumerResultCallbackTest { - private static final String FRAME_PAYLOAD = "\u001B[0;32mТест1\u001B[0m\n\u001B[1;33mTest2\u001B[0m\n\u001B[0;31mTest3\u001B[0m"; + + private static final String FRAME_PAYLOAD = + "\u001B[0;32mТест1\u001B[0m\n\u001B[1;33mTest2\u001B[0m\n\u001B[0;31mTest3\u001B[0m"; + private static final String LOG_RESULT = "Тест1\nTest2\nTest3"; @Test public void passStderrFrameWithoutColors() { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer(); - callback.addConsumer(OutputType.STDERR, consumer); + callback.addConsumer(OutputFrame.OutputType.STDERR, consumer); callback.onNext(new Frame(StreamType.STDERR, FRAME_PAYLOAD.getBytes())); assertEquals(LOG_RESULT, consumer.toUtf8String()); } @@ -31,7 +33,7 @@ public void passStderrFrameWithoutColors() { public void passStderrFrameWithColors() { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDERR, consumer); + callback.addConsumer(OutputFrame.OutputType.STDERR, consumer); callback.onNext(new Frame(StreamType.STDERR, FRAME_PAYLOAD.getBytes())); assertEquals(FRAME_PAYLOAD, consumer.toUtf8String()); } @@ -40,7 +42,7 @@ public void passStderrFrameWithColors() { public void passStdoutFrameWithoutColors() { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer(); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, FRAME_PAYLOAD.getBytes())); assertEquals(LOG_RESULT, consumer.toUtf8String()); } @@ -49,7 +51,7 @@ public void passStdoutFrameWithoutColors() { public void passStdoutFrameWithColors() { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, FRAME_PAYLOAD.getBytes())); assertEquals(FRAME_PAYLOAD, consumer.toUtf8String()); } @@ -58,7 +60,7 @@ public void passStdoutFrameWithColors() { public void basicConsumer() { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); BasicConsumer consumer = new BasicConsumer(); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, FRAME_PAYLOAD.getBytes())); assertEquals(LOG_RESULT, consumer.toString()); } @@ -67,7 +69,7 @@ public void basicConsumer() { public void passStdoutNull() { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, null)); assertEquals("", consumer.toUtf8String()); } @@ -77,7 +79,7 @@ public void passStdoutEmptyLine() { String payload = ""; FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, payload.getBytes())); assertEquals(payload, consumer.toUtf8String()); } @@ -87,7 +89,7 @@ public void passStdoutSingleLine() { String payload = "Test"; FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, payload.getBytes())); assertEquals(payload, consumer.toUtf8String()); } @@ -97,7 +99,7 @@ public void passStdoutSingleLineWithNewline() { String payload = "Test\n"; FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, payload.getBytes())); assertEquals(payload, consumer.toUtf8String()); } @@ -106,38 +108,90 @@ public void passStdoutSingleLineWithNewline() { public void passRawFrameWithoutColors() throws TimeoutException, IOException { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); WaitingConsumer waitConsumer = new WaitingConsumer(); - callback.addConsumer(OutputType.STDOUT, waitConsumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, waitConsumer); callback.onNext(new Frame(StreamType.RAW, FRAME_PAYLOAD.getBytes())); - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("Test2"), 1, TimeUnit.SECONDS); - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("Тест1"), 1, TimeUnit.SECONDS); + waitConsumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().equals("Test2"), + 1, + TimeUnit.SECONDS + ); + waitConsumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().equals("Тест1"), + 1, + TimeUnit.SECONDS + ); Exception exception = null; try { - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("Test3"), 1, TimeUnit.SECONDS); + waitConsumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().equals("Test3"), + 1, + TimeUnit.SECONDS + ); } catch (Exception e) { exception = e; } assertTrue(exception instanceof TimeoutException); callback.close(); - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("Test3"), 1, TimeUnit.SECONDS); + waitConsumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().equals("Test3"), + 1, + TimeUnit.SECONDS + ); } @Test public void passRawFrameWithColors() throws TimeoutException, IOException { FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); WaitingConsumer waitConsumer = new WaitingConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDOUT, waitConsumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, waitConsumer); callback.onNext(new Frame(StreamType.RAW, FRAME_PAYLOAD.getBytes())); - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("\u001B[1;33mTest2\u001B[0m"), 1, TimeUnit.SECONDS); - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("\u001B[0;32mТест1\u001B[0m"), 1, TimeUnit.SECONDS); + waitConsumer.waitUntil( + frame -> { + return ( + frame.getType() == OutputFrame.OutputType.STDOUT && + frame.getUtf8String().equals("\u001B[1;33mTest2\u001B[0m") + ); + }, + 1, + TimeUnit.SECONDS + ); + waitConsumer.waitUntil( + frame -> { + return ( + frame.getType() == OutputFrame.OutputType.STDOUT && + frame.getUtf8String().equals("\u001B[0;32mТест1\u001B[0m") + ); + }, + 1, + TimeUnit.SECONDS + ); Exception exception = null; try { - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("\u001B[0;31mTest3\u001B[0m"), 1, TimeUnit.SECONDS); + waitConsumer.waitUntil( + frame -> { + return ( + frame.getType() == OutputFrame.OutputType.STDOUT && + frame.getUtf8String().equals("\u001B[0;31mTest3\u001B[0m") + ); + }, + 1, + TimeUnit.SECONDS + ); } catch (Exception e) { exception = e; } assertTrue(exception instanceof TimeoutException); callback.close(); - waitConsumer.waitUntil(frame -> frame.getType() == OutputType.STDOUT && frame.getUtf8String().equals("\u001B[0;31mTest3\u001B[0m"), 1, TimeUnit.SECONDS); + waitConsumer.waitUntil( + frame -> { + return ( + frame.getType() == OutputFrame.OutputType.STDOUT && + frame.getUtf8String().equals("\u001B[0;31mTest3\u001B[0m") + ); + }, + 1, + TimeUnit.SECONDS + ); } @Test @@ -150,7 +204,7 @@ public void reconstructBreakedUnicode() throws IOException { System.arraycopy(payloadBytes, bytes1.length, bytes2, 0, bytes2.length); FrameConsumerResultCallback callback = new FrameConsumerResultCallback(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); - callback.addConsumer(OutputType.STDOUT, consumer); + callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.RAW, bytes1)); callback.onNext(new Frame(StreamType.RAW, bytes2)); callback.close(); @@ -158,7 +212,9 @@ public void reconstructBreakedUnicode() throws IOException { } private static class BasicConsumer implements Consumer { + private boolean firstLine = true; + private StringBuilder input = new StringBuilder(); @Override diff --git a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java index 1760a8031b2..08973f2d601 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java @@ -1,7 +1,5 @@ package org.testcontainers.containers.output; -import static org.assertj.core.api.Assertions.assertThat; - import org.apache.commons.lang3.RandomStringUtils; import org.assertj.core.api.Assertions; import org.junit.Test; @@ -9,12 +7,14 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import static org.assertj.core.api.Assertions.assertThat; + public class ToStringConsumerTest { private static final String LARGE_PAYLOAD; static { - StringBuilder builder = new StringBuilder(10_003 * 10);; + StringBuilder builder = new StringBuilder(10_003 * 10); for (int i = 0; i < 10; i++) { builder.append(' ').append(i).append(RandomStringUtils.randomAlphabetic(10000)); } @@ -29,9 +29,7 @@ public void newlines_are_not_added_to_exec_output() throws Exception { container.start(); ExecResult build = container.execInContainer("echo", "-n", LARGE_PAYLOAD); - Assertions.assertThat(build.getStdout()) - .doesNotContain("\n") - .isEqualTo(LARGE_PAYLOAD); + Assertions.assertThat(build.getStdout()).doesNotContain("\n").isEqualTo(LARGE_PAYLOAD); } } @@ -39,18 +37,13 @@ public void newlines_are_not_added_to_exec_output() throws Exception { public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { container.withCreateContainerCmdModifier(cmd -> { - cmd - .withAttachStdin(true) - .withStdinOpen(true) - .withTty(true); + cmd.withAttachStdin(true).withStdinOpen(true).withTty(true); }); container.withCommand("sleep", "2m"); container.start(); ExecResult build = container.execInContainer("echo", "-n", LARGE_PAYLOAD); - assertThat(build.getStdout()) - .isEqualTo(LARGE_PAYLOAD) - .doesNotContain("\n"); + assertThat(build.getStdout()).isEqualTo(LARGE_PAYLOAD).doesNotContain("\n"); } } @@ -63,9 +56,7 @@ public void newlines_are_not_added_to_container_output() { container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode(); - assertThat(container.getLogs()) - .isEqualTo(LARGE_PAYLOAD) - .doesNotContain("\n"); + assertThat(container.getLogs()).isEqualTo(LARGE_PAYLOAD).doesNotContain("\n"); } } @@ -81,9 +72,7 @@ public void newlines_are_not_added_to_container_output_with_tty() { container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode(); - assertThat(container.getLogs()) - .isEqualTo(LARGE_PAYLOAD) - .doesNotContain("\n"); + assertThat(container.getLogs()).isEqualTo(LARGE_PAYLOAD).doesNotContain("\n"); } } } diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java index 19f3a772d41..c76d2481c7c 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java @@ -16,8 +16,11 @@ public class ExternalPortListeningCheckTest { private ServerSocket listeningSocket1; + private ServerSocket listeningSocket2; + private ServerSocket nonListeningSocket; + private WaitStrategyTarget mockContainer; @Before @@ -34,8 +37,10 @@ public void setUp() throws Exception { @Test public void singleListening() { - - final ExternalPortListeningCheck check = new ExternalPortListeningCheck(mockContainer, ImmutableSet.of(listeningSocket1.getLocalPort())); + final ExternalPortListeningCheck check = new ExternalPortListeningCheck( + mockContainer, + ImmutableSet.of(listeningSocket1.getLocalPort()) + ); final Boolean result = check.call(); @@ -44,8 +49,10 @@ public void singleListening() { @Test public void multipleListening() { - - final ExternalPortListeningCheck check = new ExternalPortListeningCheck(mockContainer, ImmutableSet.of(listeningSocket1.getLocalPort(), listeningSocket2.getLocalPort())); + final ExternalPortListeningCheck check = new ExternalPortListeningCheck( + mockContainer, + ImmutableSet.of(listeningSocket1.getLocalPort(), listeningSocket2.getLocalPort()) + ); final Boolean result = check.call(); @@ -54,13 +61,16 @@ public void multipleListening() { @Test public void oneNotListening() { - - final ExternalPortListeningCheck check = new ExternalPortListeningCheck(mockContainer, ImmutableSet.of(listeningSocket1.getLocalPort(), nonListeningSocket.getLocalPort())); - - assertThrows("ExternalPortListeningCheck detects a non-listening port among many", - IllegalStateException.class, - (Runnable) check::call); - + final ExternalPortListeningCheck check = new ExternalPortListeningCheck( + mockContainer, + ImmutableSet.of(listeningSocket1.getLocalPort(), nonListeningSocket.getLocalPort()) + ); + + assertThrows( + "ExternalPortListeningCheck detects a non-listening port among many", + IllegalStateException.class, + (Runnable) check::call + ); } @After diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java index 22014cd097a..6f2a5d3158c 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java @@ -11,36 +11,41 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.images.builder.ImageFromDockerfile; +import java.util.Arrays; import java.util.concurrent.TimeUnit; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class InternalCommandPortListeningCheckTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"internal-port-check-dockerfile/Dockerfile-tcp"}, - {"internal-port-check-dockerfile/Dockerfile-nc"}, - {"internal-port-check-dockerfile/Dockerfile-bash"}, - }); + return Arrays.asList( + new Object[][] { + { "internal-port-check-dockerfile/Dockerfile-tcp" }, + { "internal-port-check-dockerfile/Dockerfile-nc" }, + { "internal-port-check-dockerfile/Dockerfile-bash" }, + } + ); } @Rule public GenericContainer container; public InternalCommandPortListeningCheckTest(String dockerfile) { - container = new GenericContainer(new ImageFromDockerfile() - .withFileFromClasspath("Dockerfile", dockerfile) - .withFileFromClasspath("nginx.conf", "internal-port-check-dockerfile/nginx.conf") - ); + container = + new GenericContainer( + new ImageFromDockerfile() + .withFileFromClasspath("Dockerfile", dockerfile) + .withFileFromClasspath("nginx.conf", "internal-port-check-dockerfile/nginx.conf") + ); } @Test public void singleListening() { - final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(container, ImmutableSet.of(8080)); + final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck( + container, + ImmutableSet.of(8080) + ); Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); @@ -49,18 +54,23 @@ public void singleListening() { @Test public void nonListening() { - final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(container, ImmutableSet.of(8080, 1234)); + final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck( + container, + ImmutableSet.of(8080, 1234) + ); try { Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); VisibleAssertions.fail("expected to fail"); - } catch (TimeoutException e) { - } + } catch (TimeoutException e) {} } @Test public void lowAndHighPortListening() { - final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck(container, ImmutableSet.of(100, 8080)); + final InternalCommandPortListeningCheck check = new InternalCommandPortListeningCheck( + container, + ImmutableSet.of(100, 8080) + ); Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java index d867233f5d7..0d102def5a9 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java @@ -17,10 +17,16 @@ public class DockerHealthcheckWaitStrategyTest { @Before public void setUp() { // Using a Dockerfile here, since Dockerfile builder DSL doesn't support HEALTHCHECK - container = new GenericContainer(new ImageFromDockerfile() - .withFileFromClasspath("write_file_and_loop.sh", "health-wait-strategy-dockerfile/write_file_and_loop.sh") - .withFileFromClasspath("Dockerfile", "health-wait-strategy-dockerfile/Dockerfile")) - .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofSeconds(3))); + container = + new GenericContainer( + new ImageFromDockerfile() + .withFileFromClasspath( + "write_file_and_loop.sh", + "health-wait-strategy-dockerfile/write_file_and_loop.sh" + ) + .withFileFromClasspath("Dockerfile", "health-wait-strategy-dockerfile/Dockerfile") + ) + .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofSeconds(3))); } @Test diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java index 897293282bd..2b8ba7c33ec 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java @@ -19,10 +19,13 @@ public class WaitAllStrategyTest { @Mock private GenericContainer container; + @Mock private WaitStrategy strategy1; + @Mock private WaitStrategy strategy2; + @Mock private WaitStrategy strategy3; @@ -36,32 +39,25 @@ public void setUp() { */ @Test public void parentTimeoutApplies() { - DummyStrategy child1 = new DummyStrategy(Duration.ofMillis(10)); child1.withStartupTimeout(Duration.ofMillis(20)); assertEquals("withStartupTimeout directly sets the timeout", 20L, child1.startupTimeout.toMillis()); - new WaitAllStrategy() - .withStrategy(child1) - .withStartupTimeout(Duration.ofMillis(30)); + new WaitAllStrategy().withStrategy(child1).withStartupTimeout(Duration.ofMillis(30)); assertEquals("WaitAllStrategy overrides a child's timeout", 30L, child1.startupTimeout.toMillis()); } @Test public void parentTimeoutAppliesToMultipleChildren() { - Duration defaultInnerWait = Duration.ofMillis(2); Duration outerWait = Duration.ofMillis(6); DummyStrategy child1 = new DummyStrategy(defaultInnerWait); DummyStrategy child2 = new DummyStrategy(defaultInnerWait); - new WaitAllStrategy() - .withStrategy(child1) - .withStrategy(child2) - .withStartupTimeout(outerWait); + new WaitAllStrategy().withStrategy(child1).withStrategy(child2).withStartupTimeout(outerWait); assertEquals("WaitAllStrategy overrides a child's timeout (1st)", 6L, child1.startupTimeout.toMillis()); assertEquals("WaitAllStrategy overrides a child's timeout (2nd)", 6L, child2.startupTimeout.toMillis()); @@ -69,20 +65,20 @@ public void parentTimeoutAppliesToMultipleChildren() { @Test public void parentTimeoutAppliesToAdditionalChildren() { - Duration defaultInnerWait = Duration.ofMillis(2); Duration outerWait = Duration.ofMillis(20); DummyStrategy child1 = new DummyStrategy(defaultInnerWait); DummyStrategy child2 = new DummyStrategy(defaultInnerWait); - new WaitAllStrategy() - .withStrategy(child1) - .withStartupTimeout(outerWait) - .withStrategy(child2); + new WaitAllStrategy().withStrategy(child1).withStartupTimeout(outerWait).withStrategy(child2); assertEquals("WaitAllStrategy overrides a child's timeout (1st)", 20L, child1.startupTimeout.toMillis()); - assertEquals("WaitAllStrategy overrides a child's timeout (2nd, additional)", 20L, child2.startupTimeout.toMillis()); + assertEquals( + "WaitAllStrategy overrides a child's timeout (2nd, additional)", + 20L, + child2.startupTimeout.toMillis() + ); } /* @@ -90,10 +86,7 @@ public void parentTimeoutAppliesToAdditionalChildren() { */ @Test public void childExecutionTest() { - - final WaitStrategy underTest = new WaitAllStrategy() - .withStrategy(strategy1) - .withStrategy(strategy2); + final WaitStrategy underTest = new WaitAllStrategy().withStrategy(strategy1).withStrategy(strategy2); doNothing().when(strategy1).waitUntilReady(eq(container)); doNothing().when(strategy2).waitUntilReady(eq(container)); @@ -107,7 +100,6 @@ public void childExecutionTest() { @Test public void withoutOuterTimeoutShouldRelyOnInnerStrategies() { - final WaitStrategy underTest = new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) .withStrategy(strategy1) .withStrategy(strategy2) @@ -116,9 +108,13 @@ public void withoutOuterTimeoutShouldRelyOnInnerStrategies() { doNothing().when(strategy1).waitUntilReady(eq(container)); doThrow(TimeoutException.class).when(strategy2).waitUntilReady(eq(container)); - assertThrows("The outer strategy timeout applies", TimeoutException.class, () -> { - underTest.waitUntilReady(container); - }); + assertThrows( + "The outer strategy timeout applies", + TimeoutException.class, + () -> { + underTest.waitUntilReady(container); + } + ); InOrder inOrder = inOrder(strategy1, strategy2, strategy3); inOrder.verify(strategy1).waitUntilReady(any()); @@ -128,17 +124,19 @@ public void withoutOuterTimeoutShouldRelyOnInnerStrategies() { @Test public void timeoutChangeShouldNotBePossibleWithIndividualTimeoutMode() { - final WaitStrategy underTest = new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY); - assertThrows("Cannot change timeout for individual timeouts", IllegalStateException.class, () -> { - underTest.withStartupTimeout(Duration.ofSeconds(42)); - }); + assertThrows( + "Cannot change timeout for individual timeouts", + IllegalStateException.class, + () -> { + underTest.withStartupTimeout(Duration.ofSeconds(42)); + } + ); } @Test public void shouldNotMessWithIndividualTimeouts() { - new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY) .withStrategy(strategy1) .withStrategy(strategy2); @@ -149,18 +147,15 @@ public void shouldNotMessWithIndividualTimeouts() { @Test public void shouldOverwriteIndividualTimeouts() { - Duration someSeconds = Duration.ofSeconds(23); - new WaitAllStrategy() - .withStartupTimeout(someSeconds) - .withStrategy(strategy1) - .withStrategy(strategy2); + new WaitAllStrategy().withStartupTimeout(someSeconds).withStrategy(strategy1).withStrategy(strategy2); verify(strategy1).withStartupTimeout(someSeconds); verify(strategy1).withStartupTimeout(someSeconds); } static class DummyStrategy extends AbstractWaitStrategy { + DummyStrategy(Duration defaultInnerWait) { super.startupTimeout = defaultInnerWait; } diff --git a/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java index 2e39b367c46..f67ad212d77 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/AmbiguousImagePullTest.java @@ -14,8 +14,7 @@ public void testNotUsingParse() { DockerImageName imageName = registryContainer.createImage("latest"); String imageNameWithoutTag = imageName.getRegistry() + "/" + imageName.getRepository(); try ( - final GenericContainer container = new GenericContainer<>(imageNameWithoutTag) - .withExposedPorts(8080) + final GenericContainer container = new GenericContainer<>(imageNameWithoutTag).withExposedPorts(8080) ) { container.start(); // do nothing other than start and stop diff --git a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java index 442c2efd950..39e1338bc46 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java @@ -17,29 +17,39 @@ public class DockerClientConfigUtilsTest { @Test public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() { - Assumptions.assumeThat(DockerClientConfigUtils.IN_A_CONTAINER) - .as("in a container") - .isFalse(); + Assumptions.assumeThat(DockerClientConfigUtils.IN_A_CONTAINER).as("in a container").isFalse(); - String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("unix:///var/run/docker.sock")); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( + client, + URI.create("unix:///var/run/docker.sock") + ); assertEquals("localhost", actual); } @Test public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() { - String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("http://12.23.34.45")); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( + client, + URI.create("http://12.23.34.45") + ); assertEquals("12.23.34.45", actual); } @Test public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() { - String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("tcp://12.23.34.45")); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( + client, + URI.create("tcp://12.23.34.45") + ); assertEquals("12.23.34.45", actual); } @Test public void getDockerHostIpAddressShouldReturnNullWhenUnsupportedUriScheme() { - String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(client, URI.create("gopher://12.23.34.45")); + String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress( + client, + URI.create("gopher://12.23.34.45") + ); assertNull(actual); } diff --git a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java index a6bd68be745..b2ab27aad27 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java @@ -20,7 +20,6 @@ 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.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -35,7 +34,9 @@ public class EnvironmentAndSystemPropertyClientProviderStrategyTest { @Rule public MockTestcontainersConfigurationRule mockConfig = new MockTestcontainersConfigurationRule(); + private URI defaultDockerHost; + private com.github.dockerjava.core.SSLConfig defaultSSLConfig; @Before @@ -48,10 +49,22 @@ public void checkEnvironmentClear() { @Test public void testWhenConfigAbsent() { - Mockito.doReturn("auto").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); - Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); - Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); - Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); + Mockito + .doReturn("auto") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); + Mockito + .doReturn(null) + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.host"), isNull()); + Mockito + .doReturn(null) + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); + Mockito + .doReturn(null) + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); @@ -62,10 +75,22 @@ public void testWhenConfigAbsent() { @Test public void testWhenDockerHostPresent() { - Mockito.doReturn("auto").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); - Mockito.doReturn("tcp://1.2.3.4:2375").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); - Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); - Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); + Mockito + .doReturn("auto") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); + Mockito + .doReturn("tcp://1.2.3.4:2375") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.host"), isNull()); + Mockito + .doReturn(null) + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); + Mockito + .doReturn(null) + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); @@ -79,10 +104,22 @@ public void testWhenDockerHostAndSSLConfigPresent() throws IOException { Path tempDir = Files.createTempDirectory("testcontainers-test"); String tempDirPath = tempDir.toAbsolutePath().toString(); - Mockito.doReturn("auto").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); - Mockito.doReturn("tcp://1.2.3.4:2375").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.host"), isNull()); - Mockito.doReturn("1").when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); - Mockito.doReturn(tempDirPath).when(TestcontainersConfiguration.getInstance()).getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); + Mockito + .doReturn("auto") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); + Mockito + .doReturn("tcp://1.2.3.4:2375") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.host"), isNull()); + Mockito + .doReturn("1") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.tls.verify"), isNull()); + Mockito + .doReturn(tempDirPath) + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrUserProperty(eq("docker.cert.path"), isNull()); EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); @@ -90,14 +127,15 @@ public void testWhenDockerHostAndSSLConfigPresent() throws IOException { assertEquals("tcp://1.2.3.4:2375", transportConfig.getDockerHost().toString()); SSLConfig sslConfig = transportConfig.getSslConfig(); - Assertions.assertThat(sslConfig) - .extracting("dockerCertPath") - .isEqualTo(tempDirPath); + Assertions.assertThat(sslConfig).extracting("dockerCertPath").isEqualTo(tempDirPath); } @Test public void applicableWhenIgnoringUserPropertiesAndConfigured() { - Mockito.doReturn("autoIgnoringUserProperties").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); + Mockito + .doReturn("autoIgnoringUserProperties") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); Properties oldProperties = System.getProperties(); try { @@ -112,7 +150,10 @@ public void applicableWhenIgnoringUserPropertiesAndConfigured() { @Test public void notApplicableWhenIgnoringUserPropertiesAndNotConfigured() { - Mockito.doReturn("autoIgnoringUserProperties").when(TestcontainersConfiguration.getInstance()).getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); + Mockito + .doReturn("autoIgnoringUserProperties") + .when(TestcontainersConfiguration.getInstance()) + .getEnvVarOrProperty(eq("dockerconfig.source"), anyString()); EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); diff --git a/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java b/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java index a43a001ca5b..642eb6d7390 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/EventStreamTest.java @@ -8,6 +8,7 @@ import org.junit.Test; import org.junit.rules.Timeout; import org.testcontainers.DockerClientFactory; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; @@ -16,8 +17,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.testcontainers.TestImages.TINY_IMAGE; - /** * Test that event streaming from the {@link DockerClient} works correctly */ @@ -34,7 +33,7 @@ public void test() throws IOException, InterruptedException { CountDownLatch latch = new CountDownLatch(1); try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withCommand("true") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) ) { @@ -43,24 +42,31 @@ public void test() throws IOException, InterruptedException { // Request all events between startTime and endTime for the container try ( - EventsResultCallback response = DockerClientFactory.instance().client().eventsCmd() + EventsResultCallback response = DockerClientFactory + .instance() + .client() + .eventsCmd() .withContainerFilter(container.getContainerId()) .withEventFilter("create") .withSince(Instant.parse(createdAt).getEpochSecond() + "") - .exec(new EventsResultCallback() { - @Override - public void onNext(@NotNull Event event) { - // Check that a create event for the container is received - if (event.getId().equals(container.getContainerId()) && event.getStatus().equals("create")) { - latch.countDown(); + .exec( + new EventsResultCallback() { + @Override + public void onNext(@NotNull Event event) { + // Check that a create event for the container is received + if ( + event.getId().equals(container.getContainerId()) && + event.getStatus().equals("create") + ) { + latch.countDown(); + } } } - }) + ) ) { response.awaitStarted(5, TimeUnit.SECONDS); latch.await(5, TimeUnit.SECONDS); } } } - } diff --git a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java index 8691e8f5f56..730208c553f 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java @@ -22,7 +22,7 @@ public static String[] parameters() { "quay.io/testcontainers/ryuk:latest", "quay.io/testcontainers/ryuk:0.2.3", "quay.io/testcontainers/ryuk@sha256:bb5a635cac4bd96c93cc476969ce11dc56436238ec7cd028d0524462f4739dd9", -// "ibmcom/db2express-c", // Big image for testing with slow networks + // "ibmcom/db2express-c", // Big image for testing with slow networks }; } @@ -32,9 +32,11 @@ public ImagePullTest(String image) { @Test public void test() { - try (final GenericContainer container = new GenericContainer<>(DockerImageName.parse(image)) - .withCommand("/bin/sh", "-c", "sleep 0") - .withStartupCheckStrategy(new OneShotStartupCheckStrategy())) { + try ( + final GenericContainer container = new GenericContainer<>(DockerImageName.parse(image)) + .withCommand("/bin/sh", "-c", "sleep 0") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { container.start(); // do nothing other than start and stop } diff --git a/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java index e073fa0522a..96fdfa4010b 100644 --- a/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java @@ -1,15 +1,15 @@ package org.testcontainers.images; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.testcontainers.utility.DockerImageName; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.UUID; -import org.junit.Test; -import org.testcontainers.utility.DockerImageName; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class AgeBasedPullPolicyTest { @@ -17,9 +17,7 @@ public class AgeBasedPullPolicyTest { @Test public void shouldPull() { - ImageData imageData = ImageData.builder() - .createdAt(Instant.now().minus(2, ChronoUnit.HOURS)) - .build(); + ImageData imageData = ImageData.builder().createdAt(Instant.now().minus(2, ChronoUnit.HOURS)).build(); AgeBasedPullPolicy oneHour = new AgeBasedPullPolicy(Duration.of(1L, ChronoUnit.HOURS)); assertTrue(oneHour.shouldPullCached(imageName, imageData)); diff --git a/core/src/test/java/org/testcontainers/images/ImageDataTest.java b/core/src/test/java/org/testcontainers/images/ImageDataTest.java index 3b473cf7ffd..6ff75e9e355 100644 --- a/core/src/test/java/org/testcontainers/images/ImageDataTest.java +++ b/core/src/test/java/org/testcontainers/images/ImageDataTest.java @@ -1,12 +1,11 @@ package org.testcontainers.images; -import static org.assertj.core.api.Assertions.assertThat; +import com.github.dockerjava.api.command.InspectImageResponse; +import org.junit.Test; import java.time.Instant; -import org.junit.Test; - -import com.github.dockerjava.api.command.InspectImageResponse; +import static org.assertj.core.api.Assertions.assertThat; public class ImageDataTest { @@ -23,5 +22,4 @@ public void shouldReadTimestampWithOffsetFromInspectImageResponse() { final ImageData imageData = ImageData.from(new InspectImageResponse().withCreated(timestamp)); assertThat(imageData.getCreatedAt()).isEqualTo(Instant.parse("2020-07-27T16:23:31.365190246Z")); } - } diff --git a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java index 9d5ed400d32..0b0ee5f1b70 100644 --- a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java @@ -24,29 +24,20 @@ public class ImagePullPolicyTest { @Test public void pullsByDefault() { - try ( - GenericContainer container = new GenericContainer<>(imageName) - .withExposedPorts(8080) - ) { + try (GenericContainer container = new GenericContainer<>(imageName).withExposedPorts(8080)) { container.start(); } } @Test public void shouldAlwaysPull() { - try ( - GenericContainer container = new GenericContainer<>(imageName) - .withExposedPorts(8080) - ) { + try (GenericContainer container = new GenericContainer<>(imageName).withExposedPorts(8080)) { container.start(); } removeImage(); - try ( - GenericContainer container = new GenericContainer<>(imageName) - .withExposedPorts(8080) - ) { + try (GenericContainer container = new GenericContainer<>(imageName).withExposedPorts(8080)) { expectToFailWithNotFoundException(container); } @@ -66,12 +57,14 @@ public void shouldSupportCustomPolicies() { try ( // custom_image_pull_policy { GenericContainer container = new GenericContainer<>(imageName) - .withImagePullPolicy(new AbstractImagePullPolicy() { - @Override - protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { - return System.getenv("ALWAYS_PULL_IMAGE") != null; + .withImagePullPolicy( + new AbstractImagePullPolicy() { + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + return System.getenv("ALWAYS_PULL_IMAGE") != null; + } } - }) + ) // } ) { container.withExposedPorts(8080); @@ -81,12 +74,14 @@ protected boolean shouldPullCached(DockerImageName imageName, ImageData localIma @Test public void shouldCheckPolicy() { - ImagePullPolicy policy = Mockito.spy(new AbstractImagePullPolicy() { - @Override - protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { - return false; + ImagePullPolicy policy = Mockito.spy( + new AbstractImagePullPolicy() { + @Override + protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) { + return false; + } } - }); + ); try ( GenericContainer container = new GenericContainer<>(imageName) .withImagePullPolicy(policy) @@ -128,11 +123,12 @@ private void expectToFailWithNotFoundException(GenericContainer container) { private void removeImage() { try { - DockerClientFactory.instance().client() + DockerClientFactory + .instance() + .client() .removeImageCmd(imageName.asCanonicalNameString()) .withForce(true) .exec(); - } catch (NotFoundException ignored) { - } + } catch (NotFoundException ignored) {} } } diff --git a/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java index 52a22c83b00..cd4509965e6 100644 --- a/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java +++ b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java @@ -4,69 +4,119 @@ import org.junit.Test; import java.nio.file.Paths; +import java.util.Arrays; -import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; public class ParsedDockerfileTest { @Test public void doesSimpleParsing() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage", "RUN something")); - assertEquals("extracts a single image name", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("FROM someimage", "RUN something") + ); + assertEquals( + "extracts a single image name", + Sets.newHashSet("someimage"), + parsedDockerfile.getDependencyImageNames() + ); } @Test public void isCaseInsensitive() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("from someimage", "RUN something")); - assertEquals("extracts a single image name", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("from someimage", "RUN something") + ); + assertEquals( + "extracts a single image name", + Sets.newHashSet("someimage"), + parsedDockerfile.getDependencyImageNames() + ); } @Test public void handlesTags() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage:tag", "RUN something")); - assertEquals("retains tags in image names", Sets.newHashSet("someimage:tag"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("FROM someimage:tag", "RUN something") + ); + assertEquals( + "retains tags in image names", + Sets.newHashSet("someimage:tag"), + parsedDockerfile.getDependencyImageNames() + ); } @Test public void handlesDigests() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage@sha256:abc123", "RUN something")); - assertEquals("retains digests in image names", Sets.newHashSet("someimage@sha256:abc123"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("FROM someimage@sha256:abc123", "RUN something") + ); + assertEquals( + "retains digests in image names", + Sets.newHashSet("someimage@sha256:abc123"), + parsedDockerfile.getDependencyImageNames() + ); } @Test public void ignoringCommentedFromLines() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage", "#FROM somethingelse")); - assertEquals("ignores commented from lines", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("FROM someimage", "#FROM somethingelse") + ); + assertEquals( + "ignores commented from lines", + Sets.newHashSet("someimage"), + parsedDockerfile.getDependencyImageNames() + ); } @Test public void ignoringBuildStageNames() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM someimage --as=base", "RUN something", "FROM nextimage", "RUN something")); - assertEquals("ignores build stage names and allows multiple images to be extracted", Sets.newHashSet("someimage", "nextimage"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("FROM someimage --as=base", "RUN something", "FROM nextimage", "RUN something") + ); + assertEquals( + "ignores build stage names and allows multiple images to be extracted", + Sets.newHashSet("someimage", "nextimage"), + parsedDockerfile.getDependencyImageNames() + ); } @Test public void ignoringPlatformArgs() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM --platform=linux/amd64 someimage", "RUN something")); - assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("FROM --platform=linux/amd64 someimage", "RUN something") + ); + assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); } @Test public void ignoringExtraPlatformArgs() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("FROM --platform=linux/amd64 --somethingelse=value someimage", "RUN something")); - assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("FROM --platform=linux/amd64 --somethingelse=value someimage", "RUN something") + ); + assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); } @Test public void handlesGracefullyIfNoFromLine() { - final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(asList("RUN something", "# is this even a valid Dockerfile?")); - assertEquals("handles invalid Dockerfiles gracefully", Sets.newHashSet(), parsedDockerfile.getDependencyImageNames()); + final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( + Arrays.asList("RUN something", "# is this even a valid Dockerfile?") + ); + assertEquals( + "handles invalid Dockerfiles gracefully", + Sets.newHashSet(), + parsedDockerfile.getDependencyImageNames() + ); } @Test public void handlesGracefullyIfDockerfileNotFound() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(Paths.get("nonexistent.Dockerfile")); - assertEquals("handles missing Dockerfiles gracefully", Sets.newHashSet(), parsedDockerfile.getDependencyImageNames()); + assertEquals( + "handles missing Dockerfiles gracefully", + Sets.newHashSet(), + parsedDockerfile.getDependencyImageNames() + ); } } diff --git a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java index d2ea3e7188a..592d46f33d1 100644 --- a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java +++ b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java @@ -9,7 +9,7 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; @@ -23,7 +23,7 @@ public void toStringContainsOnlyImageName() { } @Test - public void toStringWithExceptionContainsOnlyImageNameFuture() { + public void toStringWithExceptionContainsOnlyImageNameFuture() { CompletableFuture imageNameFuture = new CompletableFuture<>(); imageNameFuture.completeExceptionally(new RuntimeException("arbitrary")); @@ -31,8 +31,8 @@ public void toStringWithExceptionContainsOnlyImageNameFuture() { assertThat(remoteDockerImage.toString(), containsString("imageName=java.lang.RuntimeException: arbitrary")); } - @Test(timeout=5000L) - public void toStringDoesntResolveImageNameFuture() { + @Test(timeout = 5000L) + public void toStringDoesntResolveImageNameFuture() { CompletableFuture imageNameFuture = new CompletableFuture<>(); // verify that we've set up the test properly @@ -49,7 +49,7 @@ public void toStringDoesntResolveImageNameFuture() { assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); } - @Test(timeout=5000L) + @Test(timeout = 5000L) public void toStringDoesntResolveLazyFuture() throws Exception { String imageName = Base58.randomString(8).toLowerCase(); AtomicBoolean resolved = new AtomicBoolean(false); diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java index 9a9d647d71b..29cf4fcf6a7 100644 --- a/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java @@ -6,7 +6,6 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; -import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; @@ -18,39 +17,41 @@ public class DockerfileBuildTest { static final Path RESOURCE_PATH = Paths.get("src/test/resources/dockerfile-build-test"); public String expectedFileContent; + public ImageFromDockerfile image; @Parameterized.Parameters public static Object[][] parameters() { - return new Object[][]{ + return new Object[][] { // Dockerfile build without explicit per-file inclusion - new Object[]{"test1234", + new Object[] { + "test1234", + // spotless:off // docsShowRecursiveFileInclusion { new ImageFromDockerfile() - .withFileFromPath(".", RESOURCE_PATH) + .withFileFromPath(".", RESOURCE_PATH), // } + // spotless:on }, - // Dockerfile build using a non-standard Dockerfile - new Object[]{"test4567", - new ImageFromDockerfile() - .withFileFromPath(".", RESOURCE_PATH) - .withDockerfilePath("./Dockerfile-alt") + new Object[] { + "test4567", + new ImageFromDockerfile().withFileFromPath(".", RESOURCE_PATH).withDockerfilePath("./Dockerfile-alt"), }, - // Dockerfile build using build args - new Object[]{"test7890", + new Object[] { + "test7890", new ImageFromDockerfile() .withFileFromPath(".", RESOURCE_PATH) .withDockerfilePath("./Dockerfile-buildarg") - .withBuildArg("CUSTOM_ARG", "test7890") + .withBuildArg("CUSTOM_ARG", "test7890"), }, - - // Dockerfile build using withDockerfile(File) - new Object[]{"test4567", + // Dockerfile build using withDockerfile(File) + new Object[] { + "test4567", new ImageFromDockerfile() .withFileFromPath(".", RESOURCE_PATH) - .withDockerfile(RESOURCE_PATH.resolve("Dockerfile-alt")) + .withDockerfile(RESOURCE_PATH.resolve("Dockerfile-alt")), }, }; } @@ -62,14 +63,18 @@ public DockerfileBuildTest(String expectedFileContent, ImageFromDockerfile image @Test public void performTest() { - try (final GenericContainer container = new GenericContainer(image) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withCommand("cat", "/test.txt")) { + try ( + final GenericContainer container = new GenericContainer(image) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withCommand("cat", "/test.txt") + ) { container.start(); final String logs = container.getLogs(); - assertTrue("expected file content indicates that dockerfile build steps have been run", logs.contains(expectedFileContent)); + assertTrue( + "expected file content indicates that dockerfile build steps have been run", + logs.contains(expectedFileContent) + ); } } - } diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java index b99a70a7650..513b1ce1784 100644 --- a/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java @@ -24,10 +24,10 @@ public void testInvalidDockerignore() throws Exception { .withDockerfile(INVALID_DOCKERIGNORE_PATH.resolve("Dockerfile")) .get(); fail("Should not be able to build an image with an invalid .dockerignore file"); - } - catch (DockerClientException e) { - if (!e.getMessage().contains("Invalid pattern")) + } catch (DockerClientException e) { + if (!e.getMessage().contains("Invalid pattern")) { throw e; + } } } @@ -35,22 +35,24 @@ public void testInvalidDockerignore() throws Exception { @Test public void testValidDockerignore() throws Exception { ImageFromDockerfile img = new ImageFromDockerfile() - .withFileFromPath(".", DockerfileBuildTest.RESOURCE_PATH) - .withDockerfile(DockerfileBuildTest.RESOURCE_PATH.resolve("Dockerfile-currentdir")); - try( + .withFileFromPath(".", DockerfileBuildTest.RESOURCE_PATH) + .withDockerfile(DockerfileBuildTest.RESOURCE_PATH.resolve("Dockerfile-currentdir")); + try ( final GenericContainer container = new GenericContainer(DockerImageName.parse(img.get())) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withCommand("ls", "/") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withCommand("ls", "/") ) { - container.start(); final String logs = container.getLogs(); - assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, - logs.contains("should_not_be_ignored.txt")); - assertTrue("Files in the container indicated the .dockerignore was not applied. Output was: " + logs, - !logs.contains("should_be_ignored.txt")); + assertTrue( + "Files in the container indicated the .dockerignore was not applied. Output was: " + logs, + logs.contains("should_not_be_ignored.txt") + ); + assertTrue( + "Files in the container indicated the .dockerignore was not applied. Output was: " + logs, + !logs.contains("should_be_ignored.txt") + ); } } - } diff --git a/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java b/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java index da3509cea7b..abc05eb567c 100644 --- a/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/ImageFromDockerfileTest.java @@ -12,8 +12,7 @@ public class ImageFromDockerfileTest { @Test public void shouldAddDefaultLabels() { - ImageFromDockerfile image = new ImageFromDockerfile() - .withDockerfileFromBuilder(it -> it.from("scratch")); + ImageFromDockerfile image = new ImageFromDockerfile().withDockerfileFromBuilder(it -> it.from("scratch")); String imageId = image.resolve(); @@ -27,7 +26,10 @@ public void shouldAddDefaultLabels() { @Test public void shouldNotAddSessionLabelIfDeleteOnExitIsFalse() { - ImageFromDockerfile image = new ImageFromDockerfile("localhost/testcontainers/" + Base58.randomString(16).toLowerCase(), false) + ImageFromDockerfile image = new ImageFromDockerfile( + "localhost/testcontainers/" + Base58.randomString(16).toLowerCase(), + false + ) .withDockerfileFromBuilder(it -> it.from("scratch")); String imageId = image.resolve(); DockerClient dockerClient = DockerClientFactory.instance().client(); @@ -40,7 +42,5 @@ public void shouldNotAddSessionLabelIfDeleteOnExitIsFalse() { // ensure the image is deleted, even if the test fails dockerClient.removeImageCmd(imageId).exec(); } - } - } diff --git a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java index 15c73cadb5f..69d9a1b6840 100644 --- a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java @@ -19,7 +19,6 @@ public abstract class AbstractStatementTest { public TestName testName = new TestName(); protected void assertStatement(Statement statement) { - String[] expectedLines = new String[0]; try { String path = "fixtures/statements/" + getClass().getSimpleName() + "/" + testName.getMethodName(); @@ -39,7 +38,9 @@ protected void assertStatement(Statement statement) { String[] resultLines = StringUtils.chomp(builder.toString().trim()).split("\n"); if (expectedLines.length != resultLines.length) { - fail("number of lines is not the same. Expected " + expectedLines.length + " but got " + resultLines.length); + fail( + "number of lines is not the same. Expected " + expectedLines.length + " but got " + resultLines.length + ); } if (!Arrays.equals(expectedLines, resultLines)) { @@ -59,7 +60,6 @@ protected void assertStatement(Statement statement) { failureBuilder.append(expectedLine); failureBuilder.append(">\n"); } - } fail(failureBuilder.toString()); diff --git a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/KeyValuesStatementTest.java b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/KeyValuesStatementTest.java index 6add9d462f2..f446e48b42c 100644 --- a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/KeyValuesStatementTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/KeyValuesStatementTest.java @@ -9,11 +9,12 @@ public class KeyValuesStatementTest extends AbstractStatementTest { @Test public void multilineTest() throws Exception { - ImmutableMap pairs = ImmutableMap.builder() - .put("line1", "1") - .put("line2", "2") - .put("line3", "3") - .build(); + ImmutableMap pairs = ImmutableMap + .builder() + .put("line1", "1") + .put("line2", "2") + .put("line3", "3") + .build(); assertStatement(new KeyValuesStatement("TEST", pairs)); } @@ -35,12 +36,13 @@ public void keyWithTabsTest() throws Exception { @Test public void valueIsEscapedTest() throws Exception { - ImmutableMap pairs = ImmutableMap.builder() - .put("1", "value with spaces") - .put("2", "value\nwith\nnewlines") - .put("3", "value\twith\ttab") - .build(); + ImmutableMap pairs = ImmutableMap + .builder() + .put("1", "value with spaces") + .put("2", "value\nwith\nnewlines") + .put("3", "value\twith\ttab") + .build(); assertStatement(new KeyValuesStatement("TEST", pairs)); } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/MultiArgsStatementTest.java b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/MultiArgsStatementTest.java index 3b36af8861e..50bc8bedd96 100644 --- a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/MultiArgsStatementTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/MultiArgsStatementTest.java @@ -13,4 +13,4 @@ public void simpleTest() throws Exception { public void multilineTest() throws Exception { assertStatement(new MultiArgsStatement("TEST", "some\nmultiline\nargument")); } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/RawStatementTest.java b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/RawStatementTest.java index a600451bd71..70724a03f09 100644 --- a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/RawStatementTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/RawStatementTest.java @@ -8,5 +8,4 @@ public class RawStatementTest extends AbstractStatementTest { public void simpleTest() throws Exception { assertStatement(new RawStatement("TEST", "value\nas\t\\\nis")); } - -} \ No newline at end of file +} diff --git a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/SingleArgumentStatementTest.java b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/SingleArgumentStatementTest.java index 75d290b240d..dbdabab9fff 100644 --- a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/SingleArgumentStatementTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/SingleArgumentStatementTest.java @@ -13,4 +13,4 @@ public void simpleTest() throws Exception { public void multilineTest() throws Exception { assertStatement(new SingleArgumentStatement("TEST", "hello\nworld")); } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java b/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java index 7f8b5d79953..dd62ace1fac 100644 --- a/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java +++ b/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java @@ -15,7 +15,7 @@ import java.util.List; import java.util.stream.Collectors; -import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.is; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; @@ -37,7 +37,10 @@ public static void checkVersion() { @Test public void simpleTest() { - Jedis jedis = new Jedis(getEnvironment().getServiceHost("redis_1", REDIS_PORT), getEnvironment().getServicePort("redis_1", REDIS_PORT)); + Jedis jedis = new Jedis( + getEnvironment().getServiceHost("redis_1", REDIS_PORT), + getEnvironment().getServicePort("redis_1", REDIS_PORT) + ); jedis.incr("test"); jedis.incr("test"); @@ -49,7 +52,10 @@ public void simpleTest() { @Test public void secondTest() { // used in manual checking for cleanup in between tests - Jedis jedis = new Jedis(getEnvironment().getServiceHost("redis_1", REDIS_PORT), getEnvironment().getServicePort("redis_1", REDIS_PORT)); + Jedis jedis = new Jedis( + getEnvironment().getServiceHost("redis_1", REDIS_PORT), + getEnvironment().getServicePort("redis_1", REDIS_PORT) + ); jedis.incr("test"); jedis.incr("test"); @@ -62,18 +68,23 @@ public void secondTest() { @Before public void captureNetworks() { - existingNetworks.addAll(findAllNetworks()); + existingNetworks.addAll(findAllNetworks()); } @After public void verifyNoNetworks() { - assertThat("The networks", findAllNetworks(), is(existingNetworks)); + assertThat("The networks", findAllNetworks(), is(existingNetworks)); } private List findAllNetworks() { - return DockerClientFactory.instance().client().listNetworksCmd().exec().stream() - .map(Network::getName) - .sorted() - .collect(Collectors.toList()); + return DockerClientFactory + .instance() + .client() + .listNetworksCmd() + .exec() + .stream() + .map(Network::getName) + .sorted() + .collect(Collectors.toList()); } } diff --git a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java index b0ed90d9c9e..7041e74912a 100644 --- a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java @@ -1,6 +1,7 @@ package org.testcontainers.junit; import org.junit.Test; +import org.testcontainers.TestImages; import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.SelinuxContext; @@ -11,16 +12,17 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.TINY_IMAGE; public class CopyFileToContainerTest { + private static String containerPath = "/tmp/mappable-resource/"; + private static String fileName = "test-resource.txt"; @Test public void checkFileCopied() throws IOException, InterruptedException { try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withCommand("sleep", "3000") .withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), containerPath) ) { @@ -33,7 +35,7 @@ public void checkFileCopied() throws IOException, InterruptedException { @Test public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withCommand("sleep", "3000") .withClasspathResourceMapping("/mappable-resource/", containerPath, BindMode.READ_ONLY) ) { @@ -46,10 +48,9 @@ public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { @Test public void shouldUseCopyOnlyWithReadOnlyClasspathResources() { String resource = "/test_copy_to_container.txt"; - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withClasspathResourceMapping(resource, "/readOnly", BindMode.READ_ONLY) .withClasspathResourceMapping(resource, "/readOnlyNoSelinux", BindMode.READ_ONLY) - .withClasspathResourceMapping(resource, "/readOnlyShared", BindMode.READ_ONLY, SelinuxContext.SHARED) .withClasspathResourceMapping(resource, "/readWrite", BindMode.READ_WRITE); @@ -65,7 +66,7 @@ public void shouldUseCopyOnlyWithReadOnlyClasspathResources() { public void shouldCreateFoldersStructureWithCopy() throws Exception { String resource = "/test_copy_to_container.txt"; try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withCommand("sleep", "3000") .withClasspathResourceMapping(resource, "/a/b/c/file", BindMode.READ_ONLY) ) { diff --git a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java index bd82c58a7f7..78e55335d9a 100644 --- a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java +++ b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java @@ -3,6 +3,7 @@ import lombok.Getter; import org.junit.Test; import org.rnorth.visibleassertions.VisibleAssertions; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.lifecycle.Startable; @@ -16,8 +17,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.testcontainers.TestImages.TINY_IMAGE; - public class DependenciesTest { @Test @@ -25,7 +24,7 @@ public void shouldWorkWithSimpleDependency() { InvocationCountingStartable startable = new InvocationCountingStartable(); try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable) ) { @@ -42,7 +41,7 @@ public void shouldWorkWithMutlipleDependencies() { InvocationCountingStartable startable2 = new InvocationCountingStartable(); try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable1, startable2) ) { @@ -58,7 +57,7 @@ public void shouldStartEveryTime() { InvocationCountingStartable startable = new InvocationCountingStartable(); try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable) ) { @@ -85,7 +84,7 @@ public void shouldStartTransitiveDependencies() { startable.getDependencies().add(transitiveStartable); try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .dependsOn(startable) ) { @@ -94,8 +93,16 @@ public void shouldStartTransitiveDependencies() { } VisibleAssertions.assertEquals("Root started", 1, startable.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("Transitive started", 1, transitiveStartable.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("Transitive of transitive started", 1, transitiveOfTransitiveStartable.getStartInvocationCount().intValue()); + VisibleAssertions.assertEquals( + "Transitive started", + 1, + transitiveStartable.getStartInvocationCount().intValue() + ); + VisibleAssertions.assertEquals( + "Transitive of transitive started", + 1, + transitiveOfTransitiveStartable.getStartInvocationCount().intValue() + ); } @Test @@ -123,7 +130,8 @@ public void shouldHandleDiamondDependencies() throws Exception { @Test public void shouldHandleParallelStream() throws Exception { - List startables = Stream.generate(InvocationCountingStartable::new) + List startables = Stream + .generate(InvocationCountingStartable::new) .limit(10) .collect(Collectors.toList()); diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java index a44d8de49f4..651696696c7 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java @@ -24,25 +24,26 @@ public static void checkVersion() { } @Rule - public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/scaled-compose-test.yml")) - .withScaledService("redis", 3) - .withExposedService("redis", REDIS_PORT) // implicit '_1' - .withExposedService("redis_2", REDIS_PORT) // explicit service index - .withExposedService("redis", 3, REDIS_PORT); // explicit service index via parameter + public DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/scaled-compose-test.yml") + ) + .withScaledService("redis", 3) + .withExposedService("redis", REDIS_PORT) // implicit '_1' + .withExposedService("redis_2", REDIS_PORT) // explicit service index + .withExposedService("redis", 3, REDIS_PORT); // explicit service index via parameter @Before public void setupClients() { for (int i = 0; i < 3; i++) { - String name = String.format("redis_%d", i + 1); - clients[i] = new Jedis(environment.getServiceHost(name, REDIS_PORT), environment.getServicePort(name, REDIS_PORT)); + clients[i] = + new Jedis(environment.getServiceHost(name, REDIS_PORT), environment.getServicePort(name, REDIS_PORT)); } } @Test public void simpleTest() { - for (int i = 0; i < 3; i++) { clients[i].incr("somekey"); diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java index 17a9b665513..c49663a4e35 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java @@ -9,10 +9,9 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.Collections; import java.util.Optional; -import static java.lang.String.format; -import static java.util.Collections.singletonList; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; @@ -24,7 +23,9 @@ public class DockerComposeContainerTest extends BaseDockerComposeTest { @Rule - public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) + public DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/compose-test.yml") + ) .withExposedService("redis_1", REDIS_PORT) .withExposedService("db_1", 3306); @@ -46,34 +47,46 @@ public void testGetServicePort() { public void shouldRetrieveContainerByServiceName() { String existingServiceName = "db_1"; Optional result = environment.getContainerByServiceName(existingServiceName); - assertTrue(format("Container should be found by service name %s", existingServiceName), result.isPresent()); - assertEquals("Mapped port for result container was wrong, probably wrong container found", result.get().getExposedPorts(), singletonList(3306)); + assertTrue( + String.format("Container should be found by service name %s", existingServiceName), + result.isPresent() + ); + assertEquals( + "Mapped port for result container was wrong, probably wrong container found", + result.get().getExposedPorts(), + Collections.singletonList(3306) + ); } @Test public void shouldReturnEmptyResultOnNoneExistingService() { String notExistingServiceName = "db_256"; Optional result = environment.getContainerByServiceName(notExistingServiceName); - assertFalse(format("No container should be found under service name %s", notExistingServiceName), result.isPresent()); + assertFalse( + String.format("No container should be found under service name %s", notExistingServiceName), + result.isPresent() + ); } @Test public void shouldCreateContainerWhenFileNotPrefixedWithPath() throws IOException { String validYaml = "version: '2.2'\n" + - "services:\n" + - " http:\n" + - " build: .\n" + - " image: python:latest\n" + - " ports:\n" + - " - 8080:8080"; + "services:\n" + + " http:\n" + + " build: .\n" + + " image: python:latest\n" + + " ports:\n" + + " - 8080:8080"; File filePathNotStartWithDotSlash = new File("docker-compose-test.yml"); filePathNotStartWithDotSlash.createNewFile(); filePathNotStartWithDotSlash.deleteOnExit(); Files.write(filePathNotStartWithDotSlash.toPath(), validYaml.getBytes(StandardCharsets.UTF_8)); - final DockerComposeContainer dockerComposeContainer = new DockerComposeContainer<>(filePathNotStartWithDotSlash); + final DockerComposeContainer dockerComposeContainer = new DockerComposeContainer<>( + filePathNotStartWithDotSlash + ); assertNotNull("Container could not be created using docker compose file", dockerComposeContainer); } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java index 1b1efc878af..e0705a2c73b 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java @@ -14,30 +14,32 @@ import java.util.stream.Stream; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.containers.DockerComposeContainer.RemoveImages.ALL; -import static org.testcontainers.containers.DockerComposeContainer.RemoveImages.LOCAL; @RunWith(Parameterized.class) public class DockerComposeContainerWithBuildTest { - public DockerComposeContainerWithBuildTest(final DockerComposeContainer.RemoveImages removeMode, - final boolean shouldBuiltImageBePresentAfterRunning, - final boolean shouldPulledImageBePresentAfterRunning) { + public DockerComposeContainerWithBuildTest( + final DockerComposeContainer.RemoveImages removeMode, + final boolean shouldBuiltImageBePresentAfterRunning, + final boolean shouldPulledImageBePresentAfterRunning + ) { this.removeMode = removeMode; this.shouldBuiltImageBePresentAfterRunning = shouldBuiltImageBePresentAfterRunning; this.shouldPulledImageBePresentAfterRunning = shouldPulledImageBePresentAfterRunning; } public final DockerComposeContainer.RemoveImages removeMode; + public final boolean shouldBuiltImageBePresentAfterRunning; + public final boolean shouldPulledImageBePresentAfterRunning; @Parameterized.Parameters(name = "removeMode = {0}") public static Object[][] params() { - return new Object[][]{ - {null, true, true}, - {LOCAL, false, true}, - {ALL, false, false}, + return new Object[][] { + { null, true, true }, + { DockerComposeContainer.RemoveImages.LOCAL, false, true }, + { DockerComposeContainer.RemoveImages.ALL, false, false }, }; } @@ -47,11 +49,12 @@ public void performTest() { final AtomicReference builtImageName = new AtomicReference<>(""); final AtomicReference pulledImageName = new AtomicReference<>(""); - try (DockerComposeContainer environment = new DockerComposeContainer<>(composeFile) - .withExposedService("customredis", 6379) - .withBuild(true) - .withRemoveImages(removeMode)) { - + try ( + DockerComposeContainer environment = new DockerComposeContainer<>(composeFile) + .withExposedService("customredis", 6379) + .withBuild(true) + .withRemoveImages(removeMode) + ) { environment.start(); builtImageName.set(imageNameForRunningContainer("_customredis_1")); @@ -63,21 +66,42 @@ public void performTest() { assertEquals("the pulled image is present while running", true, isPulledImagePresentWhileRunning); } - Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { - final boolean isBuiltImagePresentAfterRunning = isImagePresent(builtImageName.get()); - assertEquals("the built image is not present after running", shouldBuiltImageBePresentAfterRunning, isBuiltImagePresentAfterRunning); - return null; - }); - - Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { - final boolean isPulledImagePresentAfterRunning = isImagePresent(pulledImageName.get()); - assertEquals("the pulled image is present after running", shouldPulledImageBePresentAfterRunning, isPulledImagePresentAfterRunning); - return null; - }); + Unreliables.retryUntilSuccess( + 10, + TimeUnit.SECONDS, + () -> { + final boolean isBuiltImagePresentAfterRunning = isImagePresent(builtImageName.get()); + assertEquals( + "the built image is not present after running", + shouldBuiltImageBePresentAfterRunning, + isBuiltImagePresentAfterRunning + ); + return null; + } + ); + + Unreliables.retryUntilSuccess( + 10, + TimeUnit.SECONDS, + () -> { + final boolean isPulledImagePresentAfterRunning = isImagePresent(pulledImageName.get()); + assertEquals( + "the pulled image is present after running", + shouldPulledImageBePresentAfterRunning, + isPulledImagePresentAfterRunning + ); + return null; + } + ); } private String imageNameForRunningContainer(final String containerNameSuffix) { - return DockerClientFactory.instance().client().listContainersCmd().exec().stream() + return DockerClientFactory + .instance() + .client() + .listContainersCmd() + .exec() + .stream() .filter(it -> Stream.of(it.getNames()).anyMatch(name -> name.endsWith(containerNameSuffix))) .findFirst() .map(Container::getImage) @@ -85,7 +109,13 @@ private String imageNameForRunningContainer(final String containerNameSuffix) { } private boolean isImagePresent(final String imageName) { - return DockerClientFactory.instance().client().listImagesCmd().withImageNameFilter(imageName).exec().stream() + return DockerClientFactory + .instance() + .client() + .listImagesCmd() + .withImageNameFilter(imageName) + .exec() + .stream() .findFirst() .isPresent(); } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java index 375c9baa070..77e60580b39 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithOptionsTest.java @@ -17,7 +17,12 @@ @RunWith(Parameterized.class) public class DockerComposeContainerWithOptionsTest { - public DockerComposeContainerWithOptionsTest(final File composeFile, final boolean local, final Set options, final boolean expectError) { + public DockerComposeContainerWithOptionsTest( + final File composeFile, + final boolean local, + final Set options, + final boolean expectError + ) { this.composeFile = composeFile; this.local = local; this.options = options; @@ -25,38 +30,60 @@ public DockerComposeContainerWithOptionsTest(final File composeFile, final boole } private final File composeFile; + private final boolean local; private final Set options; - private final boolean expectError; - @Parameterized.Parameters(name = "docker-compose test [compose file: {0}, local: {1}, options: {2}, expected result: {3}]") + private final boolean expectError; + @Parameterized.Parameters( + name = "docker-compose test [compose file: {0}, local: {1}, options: {2}, expected result: {3}]" + ) public static Object[][] params() { - return new Object[][]{ + return new Object[][] { // Test the happy day case. THe compatibility option should be accepted by docker-compose. - {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), false, ImmutableSet.of("--compatibility"), false}, + { + new File("src/test/resources/compose-options-test/with-deploy-block.yml"), + false, + ImmutableSet.of("--compatibility"), + false, + }, // Test with flags absent. Docker compose will warn but continue, ignoring the deploy block. - {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), false, ImmutableSet.of(""), false}, + { + new File("src/test/resources/compose-options-test/with-deploy-block.yml"), + false, + ImmutableSet.of(""), + false, + }, // Test with a bad option. Compose will complain. - {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), false, ImmutableSet.of("--bad-option"), true}, + { + new File("src/test/resources/compose-options-test/with-deploy-block.yml"), + false, + ImmutableSet.of("--bad-option"), + true, + }, // Local compose - {new File("src/test/resources/compose-options-test/with-deploy-block.yml"), true, ImmutableSet.of("--compatibility"), false}, + { + new File("src/test/resources/compose-options-test/with-deploy-block.yml"), + true, + ImmutableSet.of("--compatibility"), + false, + }, }; } @Test public void performTest() { - - try (DockerComposeContainer environment = new DockerComposeContainer<>(composeFile) + try ( + DockerComposeContainer environment = new DockerComposeContainer<>(composeFile) .withOptions(options.stream().toArray(String[]::new)) - .withLocalCompose(local)) { + .withLocalCompose(local) + ) { environment.start(); assertThat(expectError).isEqualTo(false); } catch (Exception e) { assertThat(expectError).isEqualTo(true); } - } - } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java index b8e26ffd3f1..51f09bdb095 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java @@ -10,11 +10,15 @@ public class DockerComposeErrorHandlingTest { @Test public void simpleTest() { - VisibleAssertions.assertThrows("starting with an invalid docker-compose file throws an exception", + VisibleAssertions.assertThrows( + "starting with an invalid docker-compose file throws an exception", IllegalArgumentException.class, - () -> { - DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/invalid-compose.yml")) - .withExposedService("something", 123); - }); + () -> { + DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/invalid-compose.yml") + ) + .withExposedService("something", 123); + } + ); } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeLocalImageTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeLocalImageTest.java index 890fa34b0f8..dd2054e1e2e 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeLocalImageTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeLocalImageTest.java @@ -14,7 +14,9 @@ public class DockerComposeLocalImageTest { public void usesLocalImageEvenWhenPullFails() throws InterruptedException { tagImage("redis:4.0.10", "redis-local", "latest"); - DockerComposeContainer composeContainer = new DockerComposeContainer(new File("src/test/resources/local-compose-test.yml")) + DockerComposeContainer composeContainer = new DockerComposeContainer( + new File("src/test/resources/local-compose-test.yml") + ) .withExposedService("redis", 6379); composeContainer.start(); } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeLogConsumerTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeLogConsumerTest.java index 6cd90d3cd9c..97e686a9b92 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeLogConsumerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeLogConsumerTest.java @@ -3,26 +3,36 @@ import org.junit.Test; import org.junit.runner.Description; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.output.OutputFrame.OutputType; import org.testcontainers.containers.output.WaitingConsumer; import java.io.File; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; - public class DockerComposeLogConsumerTest { @Test public void testLogConsumer() throws TimeoutException { WaitingConsumer logConsumer = new WaitingConsumer(); - DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/v2-compose-test.yml")) + DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/v2-compose-test.yml") + ) .withExposedService("redis_1", 6379) .withLogConsumer("redis_1", logConsumer); try { environment.starting(Description.EMPTY); - logConsumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("Ready to accept connections"), 5, TimeUnit.SECONDS); + logConsumer.waitUntil( + frame -> { + return ( + frame.getType() == OutputType.STDOUT && + frame.getUtf8String().contains("Ready to accept connections") + ); + }, + 5, + TimeUnit.SECONDS + ); } finally { environment.finished(Description.EMPTY); } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java index cdeea00d201..c026bcaa741 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java @@ -13,7 +13,7 @@ import java.util.Arrays; import java.util.Objects; -import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.Matchers.hasItem; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; @@ -30,25 +30,27 @@ public static void checkVersion() { } @Rule - public DockerComposeContainer compose = - new DockerComposeContainer(new File("src/test/resources/v2-compose-test-passthrough.yml")) - .withEnv("foo", "bar") - .withExposedService("alpine_1", 3000, waitStrategy); - + public DockerComposeContainer compose = new DockerComposeContainer( + new File("src/test/resources/v2-compose-test-passthrough.yml") + ) + .withEnv("foo", "bar") + .withExposedService("alpine_1", 3000, waitStrategy); @Test public void testContainerInstanceProperties() { final ContainerState container = waitStrategy.getContainer(); //check environment variable was set - assertThat("Environment variable set correctly", Arrays.asList(Objects.requireNonNull(container.getContainerInfo() - .getConfig().getEnv())), hasItem("bar=bar")); + assertThat( + "Environment variable set correctly", + Arrays.asList(Objects.requireNonNull(container.getContainerInfo().getConfig().getEnv())), + hasItem("bar=bar") + ); //check other container properties assertNotNull("Container id is not null", container.getContainerId()); assertNotNull("Port mapped", container.getMappedPort(3000)); assertThat("Exposed Ports", container.getExposedPorts(), hasItem(3000)); - } /* diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java index ec8c50d42ab..5e6ba4cc30f 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java @@ -4,17 +4,18 @@ import org.junit.Test; import org.testcontainers.containers.DockerComposeContainer; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; - import java.io.File; +import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; + public class DockerComposeServiceTest extends BaseDockerComposeTest { @Rule - public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withServices("redis") - .withExposedService("redis_1", REDIS_PORT); - + public DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/compose-test.yml") + ) + .withServices("redis") + .withExposedService("redis_1", REDIS_PORT); @Override protected DockerComposeContainer getEnvironment() { diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeV2FormatTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeV2FormatTest.java index bed19bd0d09..f3dc2ee3cc8 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeV2FormatTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeV2FormatTest.java @@ -11,8 +11,10 @@ public class DockerComposeV2FormatTest extends BaseDockerComposeTest { @Rule - public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/v2-compose-test.yml")) - .withExposedService("redis_1", REDIS_PORT); + public DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/v2-compose-test.yml") + ) + .withExposedService("redis_1", REDIS_PORT); @Override protected DockerComposeContainer getEnvironment() { diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java index 26764476687..b28dfc3ee51 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java @@ -1,21 +1,20 @@ package org.testcontainers.junit; -import java.io.File; - import org.junit.Rule; import org.testcontainers.containers.DockerComposeContainer; +import java.io.File; + public class DockerComposeV2WithNetworkTest extends BaseDockerComposeTest { @Rule - public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/v2-compose-test-with-network.yml")) - .withExposedService("redis_1", REDIS_PORT); + public DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/v2-compose-test-with-network.yml") + ) + .withExposedService("redis_1", REDIS_PORT); @Override protected DockerComposeContainer getEnvironment() { return environment; } - - - } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java index 32465010700..a30c716964e 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java @@ -1,10 +1,5 @@ package org.testcontainers.junit; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; - -import java.io.File; -import java.time.Duration; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -15,6 +10,12 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import java.io.File; +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + public class DockerComposeWaitStrategyTest { private static final int REDIS_PORT = 6379; @@ -23,8 +24,7 @@ public class DockerComposeWaitStrategyTest { @Before public final void setUp() { - environment = new DockerComposeContainer<>( - new File("src/test/resources/compose-test.yml")); + environment = new DockerComposeContainer<>(new File("src/test/resources/compose-test.yml")); } @After @@ -34,14 +34,15 @@ public final void cleanUp() { @Test public void testWaitOnListeningPort() { - environment - .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()); + environment.withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()); try { environment.starting(Description.createTestDescription(Object.class, "name")); VisibleAssertions.pass("Docker compose should start after waiting for listening port"); } catch (RuntimeException e) { - VisibleAssertions.fail("Docker compose should start after waiting for listening port with failed with: " + e); + VisibleAssertions.fail( + "Docker compose should start after waiting for listening port with failed with: " + e + ); } } @@ -56,29 +57,45 @@ public void testWaitOnMultipleStrategiesPassing() { environment.starting(Description.createTestDescription(Object.class, "name")); VisibleAssertions.pass("Docker compose should start after waiting for listening port"); } catch (RuntimeException e) { - VisibleAssertions.fail("Docker compose should start after waiting for listening port with failed with: " + e); + VisibleAssertions.fail( + "Docker compose should start after waiting for listening port with failed with: " + e + ); } } @Test public void testWaitingFails() { - environment - .withExposedService("redis_1", REDIS_PORT, Wait.forHttp("/test").withStartupTimeout(Duration.ofSeconds(10))); - VisibleAssertions.assertThrows("waiting on an invalid http path times out", + environment.withExposedService( + "redis_1", + REDIS_PORT, + Wait.forHttp("/test").withStartupTimeout(Duration.ofSeconds(10)) + ); + VisibleAssertions.assertThrows( + "waiting on an invalid http path times out", RuntimeException.class, - () -> environment.starting(Description.createTestDescription(Object.class, "name"))); + () -> environment.starting(Description.createTestDescription(Object.class, "name")) + ); } @Test public void testWaitOnOneOfMultipleStrategiesFailing() { environment - .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(10))) - .waitingFor("db_1", Wait.forLogMessage(".*test test test.*\\s", 1).withStartupTimeout(Duration.ofSeconds(10))) + .withExposedService( + "redis_1", + REDIS_PORT, + Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(10)) + ) + .waitingFor( + "db_1", + Wait.forLogMessage(".*test test test.*\\s", 1).withStartupTimeout(Duration.ofSeconds(10)) + ) .withTailChildContainers(true); - VisibleAssertions.assertThrows("waiting on one failing strategy to time out", + VisibleAssertions.assertThrows( + "waiting on one failing strategy to time out", RuntimeException.class, - () -> environment.starting(Description.createTestDescription(Object.class, "name"))); + () -> environment.starting(Description.createTestDescription(Object.class, "name")) + ); } @Test @@ -93,14 +110,11 @@ public void testWaitingForNonexistentServices() { .waitingFor(nonexistentServiceName1, someWaitStrategy) .waitingFor(nonexistentServiceName2, someWaitStrategy); - Throwable thrownWhenRequestedToWaitForNonexistentService = - catchThrowable(environment::start); + Throwable thrownWhenRequestedToWaitForNonexistentService = catchThrowable(environment::start); assertThat(thrownWhenRequestedToWaitForNonexistentService) .isInstanceOf(IllegalStateException.class) - .hasMessageContaining( - nonexistentServiceName1, - nonexistentServiceName2) + .hasMessageContaining(nonexistentServiceName1, nonexistentServiceName2) .hasMessageNotContaining(existentServiceName); } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java index 59c2a63127c..7962b87e157 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java @@ -3,12 +3,12 @@ import com.github.dockerjava.api.model.NetworkSettings; import lombok.extern.slf4j.Slf4j; import org.junit.Test; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.TINY_IMAGE; /** * Simple tests of named network modes - more may be possible, but may not be reproducible @@ -20,7 +20,7 @@ public class DockerNetworkModeTest { @Test public void testNoNetworkContainer() { try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCommand("true") .withNetworkMode("none") @@ -36,7 +36,7 @@ public void testNoNetworkContainer() { @Test public void testHostNetworkContainer() { try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCommand("true") .withNetworkMode("host") diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java index 6ad7c3ea26e..715ba3f64a1 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java @@ -21,13 +21,16 @@ public class DockerfileContainerTest { @Rule public GenericContainer dslContainer = new GenericContainer( - new ImageFromDockerfile("tcdockerfile/nginx", false).withDockerfileFromBuilder(builder -> { - builder - .from("alpine:3.2") - .run("apk add --update nginx") - .cmd("nginx", "-g", "daemon off;") - .build(); })) - .withExposedPorts(80); + new ImageFromDockerfile("tcdockerfile/nginx", false) + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.2") // + .run("apk add --update nginx") + .cmd("nginx", "-g", "daemon off;") + .build(); + }) + ) + .withExposedPorts(80); @Test public void simpleDslTest() throws IOException { @@ -37,11 +40,15 @@ public void simpleDslTest() throws IOException { HttpGet get = new HttpGet(address); try (CloseableHttpResponse response = httpClient.execute(get)) { - assertEquals("A container built from a dockerfile can run nginx as expected, and returns a good status code", - 200, - response.getStatusLine().getStatusCode()); - assertTrue("A container built from a dockerfile can run nginx as expected, and returns an expected Server header", - response.getHeaders("Server")[0].getValue().contains("nginx")); + assertEquals( + "A container built from a dockerfile can run nginx as expected, and returns a good status code", + 200, + response.getStatusLine().getStatusCode() + ); + assertTrue( + "A container built from a dockerfile can run nginx as expected, and returns an expected Server header", + response.getHeaders("Server")[0].getValue().contains("nginx") + ); } } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java index 2197d7be0e7..e121e7db5a4 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.WaitingConsumer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.images.builder.ImageFromDockerfile; @@ -16,7 +17,6 @@ import java.util.concurrent.TimeoutException; import static org.rnorth.visibleassertions.VisibleAssertions.pass; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; public class DockerfileTest { @@ -25,9 +25,9 @@ public class DockerfileTest { @Test public void simpleDockerfileWorks() { ImageFromDockerfile image = new ImageFromDockerfile() - .withFileFromString("folder/someFile.txt", "hello") - .withFileFromClasspath("test.txt", "mappable-resource/test-resource.txt") - .withFileFromClasspath("Dockerfile", "mappable-dockerfile/Dockerfile"); + .withFileFromString("folder/someFile.txt", "hello") + .withFileFromClasspath("test.txt", "mappable-resource/test-resource.txt") + .withFileFromClasspath("Dockerfile", "mappable-dockerfile/Dockerfile"); verifyImage(image); } @@ -40,9 +40,9 @@ protected void configure(BuildImageCmd buildImageCmd) { super.configure(buildImageCmd); List dockerfile = Arrays.asList( - "FROM alpine:3.14", - "RUN echo 'hello from Docker build process'", - "CMD yes" + "FROM alpine:3.14", + "RUN echo 'hello from Docker build process'", + "CMD yes" ); withFileFromString("Dockerfile", String.join("\n", dockerfile)); @@ -56,28 +56,30 @@ protected void configure(BuildImageCmd buildImageCmd) { @Test public void dockerfileBuilderWorks() { ImageFromDockerfile image = new ImageFromDockerfile() - .withFileFromClasspath("test.txt", "mappable-resource/test-resource.txt") - .withFileFromString("folder/someFile.txt", "hello") - .withDockerfileFromBuilder(builder -> builder - .from("alpine:3.14") - .workDir("/app") - .add("test.txt", "test file.txt") - .run("ls", "-la", "/app/test file.txt") - .copy("folder/someFile.txt", "/someFile.txt") - .expose(80, 8080) - .cmd("while true; do cat /someFile.txt | nc -l -p 80; done") - ); + .withFileFromClasspath("test.txt", "mappable-resource/test-resource.txt") + .withFileFromString("folder/someFile.txt", "hello") + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.14") + .workDir("/app") + .add("test.txt", "test file.txt") + .run("ls", "-la", "/app/test file.txt") + .copy("folder/someFile.txt", "/someFile.txt") + .expose(80, 8080) + .cmd("while true; do cat /someFile.txt | nc -l -p 80; done"); + }); verifyImage(image); } @Test public void filePermissions() throws TimeoutException { - WaitingConsumer consumer = new WaitingConsumer(); ImageFromDockerfile image = new ImageFromDockerfile() - .withFileFromTransferable("/someFile.txt", new Transferable() { + .withFileFromTransferable( + "/someFile.txt", + new Transferable() { @Override public long getSize() { return 0; @@ -97,23 +99,27 @@ public String getDescription() { public int getFileMode() { return 0123; } - - - }) - .withDockerfileFromBuilder(builder -> builder - .from("alpine:3.14") - .copy("someFile.txt", "/someFile.txt") - .cmd("stat -c \"%a\" /someFile.txt") - ); + } + ) + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.14") // + .copy("someFile.txt", "/someFile.txt") + .cmd("stat -c \"%a\" /someFile.txt"); + }); GenericContainer container = new GenericContainer(image) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withLogConsumer(consumer); + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withLogConsumer(consumer); try { container.start(); - consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("123"), 5, TimeUnit.SECONDS); + consumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("123"), + 5, + TimeUnit.SECONDS + ); } finally { container.stop(); } diff --git a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java index beca4a8a49f..e61721f80c4 100644 --- a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java +++ b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java @@ -7,6 +7,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.utility.MountableFile; @@ -16,7 +17,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.ALPINE_IMAGE; public class FileOperationsTest { @@ -26,7 +26,7 @@ public class FileOperationsTest { @Test public void copyFileToContainerFileTest() throws Exception { try ( - GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) + GenericContainer alpineCopyToContainer = new GenericContainer(TestImages.ALPINE_IMAGE) // .withCommand("top") ) { alpineCopyToContainer.start(); @@ -44,7 +44,7 @@ public void copyFileToContainerFileTest() throws Exception { @Test public void copyFileToContainerFolderTest() throws Exception { try ( - GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) + GenericContainer alpineCopyToContainer = new GenericContainer(TestImages.ALPINE_IMAGE) // .withCommand("top") ) { alpineCopyToContainer.start(); @@ -62,10 +62,9 @@ public void copyFileToContainerFolderTest() throws Exception { @Test public void copyFolderToContainerFolderTest() throws Exception { try ( - GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) + GenericContainer alpineCopyToContainer = new GenericContainer(TestImages.ALPINE_IMAGE) // .withCommand("top") ) { - alpineCopyToContainer.start(); final MountableFile mountableFile = MountableFile.forClasspathResource("mappable-resource/"); alpineCopyToContainer.copyFileToContainer(mountableFile, "/home/test/"); @@ -81,7 +80,7 @@ public void copyFolderToContainerFolderTest() throws Exception { @Test(expected = NotFoundException.class) public void copyFromContainerShouldFailBecauseNoFileTest() throws NotFoundException { try ( - GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) + GenericContainer alpineCopyToContainer = new GenericContainer(TestImages.ALPINE_IMAGE) // .withCommand("top") ) { alpineCopyToContainer.start(); @@ -92,10 +91,9 @@ public void copyFromContainerShouldFailBecauseNoFileTest() throws NotFoundExcept @Test public void shouldCopyFileFromContainerTest() throws IOException { try ( - GenericContainer alpineCopyToContainer = new GenericContainer(ALPINE_IMAGE) + GenericContainer alpineCopyToContainer = new GenericContainer(TestImages.ALPINE_IMAGE) // .withCommand("top") ) { - alpineCopyToContainer.start(); final MountableFile mountableFile = MountableFile.forClasspathResource("test_copy_to_container.txt"); alpineCopyToContainer.copyFileToContainer(mountableFile, "/home/"); @@ -110,7 +108,7 @@ public void shouldCopyFileFromContainerTest() throws IOException { @Test public void copyFileOperationsShouldFailWhenNotStartedTest() { - try (GenericContainer container = new GenericContainer<>(ALPINE_IMAGE).withCommand("top")) { + try (GenericContainer container = new GenericContainer<>(TestImages.ALPINE_IMAGE).withCommand("top")) { Assertions .assertThatThrownBy(() -> { MountableFile mountableFile = MountableFile.forClasspathResource("test_copy_to_container.txt"); @@ -121,10 +119,7 @@ public void copyFileOperationsShouldFailWhenNotStartedTest() { Assertions .assertThatThrownBy(() -> { - container.copyFileFromContainer( - "/home/test_copy_to_container.txt", - IOUtils::toByteArray - ); + container.copyFileFromContainer("/home/test_copy_to_container.txt", IOUtils::toByteArray); }) .isInstanceOf(IllegalStateException.class) .hasMessageContaining("can only be used when the Container is created"); @@ -134,18 +129,17 @@ public void copyFileOperationsShouldFailWhenNotStartedTest() { @Test public void shouldCopyFileFromExitedContainerTest() throws IOException { try ( - GenericContainer container = new GenericContainer<>(ALPINE_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.ALPINE_IMAGE) .withCommand("sh", "-c", "echo -n 'Hello!' > /home/file_in_container.txt") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) ) { container.start(); - assertThat(container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode()) + assertThat( + container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode() + ) .isEqualTo(0); - container.copyFileFromContainer( - "/home/file_in_container.txt", - IOUtils::toByteArray - ); + container.copyFileFromContainer("/home/file_in_container.txt", IOUtils::toByteArray); container.copyFileToContainer( MountableFile.forClasspathResource("test_copy_to_container.txt"), diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index 02fad53fb1e..a6bb13d160c 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -3,6 +3,7 @@ import com.google.common.util.concurrent.Uninterruptibles; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.TestImages; import org.testcontainers.containers.FixedHostPortGenericContainer; import org.testcontainers.containers.GenericContainer; @@ -12,9 +13,8 @@ import java.net.Socket; import java.util.concurrent.TimeUnit; -import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; -import static org.testcontainers.TestImages.TINY_IMAGE; +import static org.hamcrest.Matchers.equalTo; /** * Test of {@link FixedHostPortGenericContainer}. Note that this is not an example of typical use (usually, a container @@ -39,15 +39,18 @@ public class FixedHostPortContainerTest { /** * *nix pipe to fire test response on test port */ - private static final String HTTP_ECHO_CMD = - String.format("while true; do echo \"%s\" | nc -l -p %d; done", TEST_RESPONSE, TEST_PORT); + private static final String HTTP_ECHO_CMD = String.format( + "while true; do echo \"%s\" | nc -l -p %d; done", + TEST_RESPONSE, + TEST_PORT + ); @Test public void testFixedHostPortMapping() throws IOException { // first find a free port on the docker host that will work for testing final Integer unusedHostPort; try ( - final GenericContainer echoServer = new GenericContainer(TINY_IMAGE) + final GenericContainer echoServer = new GenericContainer(TestImages.TINY_IMAGE) .withExposedPorts(TEST_PORT) .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) ) { @@ -58,15 +61,18 @@ public void testFixedHostPortMapping() throws IOException { // now starting echo server container mapped to known-as-free host port try ( final GenericContainer echoServer = new FixedHostPortGenericContainer(TEST_IMAGE) - // using workaround for port bind+expose - .withFixedExposedPort(unusedHostPort, TEST_PORT) - .withExposedPorts(TEST_PORT) - .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) + // using workaround for port bind+expose + .withFixedExposedPort(unusedHostPort, TEST_PORT) + .withExposedPorts(TEST_PORT) + .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) ) { echoServer.start(); - assertThat("Port mapping does not seem to match given fixed port", - echoServer.getMappedPort(TEST_PORT), equalTo(unusedHostPort)); + assertThat( + "Port mapping does not seem to match given fixed port", + echoServer.getMappedPort(TEST_PORT), + equalTo(unusedHostPort) + ); final String content = this.readResponse(echoServer, unusedHostPort); assertThat("Returned echo from fixed port does not match expected", content, equalTo(TEST_RESPONSE)); @@ -83,7 +89,9 @@ public void testFixedHostPortMapping() throws IOException { */ private String readResponse(GenericContainer container, Integer port) throws IOException { try ( - final BufferedReader reader = Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, + final BufferedReader reader = Unreliables.retryUntilSuccess( + 10, + TimeUnit.SECONDS, () -> { Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); final Socket socket = new Socket(container.getHost(), port); diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index c13421029e0..8c696585902 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -21,8 +21,11 @@ import org.junit.Test; import org.rnorth.ducttape.RetryCountExceededException; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.TestImages; +import org.testcontainers.containers.BindMode; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.SelinuxContext; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.utility.Base58; import org.testcontainers.utility.TestEnvironment; @@ -37,27 +40,19 @@ import java.net.Socket; import java.time.Duration; import java.util.Arrays; +import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static java.util.Collections.singletonMap; -import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.Matchers.equalTo; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.ALPINE_IMAGE; -import static org.testcontainers.TestImages.MONGODB_IMAGE; -import static org.testcontainers.TestImages.RABBITMQ_IMAGE; -import static org.testcontainers.TestImages.REDIS_IMAGE; -import static org.testcontainers.TestImages.TINY_IMAGE; -import static org.testcontainers.containers.BindMode.READ_ONLY; -import static org.testcontainers.containers.BindMode.READ_WRITE; -import static org.testcontainers.containers.SelinuxContext.SHARED; /** * Tests for GenericContainerRules @@ -65,12 +60,16 @@ public class GenericContainerRuleTest { private static final int REDIS_PORT = 6379; + private static final String RABBIQMQ_TEST_EXCHANGE = "TestExchange"; + private static final String RABBITMQ_TEST_ROUTING_KEY = "TestRoutingKey"; + private static final String RABBITMQ_TEST_MESSAGE = "Hello world"; + private static final int RABBITMQ_PORT = 5672; - private static final int MONGO_PORT = 27017; + private static final int MONGO_PORT = 27017; /* * Test data setup @@ -86,77 +85,79 @@ public static void setupContent() throws FileNotFoundException { * Redis */ @ClassRule - public static GenericContainer redis = new GenericContainer<>(REDIS_IMAGE) - .withExposedPorts(REDIS_PORT); + public static GenericContainer redis = new GenericContainer<>(TestImages.REDIS_IMAGE) + .withExposedPorts(REDIS_PORT); /** * RabbitMQ */ @ClassRule - public static GenericContainer rabbitMq = new GenericContainer<>(RABBITMQ_IMAGE) - .withExposedPorts(RABBITMQ_PORT); + public static GenericContainer rabbitMq = new GenericContainer<>(TestImages.RABBITMQ_IMAGE) + .withExposedPorts(RABBITMQ_PORT); + /** * MongoDB */ @ClassRule - public static GenericContainer mongo = new GenericContainer<>(MONGODB_IMAGE) - .withExposedPorts(MONGO_PORT); + public static GenericContainer mongo = new GenericContainer<>(TestImages.MONGODB_IMAGE) + .withExposedPorts(MONGO_PORT); + /** * Pass an environment variable to the container, then run a shell script that exposes the variable in a quick and * dirty way for testing. */ @ClassRule - public static GenericContainer alpineEnvVar = new GenericContainer<>(ALPINE_IMAGE) - .withExposedPorts(80) - .withEnv("MAGIC_NUMBER", "4") - .withEnv("MAGIC_NUMBER", oldValue -> oldValue.orElse("") + "2") - .withCommand("/bin/sh", "-c", "while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"); + public static GenericContainer alpineEnvVar = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withExposedPorts(80) + .withEnv("MAGIC_NUMBER", "4") + .withEnv("MAGIC_NUMBER", oldValue -> oldValue.orElse("") + "2") + .withCommand("/bin/sh", "-c", "while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"); /** * Pass environment variables to the container, then run a shell script that exposes the variables in a quick and * dirty way for testing. */ @ClassRule - public static GenericContainer alpineEnvVarFromMap = new GenericContainer<>(ALPINE_IMAGE) - .withExposedPorts(80) - .withEnv(ImmutableMap.of( - "FIRST", "42", - "SECOND", "50" - )) - .withCommand("/bin/sh", "-c", "while true; do echo \"$FIRST and $SECOND\" | nc -l -p 80; done"); + public static GenericContainer alpineEnvVarFromMap = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withExposedPorts(80) + .withEnv(ImmutableMap.of("FIRST", "42", "SECOND", "50")) + .withCommand("/bin/sh", "-c", "while true; do echo \"$FIRST and $SECOND\" | nc -l -p 80; done"); /** * Map a file on the classpath to a file in the container, and then expose the content for testing. */ @ClassRule - public static GenericContainer alpineClasspathResource = new GenericContainer<>(ALPINE_IMAGE) - .withExposedPorts(80) - .withClasspathResourceMapping("mappable-resource/test-resource.txt", "/content.txt", READ_ONLY) - .withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done"); + public static GenericContainer alpineClasspathResource = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withExposedPorts(80) + .withClasspathResourceMapping("mappable-resource/test-resource.txt", "/content.txt", BindMode.READ_ONLY) + .withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done"); /** * Map a file on the classpath to a file in the container, and then expose the content for testing. */ @ClassRule - public static GenericContainer alpineClasspathResourceSelinux = new GenericContainer<>(ALPINE_IMAGE) - .withExposedPorts(80) - .withClasspathResourceMapping("mappable-resource/test-resource.txt", "/content.txt", READ_WRITE, SHARED) - .withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done"); + public static GenericContainer alpineClasspathResourceSelinux = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withExposedPorts(80) + .withClasspathResourceMapping( + "mappable-resource/test-resource.txt", + "/content.txt", + BindMode.READ_WRITE, + SelinuxContext.SHARED + ) + .withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done"); /** * Create a container with an extra host entry and expose the content of /etc/hosts for testing. */ @ClassRule - public static GenericContainer alpineExtrahost = new GenericContainer<>(ALPINE_IMAGE) - .withExposedPorts(80) - .withExtraHost("somehost", "192.168.1.10") - .withCommand("/bin/sh", "-c", "while true; do cat /etc/hosts | nc -l -p 80; done"); + public static GenericContainer alpineExtrahost = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withExposedPorts(80) + .withExtraHost("somehost", "192.168.1.10") + .withCommand("/bin/sh", "-c", "while true; do cat /etc/hosts | nc -l -p 80; done"); @Test public void testIsRunning() { - try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) - .withCommand("top")) { + try (GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE).withCommand("top")) { assertFalse("Container is not started and not running", container.isRunning()); container.start(); assertTrue("Container is started and running", container.isRunning()); @@ -166,16 +167,19 @@ public void testIsRunning() { @Test public void withTmpFsTest() throws Exception { try ( - GenericContainer container = new GenericContainer<>(TINY_IMAGE) + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withCommand("top") - .withTmpFs(singletonMap("/testtmpfs", "rw")) + .withTmpFs(Collections.singletonMap("/testtmpfs", "rw")) ) { container.start(); // check file doesn't exist String path = "/testtmpfs/test.file"; Container.ExecResult execResult = container.execInContainer("ls", path); - assertEquals("tmpfs inside container works fine", execResult.getStderr(), - "ls: /testtmpfs/test.file: No such file or directory\n"); + assertEquals( + "tmpfs inside container works fine", + execResult.getStderr(), + "ls: /testtmpfs/test.file: No such file or directory\n" + ); // touch && check file does exist container.execInContainer("touch", path); execResult = container.execInContainer("ls", path); @@ -183,7 +187,6 @@ public void withTmpFsTest() throws Exception { } } - @Test public void simpleRabbitMqTest() throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); @@ -198,23 +201,39 @@ public void simpleRabbitMqTest() throws IOException, TimeoutException { // Set up a consumer on the queue final boolean[] messageWasReceived = new boolean[1]; - channel.basicConsume(queueName, false, new DefaultConsumer(channel) { - @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { - messageWasReceived[0] = Arrays.equals(body, RABBITMQ_TEST_MESSAGE.getBytes()); + channel.basicConsume( + queueName, + false, + new DefaultConsumer(channel) { + @Override + public void handleDelivery( + String consumerTag, + Envelope envelope, + AMQP.BasicProperties properties, + byte[] body + ) throws IOException { + messageWasReceived[0] = Arrays.equals(body, RABBITMQ_TEST_MESSAGE.getBytes()); + } } - }); + ); // post a message channel.basicPublish(RABBIQMQ_TEST_EXCHANGE, RABBITMQ_TEST_ROUTING_KEY, null, RABBITMQ_TEST_MESSAGE.getBytes()); // check the message was received - assertTrue("The message was received", Unreliables.retryUntilSuccess(5, TimeUnit.SECONDS, () -> { - if (!messageWasReceived[0]) { - throw new IllegalStateException("Message not received yet"); - } - return true; - })); + assertTrue( + "The message was received", + Unreliables.retryUntilSuccess( + 5, + TimeUnit.SECONDS, + () -> { + if (!messageWasReceived[0]) { + throw new IllegalStateException("Message not received yet"); + } + return true; + } + ) + ); } @Test @@ -223,8 +242,7 @@ public void simpleMongoDbTest() { MongoDatabase database = mongoClient.getDatabase("test"); MongoCollection collection = database.getCollection("testCollection"); - Document doc = new Document("name", "foo") - .append("value", 1); + Document doc = new Document("name", "foo").append("value", 1); collection.insertOne(doc); Document doc2 = collection.find(new Document("name", "foo")).first(); @@ -247,10 +265,11 @@ public void environmentFromMapTest() throws IOException { @Test public void customLabelTest() { - try (final GenericContainer alpineCustomLabel = new GenericContainer<>(ALPINE_IMAGE) - .withLabel("our.custom", "label") - .withCommand("top")) { - + try ( + final GenericContainer alpineCustomLabel = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withLabel("our.custom", "label") + .withCommand("top") + ) { alpineCustomLabel.start(); Map labels = alpineCustomLabel.getCurrentContainerInfo().getConfig().getLabels(); @@ -262,11 +281,11 @@ public void customLabelTest() { @Test public void exceptionThrownWhenTryingToOverrideTestcontainersLabels() { - assertThrows("When trying to overwrite an 'org.testcontainers' label, withLabel() throws an exception", + assertThrows( + "When trying to overwrite an 'org.testcontainers' label, withLabel() throws an exception", IllegalArgumentException.class, () -> { - new GenericContainer<>(ALPINE_IMAGE) - .withLabel("org.testcontainers.foo", "false"); + new GenericContainer<>(TestImages.ALPINE_IMAGE).withLabel("org.testcontainers.foo", "false"); } ); } @@ -277,25 +296,36 @@ public void customClasspathResourceMappingTest() throws IOException { // in that case this test will fail. String line = getReaderForContainerPort80(alpineClasspathResource).readLine(); - assertEquals("Resource on the classpath can be mapped using calls to withClasspathResourceMapping", "FOOBAR", line); + assertEquals( + "Resource on the classpath can be mapped using calls to withClasspathResourceMapping", + "FOOBAR", + line + ); } @Test public void customClasspathResourceMappingWithSelinuxTest() throws IOException { String line = getReaderForContainerPort80(alpineClasspathResourceSelinux).readLine(); - assertEquals("Resource on the classpath can be mapped using calls to withClasspathResourceMappingSelinux", "FOOBAR", line); + assertEquals( + "Resource on the classpath can be mapped using calls to withClasspathResourceMappingSelinux", + "FOOBAR", + line + ); } @Test public void exceptionThrownWhenMappedPortNotFound() { - assertThrows("When the requested port is not mapped, getMappedPort() throws an exception", - IllegalArgumentException.class, - () -> { - return redis.getMappedPort(666); - }); + assertThrows( + "When the requested port is not mapped, getMappedPort() throws an exception", + IllegalArgumentException.class, + () -> { + return redis.getMappedPort(666); + } + ); } - protected static void writeStringToFile(File contentFolder, String filename, String string) throws FileNotFoundException { + protected static void writeStringToFile(File contentFolder, String filename, String string) + throws FileNotFoundException { File file = new File(contentFolder, filename); PrintStream printStream = new PrintStream(new FileOutputStream(file)); @@ -303,32 +333,34 @@ protected static void writeStringToFile(File contentFolder, String filename, Str printStream.close(); } - @Test @Ignore //TODO investigate intermittent failures + @Test + @Ignore //TODO investigate intermittent failures public void failFastWhenContainerHaltsImmediately() { - long startingTimeMs = System.currentTimeMillis(); - final GenericContainer failsImmediately = new GenericContainer<>(ALPINE_IMAGE) - .withCommand("/bin/sh", "-c", "return false") - .withMinimumRunningDuration(Duration.ofMillis(100)); + final GenericContainer failsImmediately = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withCommand("/bin/sh", "-c", "return false") + .withMinimumRunningDuration(Duration.ofMillis(100)); try { assertThrows( - "When we start a container that halts immediately, an exception is thrown", - RetryCountExceededException.class, - () -> { - failsImmediately.start(); - return null; - }); + "When we start a container that halts immediately, an exception is thrown", + RetryCountExceededException.class, + () -> { + failsImmediately.start(); + return null; + } + ); // Check how long it took, to verify that we ARE bailing out early. // Want to strike a balance here; too short and this test will fail intermittently // on slow systems and/or due to GC variation, too long and we won't properly test // what we're intending to test. - int allowedSecondsToFailure = - GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC / 2; + int allowedSecondsToFailure = GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC / 2; long completedTimeMs = System.currentTimeMillis(); - assertTrue("container should not take long to start up", - completedTimeMs - startingTimeMs < 1000L * allowedSecondsToFailure); + assertTrue( + "container should not take long to start up", + completedTimeMs - startingTimeMs < 1000L * allowedSecondsToFailure + ); } finally { failsImmediately.stop(); } @@ -336,19 +368,20 @@ public void failFastWhenContainerHaltsImmediately() { @Test public void testExecInContainer() throws Exception { - // The older "lxc" execution driver doesn't support "exec". At the time of writing (2016/03/29), // that's the case for CircleCI. // Once they resolve the issue, this clause can be removed. Assume.assumeTrue(TestEnvironment.dockerExecutionDriverSupportsExec()); final GenericContainer.ExecResult result = redis.execInContainer("redis-cli", "role"); - assertTrue("Output for \"redis-cli role\" command should start with \"master\"", result.getStdout().startsWith("master")); + assertTrue( + "Output for \"redis-cli role\" command should start with \"master\"", + result.getStdout().startsWith("master") + ); assertEquals("Stderr for \"redis-cli role\" command should be empty", "", result.getStderr()); // We expect to reach this point for modern Docker versions. } - @Test public void extraHostTest() throws IOException { BufferedReader br = getReaderForContainerPort80(alpineExtrahost); @@ -370,30 +403,37 @@ public void extraHostTest() throws IOException { public void createContainerCmdHookTest() { // Use random name to avoid the conflicts between the tests String randomName = Base58.randomString(5); - try( - GenericContainer container = new GenericContainer<>(REDIS_IMAGE) - .withCommand("redis-server", "--help") - .withCreateContainerCmdModifier(cmd -> cmd.withName("overrideMe")) - // Preserves the order - .withCreateContainerCmdModifier(cmd -> cmd.withName(randomName)) - // Allows to override pre-configured values by GenericContainer - .withCreateContainerCmdModifier(cmd -> cmd.withCmd("redis-server", "--port", "6379")) + try ( + GenericContainer container = new GenericContainer<>(TestImages.REDIS_IMAGE) + .withCommand("redis-server", "--help") + .withCreateContainerCmdModifier(cmd -> cmd.withName("overrideMe")) + // Preserves the order + .withCreateContainerCmdModifier(cmd -> cmd.withName(randomName)) + // Allows to override pre-configured values by GenericContainer + .withCreateContainerCmdModifier(cmd -> cmd.withCmd("redis-server", "--port", "6379")) ) { container.start(); assertEquals("Name is configured", "/" + randomName, container.getContainerInfo().getName()); - assertEquals("Command is configured", "[redis-server, --port, 6379]", Arrays.toString(container.getContainerInfo().getConfig().getCmd())); + assertEquals( + "Command is configured", + "[redis-server, --port, 6379]", + Arrays.toString(container.getContainerInfo().getConfig().getCmd()) + ); } } private BufferedReader getReaderForContainerPort80(GenericContainer container) { + return Unreliables.retryUntilSuccess( + 10, + TimeUnit.SECONDS, + () -> { + Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); - return Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { - Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); - - Socket socket = new Socket(container.getHost(), container.getFirstMappedPort()); - return new BufferedReader(new InputStreamReader(socket.getInputStream())); - }); + Socket socket = new Socket(container.getHost(), container.getFirstMappedPort()); + return new BufferedReader(new InputStreamReader(socket.getInputStream())); + } + ); } @Test @@ -415,10 +455,11 @@ public void addingExposedPortTwiceShouldNotFail() { @Test public void sharedMemorySetTest() { - try (GenericContainer containerWithSharedMemory = new GenericContainer<>(TINY_IMAGE) - .withSharedMemorySize(42L * FileUtils.ONE_MB) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy())) { - + try ( + GenericContainer containerWithSharedMemory = new GenericContainer<>(TestImages.TINY_IMAGE) + .withSharedMemorySize(42L * FileUtils.ONE_MB) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { containerWithSharedMemory.start(); HostConfig hostConfig = containerWithSharedMemory.getContainerInfo().getHostConfig(); diff --git a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java index 95047779551..33909e2ed27 100644 --- a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java +++ b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java @@ -14,10 +14,12 @@ public class NonExistentImagePullTest { @Test(timeout = 60_000L) public void pullingNonExistentImageFailsGracefully() { - - assertThrows("Pulling a nonexistent container will cause an exception to be thrown", - ContainerFetchException.class, () -> { - new GenericContainer<>(DockerImageName.parse("testcontainers/nonexistent:latest")).getDockerImageName(); - }); + assertThrows( + "Pulling a nonexistent container will cause an exception to be thrown", + ContainerFetchException.class, + () -> { + new GenericContainer<>(DockerImageName.parse("testcontainers/nonexistent:latest")).getDockerImageName(); + } + ); } } diff --git a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java index 649a0b56fc4..104fb78fe48 100644 --- a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java +++ b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; @@ -17,8 +18,6 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.ALPINE_IMAGE; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; /** * Simple test for following container output. @@ -26,61 +25,74 @@ public class OutputStreamTest { @Rule - public GenericContainer container = new GenericContainer(ALPINE_IMAGE) - .withCommand("ping -c 5 127.0.0.1"); + public GenericContainer container = new GenericContainer(TestImages.ALPINE_IMAGE) + .withCommand("ping -c 5 127.0.0.1"); private static final Logger LOGGER = LoggerFactory.getLogger(OutputStreamTest.class); @Test(timeout = 60_000L) public void testFetchStdout() throws TimeoutException { - WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("seq=2"), - 30, TimeUnit.SECONDS); + consumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("seq=2"), + 30, + TimeUnit.SECONDS + ); } @Test(timeout = 60_000L) public void testFetchStdoutWithTimeout() { - WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); - - assertThrows("a TimeoutException should be thrown", TimeoutException.class, () -> { - consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("seq=5"), - 2, TimeUnit.SECONDS); - return true; - }); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); + + assertThrows( + "a TimeoutException should be thrown", + TimeoutException.class, + () -> { + consumer.waitUntil( + frame -> { + return ( + frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("seq=5") + ); + }, + 2, + TimeUnit.SECONDS + ); + return true; + } + ); } @Test(timeout = 60_000L) public void testFetchStdoutWithNoLimit() throws TimeoutException { - WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("seq=2")); + consumer.waitUntil(frame -> { + return frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("seq=2"); + }); } @Test(timeout = 60_000L) public void testLogConsumer() throws TimeoutException { - WaitingConsumer waitingConsumer = new WaitingConsumer(); Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER); Consumer composedConsumer = logConsumer.andThen(waitingConsumer); container.followOutput(composedConsumer); - waitingConsumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("seq=2")); + waitingConsumer.waitUntil(frame -> { + return frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("seq=2"); + }); } @Test(timeout = 60_000L) public void testToStringConsumer() throws TimeoutException { - WaitingConsumer waitingConsumer = new WaitingConsumer(); ToStringConsumer toStringConsumer = new ToStringConsumer(); @@ -95,4 +107,3 @@ public void testToStringConsumer() throws TimeoutException { assertFalse("a non-expected value was found", utf8String.contains("seq=42")); } } - diff --git a/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java b/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java index b15f63f4158..a87dbef3990 100644 --- a/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java +++ b/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java @@ -4,6 +4,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.Timeout; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; @@ -18,14 +19,12 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.ALPINE_IMAGE; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; @Slf4j public class OutputStreamWithTTYTest { @Rule - public GenericContainer container = new GenericContainer<>(ALPINE_IMAGE) + public GenericContainer container = new GenericContainer<>(TestImages.ALPINE_IMAGE) .withCommand("ls -1") .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .withCreateContainerCmdModifier(command -> command.withTty(true)); @@ -37,30 +36,44 @@ public class OutputStreamWithTTYTest { public void testFetchStdout() throws TimeoutException { WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("home"), 4, TimeUnit.SECONDS); + consumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("home"), + 4, + TimeUnit.SECONDS + ); } @Test public void testFetchStdoutWithTimeout() { WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); - - assertThrows("a TimeoutException should be thrown", TimeoutException.class, () -> { - consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("qqq"), 1, TimeUnit.SECONDS); - return true; - }); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); + + assertThrows( + "a TimeoutException should be thrown", + TimeoutException.class, + () -> { + consumer.waitUntil( + frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("qqq"), + 1, + TimeUnit.SECONDS + ); + return true; + } + ); } @Test public void testFetchStdoutWithNoLimit() throws TimeoutException { WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - consumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("home")); + consumer.waitUntil(frame -> { + return frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("home"); + }); } @Test @@ -71,7 +84,9 @@ public void testLogConsumer() throws TimeoutException { Consumer composedConsumer = logConsumer.andThen(waitingConsumer); container.followOutput(composedConsumer); - waitingConsumer.waitUntil(frame -> frame.getType() == STDOUT && frame.getUtf8String().contains("home")); + waitingConsumer.waitUntil(frame -> { + return frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("home"); + }); } @Test diff --git a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java index 969d2836b2e..62eccc2000c 100644 --- a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java @@ -22,22 +22,27 @@ public class ParameterizedDockerfileContainerTest { public GenericContainer container; public ParameterizedDockerfileContainerTest(String baseImage, String expectedVersion) { - container = new GenericContainer(new ImageFromDockerfile().withDockerfileFromBuilder(builder -> { - builder - .from(baseImage) - // Could potentially customise the image here, e.g. adding files, running - // commands, etc. - .build(); - })).withCommand("top"); + container = + new GenericContainer( + new ImageFromDockerfile() + .withDockerfileFromBuilder(builder -> { + builder + .from(baseImage) + // Could potentially customise the image here, e.g. adding files, running + // commands, etc. + .build(); + }) + ) + .withCommand("top"); this.expectedVersion = expectedVersion; } @Parameterized.Parameters(name = "{0}") public static Object[][] data() { - return new Object[][] { - { "alpine:3.12", "3.12"}, - { "alpine:3.13", "3.13"}, - { "alpine:3.14", "3.14"} + return new Object[][] { // + { "alpine:3.12", "3.12" }, + { "alpine:3.13", "3.13" }, + { "alpine:3.14", "3.14" }, }; } @@ -45,7 +50,6 @@ public static Object[][] data() { public void simpleTest() throws Exception { final String release = container.execInContainer("cat", "/etc/alpine-release").getStdout(); - assertTrue("/etc/alpine-release starts with " + expectedVersion, - release.startsWith(expectedVersion)); + assertTrue("/etc/alpine-release starts with " + expectedVersion, release.startsWith(expectedVersion)); } } diff --git a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java index b23ddf2ca1c..0be4022c171 100644 --- a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java +++ b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java @@ -2,11 +2,11 @@ import org.junit.ClassRule; import org.junit.Test; +import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.TestImages.ALPINE_IMAGE; /** * Created by rnorth on 26/07/2016. @@ -14,10 +14,10 @@ public class WorkingDirectoryTest { @ClassRule - public static GenericContainer container = new GenericContainer(ALPINE_IMAGE) - .withWorkingDirectory("/etc") - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) - .withCommand("ls", "-al"); + public static GenericContainer container = new GenericContainer(TestImages.ALPINE_IMAGE) + .withWorkingDirectory("/etc") + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + .withCommand("ls", "-al"); @Test public void checkOutput() { @@ -27,5 +27,4 @@ public void checkOutput() { assertTrue("Directory listing contains expected /etc content", listing.contains("init.d")); assertTrue("Directory listing contains expected /etc content", listing.contains("passwd")); } - } diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java index 480536a54ef..de16eb0e582 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java @@ -20,6 +20,7 @@ * @author Pete Cornish {@literal } */ public abstract class AbstractWaitStrategyTest { + static final long WAIT_TIMEOUT_MILLIS = 3000; /** @@ -65,12 +66,16 @@ protected GenericContainer startContainerWithCommand(String shellCommand, Wai return startContainerWithCommand(shellCommand, waitStrategy, 8080); } - protected GenericContainer startContainerWithCommand(String shellCommand, WaitStrategy waitStrategy, Integer... ports) { + protected GenericContainer startContainerWithCommand( + String shellCommand, + WaitStrategy waitStrategy, + Integer... ports + ) { // apply WaitStrategy to container return new GenericContainer<>(TestImages.ALPINE_IMAGE) - .withExposedPorts(ports) - .withCommand("sh", "-c", shellCommand) - .waitingFor(waitStrategy.withStartupTimeout(Duration.ofMillis(WAIT_TIMEOUT_MILLIS))); + .withExposedPorts(ports) + .withCommand("sh", "-c", shellCommand) + .waitingFor(waitStrategy.withStartupTimeout(Duration.ofMillis(WAIT_TIMEOUT_MILLIS))); } /** @@ -100,10 +105,11 @@ protected void waitUntilReadyAndTimeout(String shellCommand) { */ protected void waitUntilReadyAndTimeout(GenericContainer container) { // start() blocks until successful or timeout - VisibleAssertions.assertThrows("an exception is thrown when timeout occurs (" + WAIT_TIMEOUT_MILLIS + "ms)", - ContainerLaunchException.class, - container::start); - + VisibleAssertions.assertThrows( + "an exception is thrown when timeout occurs (" + WAIT_TIMEOUT_MILLIS + "ms)", + ContainerLaunchException.class, + container::start + ); } /** @@ -115,7 +121,9 @@ protected void waitUntilReadyAndSucceed(GenericContainer container) { // start() blocks until successful or timeout container.start(); - assertTrue(String.format("Expected container to be ready after timeout of %sms", - WAIT_TIMEOUT_MILLIS), ready.get()); + assertTrue( + String.format("Expected container to be ready after timeout of %sms", WAIT_TIMEOUT_MILLIS), + ready.get() + ); } } diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java index 5c7d37a7da3..4b5f43a4d4b 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java @@ -17,7 +17,8 @@ public class HostPortWaitStrategyTest { @ClassRule - public static GenericContainer container = new GenericContainer<>(TestImages.ALPINE_IMAGE).withExposedPorts() + public static GenericContainer container = new GenericContainer<>(TestImages.ALPINE_IMAGE) + .withExposedPorts() .withCommand("sh", "-c", "while true; do nc -lp 8080; done") .withExposedPorts(8080) .waitingFor(Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(10))); diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java index 82207b4537e..7014749115e 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java @@ -1,9 +1,5 @@ package org.testcontainers.junit.wait.strategy; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; - -import java.util.HashMap; import org.jetbrains.annotations.NotNull; import org.junit.Test; import org.rnorth.ducttape.RetryCountExceededException; @@ -11,15 +7,20 @@ import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import java.time.Duration; +import java.util.HashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; + /** * Tests for {@link HttpWaitStrategy}. * * @author Pete Cornish {@literal } */ public class HttpWaitStrategyTest extends AbstractWaitStrategyTest { + /** * newline sequence indicating end of the HTTP header. */ @@ -44,10 +45,9 @@ public void testWaitUntilReadyWithSuccess() { public void testWaitUntilReadyWithSuccessWithCustomHeaders() { HashMap headers = new HashMap<>(); headers.put("baz", "boo"); - GenericContainer container = startContainerWithCommand(createShellCommand("200 OK", GOOD_RESPONSE_BODY), - createHttpWaitStrategy(ready) - .withHeader("foo", "bar") - .withHeaders(headers) + GenericContainer container = startContainerWithCommand( + createShellCommand("200 OK", GOOD_RESPONSE_BODY), + createHttpWaitStrategy(ready).withHeader("foo", "bar").withHeaders(headers) ); waitUntilReadyAndSucceed(container); @@ -58,14 +58,17 @@ public void testWaitUntilReadyWithSuccessWithCustomHeaders() { } /** - * Ensures that HTTPS requests made with the HttpWaitStrategy can skip the - * certificate validation chains (to support self-signed certificates for example). + * Ensures that HTTPS requests made with the HttpWaitStrategy can skip the + * certificate validation chains (to support self-signed certificates for example). */ @Test public void testWaitUntilReadyWithTlsAndAllowUnsecure() { - waitUntilReadyAndSucceed(startContainerWithCommand(createHttpsShellCommand("200 OK", GOOD_RESPONSE_BODY, 8080), - createHttpWaitStrategy(ready).usingTls().allowInsecure() - )); + waitUntilReadyAndSucceed( + startContainerWithCommand( + createHttpsShellCommand("200 OK", GOOD_RESPONSE_BODY, 8080), + createHttpWaitStrategy(ready).usingTls().allowInsecure() + ) + ); } /** @@ -74,10 +77,12 @@ public void testWaitUntilReadyWithTlsAndAllowUnsecure() { */ @Test public void testWaitUntilReadyWithUnauthorizedWithLambda() { - waitUntilReadyAndSucceed(startContainerWithCommand(createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), - createHttpWaitStrategy(ready) - .forStatusCodeMatching(it -> it >= 200 && it < 300 || it == 401) - )); + waitUntilReadyAndSucceed( + startContainerWithCommand( + createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), + createHttpWaitStrategy(ready).forStatusCodeMatching(it -> it >= 200 && it < 300 || it == 401) + ) + ); } /** @@ -86,12 +91,12 @@ public void testWaitUntilReadyWithUnauthorizedWithLambda() { */ @Test public void testWaitUntilReadyWithManyStatusCodes() { - waitUntilReadyAndSucceed(startContainerWithCommand(createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), - createHttpWaitStrategy(ready) - .forStatusCode(300) - .forStatusCode(401) - .forStatusCode(500) - )); + waitUntilReadyAndSucceed( + startContainerWithCommand( + createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), + createHttpWaitStrategy(ready).forStatusCode(300).forStatusCode(401).forStatusCode(500) + ) + ); } /** @@ -101,12 +106,15 @@ public void testWaitUntilReadyWithManyStatusCodes() { */ @Test public void testWaitUntilReadyWithManyStatusCodesAndLambda() { - waitUntilReadyAndSucceed(startContainerWithCommand(createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), - createHttpWaitStrategy(ready) - .forStatusCode(300) - .forStatusCode(500) - .forStatusCodeMatching(it -> it == 401) - )); + waitUntilReadyAndSucceed( + startContainerWithCommand( + createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), + createHttpWaitStrategy(ready) + .forStatusCode(300) + .forStatusCode(500) + .forStatusCodeMatching(it -> it == 401) + ) + ); } /** @@ -116,11 +124,12 @@ public void testWaitUntilReadyWithManyStatusCodesAndLambda() { */ @Test public void testWaitUntilReadyWithTimeoutAndWithManyStatusCodesAndLambda() { - waitUntilReadyAndTimeout(startContainerWithCommand(createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), - createHttpWaitStrategy(ready) - .forStatusCode(300) - .forStatusCodeMatching(it -> it == 500) - )); + waitUntilReadyAndTimeout( + startContainerWithCommand( + createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY), + createHttpWaitStrategy(ready).forStatusCode(300).forStatusCodeMatching(it -> it == 500) + ) + ); } /** @@ -132,10 +141,12 @@ public void testWaitUntilReadyWithTimeoutAndWithManyStatusCodesAndLambda() { */ @Test public void testWaitUntilReadyWithTimeoutAndWithLambdaShouldNotMatchOk() { - waitUntilReadyAndTimeout(startContainerWithCommand(createShellCommand("200 OK", GOOD_RESPONSE_BODY), - createHttpWaitStrategy(ready) - .forStatusCodeMatching(it -> it >= 300) - )); + waitUntilReadyAndTimeout( + startContainerWithCommand( + createShellCommand("200 OK", GOOD_RESPONSE_BODY), + createHttpWaitStrategy(ready).forStatusCodeMatching(it -> it >= 300) + ) + ); } /** @@ -156,27 +167,31 @@ public void testWaitUntilReadyWithTimeoutAndBadResponseBody() { waitUntilReadyAndTimeout(createShellCommand("200 OK", "Bad Response")); } - /** * Expects the WaitStrategy probing the right port. */ @Test public void testWaitUntilReadyWithSpecificPort() { - waitUntilReadyAndSucceed(startContainerWithCommand( - createShellCommand("200 OK", GOOD_RESPONSE_BODY, 9090), - createHttpWaitStrategy(ready) - .forPort(9090), - 7070, 8080, 9090 - )); + waitUntilReadyAndSucceed( + startContainerWithCommand( + createShellCommand("200 OK", GOOD_RESPONSE_BODY, 9090), + createHttpWaitStrategy(ready).forPort(9090), + 7070, + 8080, + 9090 + ) + ); } @Test public void testWaitUntilReadyWithTimoutCausedByReadTimeout() { waitUntilReadyAndTimeout( - startContainerWithCommand(createShellCommand("0 Connection Refused", GOOD_RESPONSE_BODY, 9090), + startContainerWithCommand( + createShellCommand("0 Connection Refused", GOOD_RESPONSE_BODY, 9090), createHttpWaitStrategy(ready).forPort(9090).withReadTimeout(Duration.ofMillis(1)), 9090 - )); + ) + ); } /** @@ -185,8 +200,7 @@ public void testWaitUntilReadyWithTimoutCausedByReadTimeout() { */ @NotNull protected HttpWaitStrategy buildWaitStrategy(final AtomicBoolean ready) { - return createHttpWaitStrategy(ready) - .forResponsePredicate(s -> s.equals(GOOD_RESPONSE_BODY)); + return createHttpWaitStrategy(ready).forResponsePredicate(s -> s.equals(GOOD_RESPONSE_BODY)); } /** @@ -212,17 +226,41 @@ private String createShellCommand(String header, String responseBody) { private String createShellCommand(String header, String responseBody, int port) { int length = responseBody.getBytes().length; - return "while true; do { echo -e \"HTTP/1.1 " + header + NEWLINE + - "Content-Type: text/html" + NEWLINE + - "Content-Length: " + length + NEWLINE + "\";" - + " echo \"" + responseBody + "\";} | nc -lp " + port + "; done"; + return ( + "while true; do { echo -e \"HTTP/1.1 " + + header + + NEWLINE + + "Content-Type: text/html" + + NEWLINE + + "Content-Length: " + + length + + NEWLINE + + "\";" + + " echo \"" + + responseBody + + "\";} | nc -lp " + + port + + "; done" + ); } - + private String createHttpsShellCommand(String header, String responseBody, int port) { int length = responseBody.getBytes().length; - return "apk add nmap-ncat; while true; do { echo -e \"HTTP/1.1 " + header + NEWLINE + - "Content-Type: text/html" + NEWLINE + - "Content-Length: " + length + NEWLINE + "\";" - + " echo \"" + responseBody + "\";} | ncat -lp " + port + " --ssl; done"; + return ( + "apk add nmap-ncat; while true; do { echo -e \"HTTP/1.1 " + + header + + NEWLINE + + "Content-Type: text/html" + + NEWLINE + + "Content-Length: " + + length + + NEWLINE + + "\";" + + " echo \"" + + responseBody + + "\";} | ncat -lp " + + port + + " --ssl; done" + ); } } diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/LogMessageWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/LogMessageWaitStrategyTest.java index a6ef9f11ba4..5dd9623107b 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/LogMessageWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/LogMessageWaitStrategyTest.java @@ -19,9 +19,9 @@ public class LogMessageWaitStrategyTest extends AbstractWaitStrategyTest { - builder.from(DOCKER_REGISTRY_IMAGE.asCanonicalNameString()) - .run("htpasswd -Bbn testuser notasecret > /htpasswd") - .env("REGISTRY_AUTH", "htpasswd") - .env("REGISTRY_AUTH_HTPASSWD_PATH", "/htpasswd") - .env("REGISTRY_AUTH_HTPASSWD_REALM", "Test"); - })); + public static DockerRegistryContainer authenticatedRegistry = new DockerRegistryContainer( + new ImageFromDockerfile() + .withDockerfileFromBuilder(builder -> { + builder + .from(TestImages.DOCKER_REGISTRY_IMAGE.asCanonicalNameString()) + .run("htpasswd -Bbn testuser notasecret > /htpasswd") + .env("REGISTRY_AUTH", "htpasswd") + .env("REGISTRY_AUTH_HTPASSWD_PATH", "/htpasswd") + .env("REGISTRY_AUTH_HTPASSWD_REALM", "Test"); + }) + ); private static RegistryAuthLocator originalAuthLocatorSingleton; @@ -65,7 +68,12 @@ public static void beforeClass() throws Exception { // Replace the RegistryAuthLocator singleton with our mock, for the duration of this test final RegistryAuthLocator mockAuthLocator = Mockito.mock(RegistryAuthLocator.class); RegistryAuthLocator.setInstance(mockAuthLocator); - when(mockAuthLocator.lookupAuthConfig(argThat(argument -> testRegistryAddress.equals(argument.getRegistry())), any())) + when( + mockAuthLocator.lookupAuthConfig( + argThat(argument -> testRegistryAddress.equals(argument.getRegistry())), + any() + ) + ) .thenReturn(authConfig); } @@ -77,8 +85,10 @@ public static void tearDown() { @Test public void testThatAuthLocatorIsUsedForContainerCreation() { // actually start a container, which will require an authenticated pull - try (final GenericContainer container = new GenericContainer<>(testImageName) - .withCommand("/bin/sh", "-c", "sleep 10")) { + try ( + final GenericContainer container = new GenericContainer<>(testImageName) + .withCommand("/bin/sh", "-c", "sleep 10") + ) { container.start(); assertTrue("container started following an authenticated pull", container.isRunning()); @@ -93,11 +103,12 @@ public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { Files.write(tempFile, dockerFileContent.getBytes()); // Start a container built from a derived image, which will require an authenticated pull - try (final GenericContainer container = new GenericContainer<>( - new ImageFromDockerfile() - .withDockerfile(tempFile) - ) - .withCommand("/bin/sh", "-c", "sleep 10")) { + try ( + final GenericContainer container = new GenericContainer<>( + new ImageFromDockerfile().withDockerfile(tempFile) + ) + .withCommand("/bin/sh", "-c", "sleep 10") + ) { container.start(); assertTrue("container started following an authenticated pull", container.isRunning()); @@ -108,23 +119,23 @@ public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { // Prepare a simple temporary Docker Compose manifest which requires our custom private image Path tempFile = getLocalTempFile(".docker-compose.yml"); - @Language("yaml") String composeFileContent = + @Language("yaml") + String composeFileContent = "version: '2.0'\n" + - "services:\n" + - " privateservice:\n" + - " command: /bin/sh -c 'sleep 60'\n" + - " image: " + testImageName.asCanonicalNameString(); + "services:\n" + + " privateservice:\n" + + " command: /bin/sh -c 'sleep 60'\n" + + " image: " + + testImageName.asCanonicalNameString(); Files.write(tempFile, composeFileContent.getBytes()); // Start the docker compose project, which will require an authenticated pull try (final DockerComposeContainer compose = new DockerComposeContainer<>(tempFile.toFile())) { compose.start(); - assertTrue("container started following an authenticated pull", - compose - .getContainerByServiceName("privateservice_1") - .map(ContainerState::isRunning) - .orElse(false) + assertTrue( + "container started following an authenticated pull", + compose.getContainerByServiceName("privateservice_1").map(ContainerState::isRunning).orElse(false) ); } } diff --git a/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java b/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java index bdd71b0db9f..4ed86e3a8fa 100644 --- a/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java +++ b/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java @@ -5,11 +5,11 @@ import java.io.IOException; import java.net.URL; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; -import static java.util.Arrays.asList; -import static java.util.stream.Collectors.toList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -18,9 +18,13 @@ public class ClasspathScannerTest { private static URL FILE_A; + private static URL FILE_B; + private static URL JAR_A; + private static URL JAR_B; + private static URL FILE_C; @BeforeClass @@ -35,7 +39,7 @@ public static void setUp() throws Exception { @Test public void realClassLoaderLookupOccurs() { // look for a resource that we know exists only once - final List foundURLs = ClasspathScanner.scanFor("expectedClasspathFile.txt").collect(toList()); + final List foundURLs = ClasspathScanner.scanFor("expectedClasspathFile.txt").collect(Collectors.toList()); assertEquals("Exactly one resource was found", 1, foundURLs.size()); } @@ -43,41 +47,27 @@ public void realClassLoaderLookupOccurs() { @Test public void multipleResultsOnOneClassLoaderAreFound() throws IOException { final ClassLoader firstMockClassLoader = mock(ClassLoader.class); - when(firstMockClassLoader.getResources(eq("someName"))).thenReturn( - Collections.enumeration( - asList( - FILE_A, - FILE_B - ) - ) - ); + when(firstMockClassLoader.getResources(eq("someName"))) + .thenReturn(Collections.enumeration(Arrays.asList(FILE_A, FILE_B))); - final List foundURLs = ClasspathScanner.scanFor("someName", firstMockClassLoader).collect(toList()); - assertEquals( - "The expected URLs are found", - asList(FILE_A, FILE_B), - foundURLs - ); + final List foundURLs = ClasspathScanner + .scanFor("someName", firstMockClassLoader) + .collect(Collectors.toList()); + assertEquals("The expected URLs are found", Arrays.asList(FILE_A, FILE_B), foundURLs); } @Test public void orderIsAlphabeticalForDeterminism() throws IOException { final ClassLoader firstMockClassLoader = mock(ClassLoader.class); - when(firstMockClassLoader.getResources(eq("someName"))).thenReturn( - Collections.enumeration( - asList( - FILE_B, - JAR_A, - JAR_B, - FILE_A - ) - ) - ); + when(firstMockClassLoader.getResources(eq("someName"))) + .thenReturn(Collections.enumeration(Arrays.asList(FILE_B, JAR_A, JAR_B, FILE_A))); - final List foundURLs = ClasspathScanner.scanFor("someName", firstMockClassLoader).collect(toList()); + final List foundURLs = ClasspathScanner + .scanFor("someName", firstMockClassLoader) + .collect(Collectors.toList()); assertEquals( "The expected URLs are found in the expected order", - asList(FILE_A, FILE_B, JAR_A, JAR_B), + Arrays.asList(FILE_A, FILE_B, JAR_A, JAR_B), foundURLs ); } @@ -85,30 +75,23 @@ public void orderIsAlphabeticalForDeterminism() throws IOException { @Test public void multipleClassLoadersAreQueried() throws IOException { final ClassLoader firstMockClassLoader = mock(ClassLoader.class); - when(firstMockClassLoader.getResources(eq("someName"))).thenReturn( - Collections.enumeration( - asList( - FILE_A, - FILE_B - ) - ) - ); + when(firstMockClassLoader.getResources(eq("someName"))) + .thenReturn(Collections.enumeration(Arrays.asList(FILE_A, FILE_B))); final ClassLoader secondMockClassLoader = mock(ClassLoader.class); - when(secondMockClassLoader.getResources(eq("someName"))).thenReturn( - Collections.enumeration( - asList( - FILE_B, // duplicate - FILE_C + when(secondMockClassLoader.getResources(eq("someName"))) + .thenReturn( + Collections.enumeration( + Arrays.asList( + FILE_B, // duplicate + FILE_C + ) ) - ) - ); + ); - final List foundURLs = ClasspathScanner.scanFor("someName", firstMockClassLoader, secondMockClassLoader).collect(toList()); + final List foundURLs = ClasspathScanner + .scanFor("someName", firstMockClassLoader, secondMockClassLoader) + .collect(Collectors.toList()); - assertEquals( - "The expected URLs are found", - asList(FILE_A, FILE_B, FILE_C), - foundURLs - ); + assertEquals("The expected URLs are found", Arrays.asList(FILE_A, FILE_B, FILE_C), foundURLs); } } diff --git a/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java b/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java index d5a2c63a5b8..fb3c7e05c0b 100644 --- a/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java +++ b/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java @@ -1,18 +1,19 @@ package org.testcontainers.utility; -import java.util.Arrays; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import java.util.Arrays; + import static org.junit.Assert.assertArrayEquals; @RunWith(Parameterized.class) public class ComparableVersionTest { private final int[] expected; + private final String given; public ComparableVersionTest(final String given, final int[] expected) { @@ -27,14 +28,15 @@ public void shouldParseVersions() { @Parameters(name = "Parsed version: {0}={1}") public static Iterable data() { - return Arrays.asList(new Object[][] { - {"1.2.3", new int[] {1, 2, 3}}, - {"", new int[0]}, - {"1", new int[] {1}}, - {"1.2.3.4.5.6.7", new int[] {1, 2, 3, 4, 5, 6, 7}}, - {"1.2-dev", new int[] {1, 2}}, - {"18.06.0-dev", new int[] {18, 6}}, - }); + return Arrays.asList( + new Object[][] { + { "1.2.3", new int[] { 1, 2, 3 } }, + { "", new int[0] }, + { "1", new int[] { 1 } }, + { "1.2.3.4.5.6.7", new int[] { 1, 2, 3, 4, 5, 6, 7 } }, + { "1.2-dev", new int[] { 1, 2 } }, + { "18.06.0-dev", new int[] { 18, 6 } }, + } + ); } - } diff --git a/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java index a6f7813c3d3..0978003f815 100644 --- a/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java +++ b/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java @@ -12,7 +12,9 @@ public class DefaultImageNameSubstitutorTest { public static final DockerImageName ORIGINAL_IMAGE = DockerImageName.parse("foo"); + public static final DockerImageName SUBSTITUTE_IMAGE = DockerImageName.parse("bar"); + private ConfigurationFileImageNameSubstitutor underTest; @Rule diff --git a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java index f439c55c3ea..cbd35a62b52 100644 --- a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java +++ b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java @@ -11,8 +11,8 @@ import java.io.File; import java.util.Arrays; -import static org.hamcrest.CoreMatchers.allOf; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; @@ -24,41 +24,51 @@ public void simpleRecursiveFileTest() { File directory = new File("src"); GenericContainer container = new GenericContainer( - new ImageFromDockerfile() - .withDockerfileFromBuilder(builder -> - builder.from("alpine:3.14") - .copy("/tmp/foo", "/foo") - .cmd("cat /foo/test/resources/test-recursive-file.txt") - .build() - ).withFileFromFile("/tmp/foo", directory)) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + new ImageFromDockerfile() + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.14") + .copy("/tmp/foo", "/foo") + .cmd("cat /foo/test/resources/test-recursive-file.txt") + .build(); + }) + .withFileFromFile("/tmp/foo", directory) + ) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); final String results = container.getLogs(); - assertTrue("The container has a file that was copied in via a recursive copy", results.contains("Used for DirectoryTarResourceTest")); + assertTrue( + "The container has a file that was copied in via a recursive copy", + results.contains("Used for DirectoryTarResourceTest") + ); } @Test public void simpleRecursiveFileWithPermissionTest() { GenericContainer container = new GenericContainer( - new ImageFromDockerfile() - .withDockerfileFromBuilder(builder -> - builder.from("alpine:3.14") - .copy("/tmp/foo", "/foo") - .cmd("ls", "-al", "/") - .build() - ).withFileFromFile("/tmp/foo", new File("/mappable-resource/test-resource.txt"), - 0754)) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + new ImageFromDockerfile() + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.14") // + .copy("/tmp/foo", "/foo") + .cmd("ls", "-al", "/") + .build(); + }) + .withFileFromFile("/tmp/foo", new File("/mappable-resource/test-resource.txt"), 0754) + ) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); String listing = container.getLogs(); - assertThat("Listing shows that file is copied with mode requested.", - Arrays.asList(listing.split("\\n")), - exactlyNItems(1, allOf(containsString("-rwxr-xr--"), containsString("foo")))); + assertThat( + "Listing shows that file is copied with mode requested.", + Arrays.asList(listing.split("\\n")), + exactlyNItems(1, allOf(containsString("-rwxr-xr--"), containsString("foo"))) + ); } @Test @@ -66,21 +76,27 @@ public void simpleRecursiveClasspathResourceTest() { // This test combines the copying of classpath resources from JAR files with the recursive TAR approach, to allow JARed classpath resources to be copied in to an image GenericContainer container = new GenericContainer( - new ImageFromDockerfile() - .withDockerfileFromBuilder(builder -> - builder.from("alpine:3.14") - .copy("/tmp/foo", "/foo") - .cmd("ls -lRt /foo") - .build() - ).withFileFromClasspath("/tmp/foo", "/recursive/dir")) // here we use /org/junit as a directory that really should exist on the classpath - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); + new ImageFromDockerfile() + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.14") // + .copy("/tmp/foo", "/foo") + .cmd("ls -lRt /foo") + .build(); + }) + .withFileFromClasspath("/tmp/foo", "/recursive/dir") + ) // here we use /org/junit as a directory that really should exist on the classpath + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); final String results = container.getLogs(); // ExternalResource.class is known to exist in a subdirectory of /org/junit so should be successfully copied in - assertTrue("The container has a file that was copied in via a recursive copy from a JAR resource", results.contains("content.txt")); + assertTrue( + "The container has a file that was copied in via a recursive copy from a JAR resource", + results.contains("content.txt") + ); } public static Matcher> exactlyNItems(final int n, Matcher elementMatcher) { @@ -91,7 +107,6 @@ protected boolean matchesSafely(Iterable collection, Description mism boolean isPastFirst = false; for (Object item : collection) { - if (elementMatcher.matches(item)) { count++; } diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java index 22d67de5785..f2ca26b8947 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java @@ -1,13 +1,12 @@ package org.testcontainers.utility; -import static org.hamcrest.core.StringContains.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; - import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import static org.hamcrest.Matchers.containsString; +import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class DockerImageNameCompatibilityTest { @@ -20,6 +19,7 @@ public void testPlainImage() { assertFalse("image name foo != bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); } + @Test public void testNoTagTreatedAsWildcard() { final DockerImageName subject = DockerImageName.parse("foo:4.5.6"); @@ -59,7 +59,10 @@ public void testImageWithClaimedCompatibilityAndVersion() { public void testImageWithClaimedCompatibilityForFullPath() { DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("registry/repo/bar"); - assertTrue("foo(registry/repo/bar) ~= registry/repo/bar", subject.isCompatibleWith(DockerImageName.parse("registry/repo/bar"))); + assertTrue( + "foo(registry/repo/bar) ~= registry/repo/bar", + subject.isCompatibleWith(DockerImageName.parse("registry/repo/bar")) + ); assertFalse("foo(registry/repo/bar) != repo/bar", subject.isCompatibleWith(DockerImageName.parse("repo/bar"))); assertFalse("foo(registry/repo/bar) != bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); } diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index e06407fbf56..98fd21064ed 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -16,7 +16,7 @@ public static class ValidNames { @Parameterized.Parameters(name = "{0}") public static String[] getNames() { - return new String[]{ + return new String[] { "myname:latest", "repo/my-name:1.0", "registry.foo.com:1234/my-name:1.0", @@ -27,7 +27,8 @@ public static String[] getNames() { "1.2.3.4/my-name:1.0", "1.2.3.4:1234/my-name:1.0", "1.2.3.4/repo-here/my-name:1.0", - "1.2.3.4:1234/repo-here/my-name:1.0"}; + "1.2.3.4:1234/repo-here/my-name:1.0", + }; } @Parameterized.Parameter @@ -44,11 +45,13 @@ public static class InvalidNames { @Parameterized.Parameters(name = "{0}") public static String[] getNames() { - return new String[]{":latest", + return new String[] { + ":latest", "/myname:latest", "/myname@sha256:latest", "/myname@sha256:gggggggggggggggggggggggggggggggg", - "repo:notaport/myname:latest"}; + "repo:notaport/myname:latest", + }; } @Parameterized.Parameter @@ -65,39 +68,43 @@ public static class Parsing { @Parameterized.Parameters(name = "{0}{1}{2}{3}{4}") public static String[][] getNames() { - return new String[][]{ - {"", "", "myname", ":", null}, - {"", "", "myname", ":", "latest"}, - {"", "", "repo/myname", ":", null}, - {"", "", "repo/myname", ":", "latest"}, - {"registry.foo.com:1234", "/", "my-name", ":", null}, - {"registry.foo.com:1234", "/", "my-name", ":", "1.0"}, - {"registry.foo.com", "/", "my-name", ":", "1.0"}, - {"registry.foo.com:1234", "/", "repo_here/my-name", ":", null}, - {"registry.foo.com:1234", "/", "repo_here/my-name", ":", "1.0"}, - {"1.2.3.4:1234", "/", "repo_here/my-name", ":", null}, - {"1.2.3.4:1234", "/", "repo_here/my-name", ":", "1.0"}, - {"1.2.3.4:1234", "/", "my-name", ":", null}, - {"1.2.3.4:1234", "/", "my-name", ":", "1.0"}, - {"", "", "myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, - {"", "", "repo/myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, - {"registry.foo.com:1234", "/", "repo-here/my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, - {"registry.foo.com:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, - {"1.2.3.4", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, - {"1.2.3.4:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, - {"1.2.3.4", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"}, - {"1.2.3.4:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd"} + return new String[][] { + { "", "", "myname", ":", null }, + { "", "", "myname", ":", "latest" }, + { "", "", "repo/myname", ":", null }, + { "", "", "repo/myname", ":", "latest" }, + { "registry.foo.com:1234", "/", "my-name", ":", null }, + { "registry.foo.com:1234", "/", "my-name", ":", "1.0" }, + { "registry.foo.com", "/", "my-name", ":", "1.0" }, + { "registry.foo.com:1234", "/", "repo_here/my-name", ":", null }, + { "registry.foo.com:1234", "/", "repo_here/my-name", ":", "1.0" }, + { "1.2.3.4:1234", "/", "repo_here/my-name", ":", null }, + { "1.2.3.4:1234", "/", "repo_here/my-name", ":", "1.0" }, + { "1.2.3.4:1234", "/", "my-name", ":", null }, + { "1.2.3.4:1234", "/", "my-name", ":", "1.0" }, + { "", "", "myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, + { "", "", "repo/myname", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, + { "registry.foo.com:1234", "/", "repo-here/my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, + { "registry.foo.com:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, + { "1.2.3.4", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, + { "1.2.3.4:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, + { "1.2.3.4", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, + { "1.2.3.4:1234", "/", "my-name", "@", "sha256:1234abcd1234abcd1234abcd1234abcd" }, }; } @Parameterized.Parameter(0) public String registry; + @Parameterized.Parameter(1) public String registrySeparator; + @Parameterized.Parameter(2) public String repo; + @Parameterized.Parameter(3) public String versionSeparator; + @Parameterized.Parameter(4) public String version; @@ -120,21 +127,45 @@ public void testParsing() { final DockerImageName imageName = DockerImageName.parse(combined); assertEquals(combined + " has registry address: " + registry, registry, imageName.getRegistry()); - assertEquals(combined + " has unversioned part: " + unversionedPart, unversionedPart, imageName.getUnversionedPart()); + assertEquals( + combined + " has unversioned part: " + unversionedPart, + unversionedPart, + imageName.getUnversionedPart() + ); if (version != null) { assertEquals(combined + " has version part: " + version, version, imageName.getVersionPart()); } else { - assertEquals(combined + " has automatic 'latest' version specified", "latest", imageName.getVersionPart()); + assertEquals( + combined + " has automatic 'latest' version specified", + "latest", + imageName.getVersionPart() + ); } - assertEquals(combined + " has canonical name: " + canonicalName, canonicalName, imageName.asCanonicalNameString()); + assertEquals( + combined + " has canonical name: " + canonicalName, + canonicalName, + imageName.asCanonicalNameString() + ); if (version != null) { VisibleAssertions.context("Using two-arg constructor:", 2); final DockerImageName imageNameFromSecondaryConstructor = new DockerImageName(unversionedPart, version); - assertEquals(combined + " has registry address: " + registry, registry, imageNameFromSecondaryConstructor.getRegistry()); - assertEquals(combined + " has unversioned part: " + unversionedPart, unversionedPart, imageNameFromSecondaryConstructor.getUnversionedPart()); - assertEquals(combined + " has version part: " + version, version, imageNameFromSecondaryConstructor.getVersionPart()); + assertEquals( + combined + " has registry address: " + registry, + registry, + imageNameFromSecondaryConstructor.getRegistry() + ); + assertEquals( + combined + " has unversioned part: " + unversionedPart, + unversionedPart, + imageNameFromSecondaryConstructor.getUnversionedPart() + ); + assertEquals( + combined + " has version part: " + version, + version, + imageNameFromSecondaryConstructor.getVersionPart() + ); } } } diff --git a/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java b/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java index 1ef8e136a32..36196aaf4c1 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java @@ -8,7 +8,7 @@ import java.time.Duration; import java.time.Instant; -import java.time.ZoneId; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import static org.junit.Assert.assertFalse; @@ -18,8 +18,9 @@ /** * */ - @RunWith(Parameterized.class) +@RunWith(Parameterized.class) public class DockerStatusTest { + private final DateTimeFormatter dateTimeFormatter; private static final Instant now = Instant.now(); @@ -55,8 +56,8 @@ public DockerStatusTest(DateTimeFormatter dateTimeFormatter) { @Parameterized.Parameters public static Object[][] parameters() { return new Object[][] { - { DateTimeFormatter.ISO_INSTANT}, - { DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.of("America/New_York")) } + { DateTimeFormatter.ISO_INSTANT }, + { DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.of("America/New_York")) }, }; } @@ -88,9 +89,12 @@ private String buildTimestamp(Instant instant) { // ContainerState is a non-static inner class, with private member variables, in a different package. // It's simpler to mock it that to try to create one. - private static InspectContainerResponse.ContainerState buildState(boolean running, boolean paused, - String startedAt, String finishedAt) { - + private static InspectContainerResponse.ContainerState buildState( + boolean running, + boolean paused, + String startedAt, + String finishedAt + ) { InspectContainerResponse.ContainerState state = Mockito.mock(InspectContainerResponse.ContainerState.class); when(state.getRunning()).thenReturn(running); when(state.getPaused()).thenReturn(paused); diff --git a/core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java b/core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java index f74a6c942b3..50681ddc729 100644 --- a/core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java +++ b/core/src/test/java/org/testcontainers/utility/FakeImageSubstitutor.java @@ -1,6 +1,7 @@ package org.testcontainers.utility; public class FakeImageSubstitutor extends ImageNameSubstitutor { + @Override public DockerImageName apply(final DockerImageName original) { return DockerImageName.parse("transformed-" + original.asCanonicalNameString()); diff --git a/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java b/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java index 49bc870e8d0..30367975d1e 100644 --- a/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java +++ b/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java @@ -9,22 +9,27 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.AbstractMap.SimpleEntry; +import java.util.Arrays; import java.util.List; import java.util.Map.Entry; -import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class FilterRegistryTest { - private static final List> FILTERS = asList( - new SimpleEntry<>("key1!", "value2?"), new SimpleEntry<>("key2#", "value2%") + private static final List> FILTERS = Arrays.asList( + new SimpleEntry<>("key1!", "value2?"), + new SimpleEntry<>("key2#", "value2%") ); + private static final String URL_ENCODED_FILTERS = "key1%21=value2%3F&key2%23=value2%25"; + private static final byte[] ACKNOWLEDGEMENT = FilterRegistry.ACKNOWLEDGMENT.getBytes(); + private static final byte[] NO_ACKNOWLEDGEMENT = "".getBytes(); + private static final String NEW_LINE = "\n"; @Test @@ -66,5 +71,4 @@ private static InputStream anyInputStream() { private static OutputStream anyOutputStream() { return new ByteArrayOutputStream(); } - } diff --git a/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java index 97ee0213f21..f7e319a5948 100644 --- a/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java +++ b/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java @@ -13,7 +13,9 @@ public class ImageNameSubstitutorTest { @Rule public MockTestcontainersConfigurationRule config = new MockTestcontainersConfigurationRule(); + private ImageNameSubstitutor originalInstance; + private ImageNameSubstitutor originalDefaultImplementation; @Before @@ -27,10 +29,7 @@ public void setUp() throws Exception { .doReturn(DockerImageName.parse("substituted-image")) .when(ImageNameSubstitutor.defaultImplementation) .apply(eq(DockerImageName.parse("original"))); - Mockito - .doReturn("default implementation") - .when(ImageNameSubstitutor.defaultImplementation) - .getDescription(); + Mockito.doReturn("default implementation").when(ImageNameSubstitutor.defaultImplementation).getDescription(); } @After @@ -58,10 +57,7 @@ public void simpleConfigurationTest() { @Test public void testWorksWithoutConfiguredImplementation() { - Mockito - .doReturn(null) - .when(TestcontainersConfiguration.getInstance()) - .getImageSubstitutorClassName(); + Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getImageSubstitutorClassName(); final ImageNameSubstitutor imageNameSubstitutor = ImageNameSubstitutor.instance(); diff --git a/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java b/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java index 81805106806..99443221805 100644 --- a/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java +++ b/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java @@ -8,9 +8,9 @@ import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import java.util.stream.IntStream; -import static java.util.stream.Collectors.toList; import static org.rnorth.visibleassertions.VisibleAssertions.*; public class LazyFutureTest { @@ -64,9 +64,14 @@ protected Integer resolve() { } }; - Future> task = new ForkJoinPool(numOfThreads).submit(() -> { - return IntStream.rangeClosed(1, numOfThreads).parallel().mapToObj(i -> Futures.getUnchecked(lazyFuture)).collect(toList()); - }); + Future> task = new ForkJoinPool(numOfThreads) + .submit(() -> { + return IntStream + .rangeClosed(1, numOfThreads) + .parallel() + .mapToObj(i -> Futures.getUnchecked(lazyFuture)) + .collect(Collectors.toList()); + }); while (latch.getCount() > 0) { latch.countDown(); @@ -74,5 +79,4 @@ protected Integer resolve() { assertEquals("All threads receives the same result", Collections.nCopies(numOfThreads, 1), task.get()); } - -} \ No newline at end of file +} diff --git a/core/src/test/java/org/testcontainers/utility/MountableFileTest.java b/core/src/test/java/org/testcontainers/utility/MountableFileTest.java index c7dcaad2908..d3ff085c5de 100644 --- a/core/src/test/java/org/testcontainers/utility/MountableFileTest.java +++ b/core/src/test/java/org/testcontainers/utility/MountableFileTest.java @@ -20,7 +20,9 @@ public class MountableFileTest { private static final int TEST_FILE_MODE = 0532; + private static final int BASE_FILE_MODE = 0100000; + private static final int BASE_DIR_MODE = 0040000; @Test @@ -67,7 +69,10 @@ public void forHostPathWithSpaces() throws Exception { performChecks(mountableFile); assertTrue("The resolved path contains the original space", mountableFile.getResolvedPath().contains(" ")); - assertFalse("The resolved path does not contain an escaped space", mountableFile.getResolvedPath().contains("\\ ")); + assertFalse( + "The resolved path does not contain an escaped space", + mountableFile.getResolvedPath().contains("\\ ") + ); } @Test @@ -78,13 +83,18 @@ public void forHostPathWithPlus() throws Exception { performChecks(mountableFile); assertTrue("The resolved path contains the original space", mountableFile.getResolvedPath().contains("+")); - assertFalse("The resolved path does not contain an escaped space", mountableFile.getResolvedPath().contains(" ")); + assertFalse( + "The resolved path does not contain an escaped space", + mountableFile.getResolvedPath().contains(" ") + ); } @Test public void forClasspathResourceWithPermission() throws Exception { - final MountableFile mountableFile = MountableFile.forClasspathResource("mappable-resource/test-resource.txt", - TEST_FILE_MODE); + final MountableFile mountableFile = MountableFile.forClasspathResource( + "mappable-resource/test-resource.txt", + TEST_FILE_MODE + ); performChecks(mountableFile); assertEquals("Valid file mode.", BASE_FILE_MODE | TEST_FILE_MODE, mountableFile.getFileMode()); @@ -110,7 +120,8 @@ public void forHostDirPathWithPermission() throws Exception { public void noTrailingSlashesInTarEntryNames() throws Exception { final MountableFile mountableFile = MountableFile.forClasspathResource("mappable-resource/test-resource.txt"); - @Cleanup final TarArchiveInputStream tais = intoTarArchive((taos) -> { + @Cleanup + final TarArchiveInputStream tais = intoTarArchive(taos -> { mountableFile.transferTo(taos, "/some/path.txt"); mountableFile.transferTo(taos, "/path.txt"); mountableFile.transferTo(taos, "path.txt"); @@ -123,8 +134,10 @@ public void noTrailingSlashesInTarEntryNames() throws Exception { } private TarArchiveInputStream intoTarArchive(Consumer consumer) throws IOException { - @Cleanup final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - @Cleanup final TarArchiveOutputStream taos = new TarArchiveOutputStream(baos); + @Cleanup + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + @Cleanup + final TarArchiveOutputStream taos = new TarArchiveOutputStream(baos); consumer.accept(taos); taos.close(); @@ -151,7 +164,9 @@ private Path createTempDir() throws IOException { private void performChecks(final MountableFile mountableFile) { final String mountablePath = mountableFile.getResolvedPath(); assertTrue("The filesystem path '" + mountablePath + "' can be found", new File(mountablePath).exists()); - assertFalse("The filesystem path '" + mountablePath + "' does not contain any URL escaping", mountablePath.contains("%20")); + assertFalse( + "The filesystem path '" + mountablePath + "' does not contain any URL escaping", + mountablePath.contains("%20") + ); } - } diff --git a/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java index d2c33989deb..211f8e00536 100644 --- a/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java +++ b/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java @@ -8,11 +8,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.utility.PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY; public class PrefixingImageNameSubstitutorTest { private TestcontainersConfiguration mockConfiguration; + private PrefixingImageNameSubstitutor underTest; @Before @@ -23,7 +23,8 @@ public void setUp() { @Test public void testHappyPath() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com/our-mirror/"); final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); @@ -36,33 +37,28 @@ public void testHappyPath() { @Test public void hubIoRegistryIsNotChanged() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com/our-mirror/"); final DockerImageName result = underTest.apply(DockerImageName.parse("docker.io/some/image:tag")); - assertEquals( - "The prefix is applied", - "docker.io/some/image:tag", - result.asCanonicalNameString() - ); + assertEquals("The prefix is applied", "docker.io/some/image:tag", result.asCanonicalNameString()); } @Test public void hubComRegistryIsNotChanged() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com/our-mirror/"); final DockerImageName result = underTest.apply(DockerImageName.parse("registry.hub.docker.com/some/image:tag")); - assertEquals( - "The prefix is applied", - "registry.hub.docker.com/some/image:tag", - result.asCanonicalNameString() - ); + assertEquals("The prefix is applied", "registry.hub.docker.com/some/image:tag", result.asCanonicalNameString()); } @Test public void thirdPartyRegistriesNotAffected() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com/our-mirror/"); final DockerImageName result = underTest.apply(DockerImageName.parse("gcr.io/something/image:tag")); @@ -75,7 +71,8 @@ public void thirdPartyRegistriesNotAffected() { @Test public void testNoDoublePrefixing() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror/"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com/our-mirror/"); final DockerImageName result = underTest.apply(DockerImageName.parse("someregistry.com/some/image:tag")); @@ -88,7 +85,8 @@ public void testNoDoublePrefixing() { @Test public void testHandlesEmptyValue() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn(""); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn(""); final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); @@ -101,39 +99,38 @@ public void testHandlesEmptyValue() { @Test public void testHandlesRegistryOnlyWithTrailingSlash() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com/"); final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); - assertEquals( - "The prefix is applied", - "someregistry.com/some/image:tag", - result.asCanonicalNameString() - ); + assertEquals("The prefix is applied", "someregistry.com/some/image:tag", result.asCanonicalNameString()); } @Test public void testCombinesLiterallyForRegistryOnlyWithoutTrailingSlash() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com"); final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); assertEquals( "The prefix is applied", - "someregistry.comsome/image:tag", // treating the prefix literally, for predictability + "someregistry.comsome/image:tag", // treating the prefix literally, for predictability result.asCanonicalNameString() ); } @Test public void testCombinesLiterallyForBothPartsWithoutTrailingSlash() { - when(mockConfiguration.getEnvVarOrProperty(eq(PREFIX_PROPERTY_KEY), any())).thenReturn("someregistry.com/our-mirror"); + when(mockConfiguration.getEnvVarOrProperty(eq(PrefixingImageNameSubstitutor.PREFIX_PROPERTY_KEY), any())) + .thenReturn("someregistry.com/our-mirror"); final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); assertEquals( "The prefix is applied", - "someregistry.com/our-mirrorsome/image:tag", // treating the prefix literally, for predictability + "someregistry.com/our-mirrorsome/image:tag", // treating the prefix literally, for predictability result.asCanonicalNameString() ); } diff --git a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java index 5db2583958a..4ddfad8454f 100644 --- a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java +++ b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java @@ -14,13 +14,21 @@ import static org.rnorth.visibleassertions.VisibleAssertions.*; public class RegistryAuthLocatorTest { + @Test public void lookupAuthConfigWithoutCredentials() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-empty.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("unauthenticated.registry.org/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("unauthenticated.registry.org/org/repo"), + new AuthConfig() + ); - assertEquals("Default docker registry URL is set on auth config", "https://index.docker.io/v1/", authConfig.getRegistryAddress()); + assertEquals( + "Default docker registry URL is set on auth config", + "https://index.docker.io/v1/", + authConfig.getRegistryAddress() + ); assertNull("No username is set", authConfig.getUsername()); assertNull("No password is set", authConfig.getPassword()); } @@ -29,9 +37,16 @@ public void lookupAuthConfigWithoutCredentials() throws URISyntaxException { public void lookupAuthConfigWithBasicAuthCredentials() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-basic-auth.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("registry.example.com/org/repo"), + new AuthConfig() + ); - assertEquals("Default docker registry URL is set on auth config", "https://registry.example.com", authConfig.getRegistryAddress()); + assertEquals( + "Default docker registry URL is set on auth config", + "https://registry.example.com", + authConfig.getRegistryAddress() + ); assertEquals("Username is set", "user", authConfig.getUsername()); assertEquals("Password is set", "pass", authConfig.getPassword()); } @@ -40,9 +55,16 @@ public void lookupAuthConfigWithBasicAuthCredentials() throws URISyntaxException public void lookupAuthConfigWithJsonKeyCredentials() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-json-key.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("registry.example.com/org/repo"), + new AuthConfig() + ); - assertEquals("Default docker registry URL is set on auth config", "https://registry.example.com", authConfig.getRegistryAddress()); + assertEquals( + "Default docker registry URL is set on auth config", + "https://registry.example.com", + authConfig.getRegistryAddress() + ); assertEquals("Username is set", "_json_key", authConfig.getUsername()); assertNotNull("Password is set", authConfig.getPassword()); } @@ -51,7 +73,10 @@ public void lookupAuthConfigWithJsonKeyCredentials() throws URISyntaxException { public void lookupAuthConfigUsingStore() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-store.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("registry.example.com/org/repo"), + new AuthConfig() + ); assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); @@ -62,7 +87,10 @@ public void lookupAuthConfigUsingStore() throws URISyntaxException { public void lookupAuthConfigUsingHelper() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-helper.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("registry.example.com/org/repo"), + new AuthConfig() + ); assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); @@ -73,16 +101,26 @@ public void lookupAuthConfigUsingHelper() throws URISyntaxException { public void lookupAuthConfigUsingHelperWithToken() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-helper-using-token.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registrytoken.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("registrytoken.example.com/org/repo"), + new AuthConfig() + ); - assertEquals("Correct identitytoken is obtained from a credential store", "secret", authConfig.getIdentitytoken()); + assertEquals( + "Correct identitytoken is obtained from a credential store", + "secret", + authConfig.getIdentitytoken() + ); } @Test public void lookupUsingHelperEmptyAuth() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-empty-auth-with-helper.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("registry.example.com/org/repo"), + new AuthConfig() + ); assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); @@ -93,7 +131,10 @@ public void lookupUsingHelperEmptyAuth() throws URISyntaxException { public void lookupNonEmptyAuthWithHelper() throws URISyntaxException { final RegistryAuthLocator authLocator = createTestAuthLocator("config-existing-auth-with-helper.json"); - final AuthConfig authConfig = authLocator.lookupAuthConfig(DockerImageName.parse("registry.example.com/org/repo"), new AuthConfig()); + final AuthConfig authConfig = authLocator.lookupAuthConfig( + DockerImageName.parse("registry.example.com/org/repo"), + new AuthConfig() + ); assertEquals("Correct server URL is obtained from a credential helper", "url", authConfig.getRegistryAddress()); assertEquals("Correct username is obtained from a credential helper", "username", authConfig.getUsername()); @@ -103,7 +144,10 @@ public void lookupNonEmptyAuthWithHelper() throws URISyntaxException { @Test public void lookupAuthConfigWithCredentialsNotFound() throws URISyntaxException { Map notFoundMessagesReference = new HashMap<>(); - final RegistryAuthLocator authLocator = createTestAuthLocator("config-with-store.json", notFoundMessagesReference); + final RegistryAuthLocator authLocator = createTestAuthLocator( + "config-with-store.json", + notFoundMessagesReference + ); DockerImageName dockerImageName = DockerImageName.parse("registry2.example.com/org/repo"); final AuthConfig authConfig = authLocator.lookupAuthConfig(dockerImageName, new AuthConfig()); @@ -117,7 +161,8 @@ public void lookupAuthConfigWithCredentialsNotFound() throws URISyntaxException assertEquals( "Not correct message discovered", "Fake credentials not found on credentials store 'https://not.a.real.registry/url'", - discoveredMessage); + discoveredMessage + ); } @Test @@ -136,7 +181,8 @@ private RegistryAuthLocator createTestAuthLocator(String configName) throws URIS } @NotNull - private RegistryAuthLocator createTestAuthLocator(String configName, Map notFoundMessagesReference) throws URISyntaxException { + private RegistryAuthLocator createTestAuthLocator(String configName, Map notFoundMessagesReference) + throws URISyntaxException { final File configFile = new File(Resources.getResource("auth-config/" + configName).toURI()); String commandPathPrefix = configFile.getParentFile().getAbsolutePath() + "/"; diff --git a/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java b/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java index 214b465c297..60f57a28b3e 100644 --- a/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java +++ b/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java @@ -42,25 +42,27 @@ public void shouldCleanupWithJVM() { private void assertCleanup(Map labels) { DockerClient client = DockerClientFactory.instance().client(); - ConditionFactory awaitFactory = Awaitility.await().atMost(Duration.ofMinutes(1)).pollInterval(Duration.ofSeconds(1)); - - List labelValues = labels.entrySet().stream() + ConditionFactory awaitFactory = Awaitility + .await() + .atMost(Duration.ofMinutes(1)) + .pollInterval(Duration.ofSeconds(1)); + + List labelValues = labels + .entrySet() + .stream() .map(it -> it.getKey() + "=" + it.getValue()) .collect(Collectors.toList()); awaitFactory.untilAsserted(() -> { - assertThat(client.listContainersCmd().withFilter("label", labelValues).withShowAll(true).exec()) - .isEmpty(); + assertThat(client.listContainersCmd().withFilter("label", labelValues).withShowAll(true).exec()).isEmpty(); }); awaitFactory.untilAsserted(() -> { - assertThat(client.listNetworksCmd().withFilter("label", labelValues).exec()) - .isEmpty(); + assertThat(client.listNetworksCmd().withFilter("label", labelValues).exec()).isEmpty(); }); awaitFactory.untilAsserted(() -> { - assertThat(client.listVolumesCmd().withFilter("label", labelValues).exec().getVolumes()) - .isEmpty(); + assertThat(client.listVolumesCmd().withFilter("label", labelValues).exec().getVolumes()).isEmpty(); }); } @@ -81,7 +83,8 @@ private Map runProcess(Consumer processExecutor ProcessResult result = processExecutor.execute(); assertEquals(0, result.getExitValue()); - String labelsJson = Stream.of(result.outputUTF8().split("\n")) + String labelsJson = Stream + .of(result.outputUTF8().split("\n")) .filter(it -> it.startsWith(SimpleUsage.LABELS_MARKER)) .map(it -> it.substring(SimpleUsage.LABELS_MARKER.length())) .findFirst() @@ -97,7 +100,9 @@ public static class SimpleUsage { @SneakyThrows @SuppressWarnings("deprecation") public static void main(String[] args) { - System.out.println(LABELS_MARKER + new ObjectMapper().writeValueAsString(ResourceReaper.instance().getLabels())); + System.out.println( + LABELS_MARKER + new ObjectMapper().writeValueAsString(ResourceReaper.instance().getLabels()) + ); GenericContainer container = new GenericContainer<>("testcontainers/helloworld:1.1.0") .withNetwork(org.testcontainers.containers.Network.newNetwork()) diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index 7ca656e1eaf..56cbdb98a56 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -15,7 +15,9 @@ public class TestcontainersConfigurationTest { private Properties userProperties; + private Properties classpathProperties; + private Map environment; @Before @@ -117,21 +119,33 @@ public void shouldReadChecksFromEnvironment() { public void shouldReadDockerSettingsFromEnvironmentWithoutTestcontainersPrefix() { userProperties.remove("docker.foo"); environment.put("DOCKER_FOO", "some value"); - assertEquals("reads unprefixed env vars for docker. settings", "some value", newConfig().getEnvVarOrUserProperty("docker.foo", "default")); + assertEquals( + "reads unprefixed env vars for docker. settings", + "some value", + newConfig().getEnvVarOrUserProperty("docker.foo", "default") + ); } @Test public void shouldNotReadDockerSettingsFromEnvironmentWithTestcontainersPrefix() { userProperties.remove("docker.foo"); environment.put("TESTCONTAINERS_DOCKER_FOO", "some value"); - assertEquals("reads unprefixed env vars for docker. settings", "default", newConfig().getEnvVarOrUserProperty("docker.foo", "default")); + assertEquals( + "reads unprefixed env vars for docker. settings", + "default", + newConfig().getEnvVarOrUserProperty("docker.foo", "default") + ); } @Test public void shouldReadDockerSettingsFromUserProperties() { environment.remove("DOCKER_FOO"); userProperties.put("docker.foo", "some value"); - assertEquals("reads unprefixed user properties for docker. settings", "some value", newConfig().getEnvVarOrUserProperty("docker.foo", "default")); + assertEquals( + "reads unprefixed user properties for docker. settings", + "some value", + newConfig().getEnvVarOrUserProperty("docker.foo", "default") + ); } @Test @@ -139,41 +153,69 @@ public void shouldNotReadDockerClientStrategyFromClasspathProperties() { String currentValue = newConfig().getDockerClientStrategyClassName(); classpathProperties.setProperty("docker.client.strategy", UUID.randomUUID().toString()); - assertEquals("Docker client strategy is not affected by classpath properties", currentValue, newConfig().getDockerClientStrategyClassName()); + assertEquals( + "Docker client strategy is not affected by classpath properties", + currentValue, + newConfig().getDockerClientStrategyClassName() + ); } @Test public void shouldReadDockerClientStrategyFromUserProperties() { userProperties.setProperty("docker.client.strategy", "foo"); - assertEquals("Docker client strategy is changed by user property", "foo", newConfig().getDockerClientStrategyClassName()); + assertEquals( + "Docker client strategy is changed by user property", + "foo", + newConfig().getDockerClientStrategyClassName() + ); } @Test public void shouldReadDockerClientStrategyFromEnvironment() { userProperties.remove("docker.client.strategy"); environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "foo"); - assertEquals("Docker client strategy is changed by env var", "foo", newConfig().getDockerClientStrategyClassName()); + assertEquals( + "Docker client strategy is changed by env var", + "foo", + newConfig().getDockerClientStrategyClassName() + ); } @Test public void shouldNotUseImplicitDockerClientStrategyWhenDockerHostAndStrategyAreBothSet() { userProperties.put("docker.client.strategy", "foo"); userProperties.put("docker.host", "tcp://1.2.3.4:5678"); - assertEquals("Docker client strategy is can be explicitly set", "foo", newConfig().getDockerClientStrategyClassName()); + assertEquals( + "Docker client strategy is can be explicitly set", + "foo", + newConfig().getDockerClientStrategyClassName() + ); userProperties.remove("docker.client.strategy"); environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "bar"); userProperties.put("docker.client.strategy", "foo"); - assertEquals("Docker client strategy is can be explicitly set", "bar", newConfig().getDockerClientStrategyClassName()); + assertEquals( + "Docker client strategy is can be explicitly set", + "bar", + newConfig().getDockerClientStrategyClassName() + ); environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "bar"); userProperties.remove("docker.client.strategy"); - assertEquals("Docker client strategy is can be explicitly set", "bar", newConfig().getDockerClientStrategyClassName()); + assertEquals( + "Docker client strategy is can be explicitly set", + "bar", + newConfig().getDockerClientStrategyClassName() + ); environment.remove("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY"); userProperties.put("docker.client.strategy", "foo"); - assertEquals("Docker client strategy is can be explicitly set", "foo", newConfig().getDockerClientStrategyClassName()); + assertEquals( + "Docker client strategy is can be explicitly set", + "foo", + newConfig().getDockerClientStrategyClassName() + ); } @Test @@ -191,6 +233,7 @@ public void shouldReadReuseFromUserProperties() { userProperties.setProperty("testcontainers.reuse.enable", "true"); assertTrue("reuse enabled via user property", newConfig().environmentSupportsReuse()); } + @Test public void shouldReadReuseFromEnvironment() { assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); @@ -203,7 +246,11 @@ public void shouldReadReuseFromEnvironment() { @Test public void shouldTrimImageNames() { userProperties.setProperty("ryuk.container.image", " testcontainers/ryuk:0.3.2 "); - assertEquals("trailing whitespace was not removed from image name property", "testcontainers/ryuk:0.3.2",newConfig().getRyukImage()); + assertEquals( + "trailing whitespace was not removed from image name property", + "testcontainers/ryuk:0.3.2", + newConfig().getRyukImage() + ); } private TestcontainersConfiguration newConfig() { diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index 5306426070f..218ed90e5e0 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -19,21 +19,26 @@ public class CmdModifierTest { // hostname { @Rule public GenericContainer theCache = new GenericContainer<>(DockerImageName.parse("redis:3.0.2")) - .withCreateContainerCmdModifier(cmd -> cmd.withHostName("the-cache")); + .withCreateContainerCmdModifier(cmd -> cmd.withHostName("the-cache")); + // } + // spotless:off // memory { private long memoryInBytes = 32 * 1024 * 1024; + private long memorySwapInBytes = 64 * 1024 * 1024; @Rule public GenericContainer memoryLimitedRedis = new GenericContainer<>(DockerImageName.parse("redis:3.0.2")) - .withCreateContainerCmdModifier(cmd -> cmd.getHostConfig() + .withCreateContainerCmdModifier(cmd -> { + cmd.getHostConfig() .withMemory(memoryInBytes) - .withMemorySwap(memorySwapInBytes) - ); - // } + .withMemorySwap(memorySwapInBytes); + }); + // } + // spotless:on @Test public void testHostnameModified() throws IOException, InterruptedException { diff --git a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java b/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java index 23b265c26fa..80292465521 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java @@ -8,11 +8,12 @@ import static org.junit.Assert.assertTrue; public class CommandsTest { + @Rule // startupCommand { public GenericContainer redisWithCustomPort = new GenericContainer(DockerImageName.parse("redis:5.0")) .withCommand("redis-server --port 7777") - // } + // } .withExposedPorts(7777); @Test diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java index 83b45f0435d..bdd82968191 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java @@ -9,31 +9,33 @@ public class ContainerCreationTest { + // spotless:off // simple { public static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:3.0.2"); - // } - // simple { @ClassRule - public static GenericContainer redis = - new GenericContainer<>(REDIS_IMAGE) - .withExposedPorts(6379); + public static GenericContainer redis = new GenericContainer<>(REDIS_IMAGE) + .withExposedPorts(6379); + // } + // spotless:on public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.14"); + // spotless:off // withOptions { // Set up a plain OS container and customize environment, // command and exposed ports. This just listens on port 80 // and always returns '42' @ClassRule - public static GenericContainer alpine = - new GenericContainer<>(ALPINE_IMAGE) - .withExposedPorts(80) - .withEnv("MAGIC_NUMBER", "42") - .withCommand("/bin/sh", "-c", - "while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"); + public static GenericContainer alpine = new GenericContainer<>(ALPINE_IMAGE) + .withExposedPorts(80) + .withEnv("MAGIC_NUMBER", "42") + .withCommand("/bin/sh", "-c", + "while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"); + // } + // spotless:on @Test public void testStartup() { diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java index 08d57e31057..64618ad25a9 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java @@ -7,12 +7,12 @@ import java.util.Map; public class ContainerLabelTest { + // single_label { public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.14")) .withLabel("key", "value"); // } - // multiple_labels { private Map mapOfLabels = new HashMap<>(); // populate map, e.g. mapOfLabels.put("key1", "value1"); diff --git a/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java index 1d15c2553b8..22bf0332a9d 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java @@ -18,19 +18,23 @@ public class HostPortExposedTest { private static HttpServer server; + private static int localServerPort; @BeforeClass public static void setUp() throws Exception { server = HttpServer.create(new InetSocketAddress(0), 0); - server.createContext("/", exchange -> { - byte[] content = "Hello World!".getBytes(); - exchange.sendResponseHeaders(200, content.length); - try (OutputStream responseBody = exchange.getResponseBody()) { - responseBody.write(content); - responseBody.flush(); + server.createContext( + "/", + exchange -> { + byte[] content = "Hello World!".getBytes(); + exchange.sendResponseHeaders(200, content.length); + try (OutputStream responseBody = exchange.getResponseBody()) { + responseBody.write(content); + responseBody.flush(); + } } - }); + ); server.start(); localServerPort = server.getAddress().getPort(); @@ -46,14 +50,12 @@ public static void tearDown() throws Exception { } @Rule - public BrowserWebDriverContainer browser = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()); + public BrowserWebDriverContainer browser = new BrowserWebDriverContainer().withCapabilities(new ChromeOptions()); @Test public void testContainerRunningAgainstExposedHostPort() { // useHostExposedPort { - final String rootUrl = - String.format("http://host.testcontainers.internal:%d/", localServerPort); + final String rootUrl = String.format("http://host.testcontainers.internal:%d/", localServerPort); final RemoteWebDriver webDriver = browser.getWebDriver(); webDriver.get(rootUrl); diff --git a/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java b/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java index 65da67fd401..afbe38fe835 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java @@ -1,6 +1,5 @@ package generic; - import generic.support.TestSpecificImageNameSubstitutor; import org.junit.Test; import org.testcontainers.containers.MySQLContainer; @@ -11,14 +10,15 @@ public class ImageNameSubstitutionTest { @Test public void simpleExample() { try ( + // spotless:off // directDockerHubReference { // Referring directly to an image on Docker Hub (mysql:8.0.24) final MySQLContainer mysql = new MySQLContainer<>( DockerImageName.parse("mysql:8.0.24") ) - // start the container and use it for testing // } + // spotless:on ) { mysql.start(); } @@ -32,15 +32,16 @@ public void simpleExample() { @Test public void substitutedExample() { try ( + // spotless:off // hardcodedMirror { // Referring directly to an image on a private registry - image name will vary final MySQLContainer mysql = new MySQLContainer<>( DockerImageName.parse("registry.mycompany.com/mirror/mysql:8.0.24") - .asCompatibleSubstituteFor("mysql") + .asCompatibleSubstituteFor("mysql") ) - // start the container and use it for testing // } + // spotless:on ) { mysql.start(); } diff --git a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java index de2b56c6a63..49e62cff217 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java @@ -1,23 +1,25 @@ package generic; -import static org.slf4j.LoggerFactory.getLogger; - import org.junit.Rule; import org.junit.Test; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.utility.DockerImageName; public class MultiplePortsExposedTest { - private static final Logger log = getLogger(MultiplePortsExposedTest.class); + private static final Logger log = LoggerFactory.getLogger(MultiplePortsExposedTest.class); @Rule // rule { - public GenericContainer container = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld:1.1.0")) + public GenericContainer container = new GenericContainer<>( + DockerImageName.parse("testcontainers/helloworld:1.1.0") + ) .withExposedPorts(8080, 8081) .withLogConsumer(new Slf4jLogConsumer(log)); + // } @Test @@ -38,7 +40,6 @@ public void getHostOnly() { @Test public void getHostAndMappedPort() { - String address = - container.getHost() + ":" + container.getMappedPort(8080); + String address = container.getHost() + ":" + container.getMappedPort(8080); } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java b/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java index d45b1e28c47..bdc0d3ced8a 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java @@ -14,8 +14,9 @@ public class WaitStrategiesTest { @Rule // waitForNetworkListening { - public GenericContainer nginx = new GenericContainer(DockerImageName.parse("nginx:1.9.4")) + public GenericContainer nginx = new GenericContainer(DockerImageName.parse("nginx:1.9.4")) // .withExposedPorts(80); + // } @Rule @@ -23,44 +24,48 @@ public class WaitStrategiesTest { public GenericContainer nginxWithHttpWait = new GenericContainer(DockerImageName.parse("nginx:1.9.4")) .withExposedPorts(80) .waitingFor(Wait.forHttp("/")); + // } @Rule // logMessageWait { public GenericContainer containerWithLogWait = new GenericContainer(DockerImageName.parse("redis:5.0.3")) .withExposedPorts(6379) - .waitingFor( - Wait.forLogMessage(".*Ready to accept connections.*\\n", 1) - ); + .waitingFor(Wait.forLogMessage(".*Ready to accept connections.*\\n", 1)); + // } private static final HttpWaitStrategy MULTI_CODE_HTTP_WAIT = + // spotless:off // waitForHttpWithMultipleStatusCodes { Wait.forHttp("/") .forStatusCode(200) - .forStatusCode(301) + .forStatusCode(301); // } - ; + // spotless:on private static final HttpWaitStrategy PREDICATE_HTTP_WAIT = + // spotless:off // waitForHttpWithStatusCodePredicate { Wait.forHttp("/all") - .forStatusCodeMatching(it -> it >= 200 && it < 300 || it == 401) + .forStatusCodeMatching(it -> it >= 200 && it < 300 || it == 401); // } - ; + // spotless:on private static final HttpWaitStrategy TLS_HTTP_WAIT = + // spotless:off // waitForHttpWithTls { Wait.forHttp("/all") - .usingTls() + .usingTls(); // } - ; + // spotless:on private static final WaitStrategy HEALTHCHECK_WAIT = + // spotless:off // healthcheckWait { - Wait.forHealthcheck() + Wait.forHealthcheck(); // } - ; + // spotless:on @Test public void testContainersAllStarted() { diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java index b60225010a1..82e3d83ab24 100644 --- a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java +++ b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java @@ -6,6 +6,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.WaitingConsumer; import org.testcontainers.utility.DockerImageName; @@ -14,34 +15,39 @@ import java.util.concurrent.TimeoutException; import static org.assertj.core.api.Assertions.assertThat; -import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT; -import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.IndefiniteOneShotStrategyTest; -import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.MinimumDurationStrategyTest; -import static org.testcontainers.containers.startupcheck.StartupCheckStrategyTest.OneShotStrategyTest; @RunWith(Suite.class) -@Suite.SuiteClasses({OneShotStrategyTest.class, IndefiniteOneShotStrategyTest.class, MinimumDurationStrategyTest.class}) +@Suite.SuiteClasses( + { + StartupCheckStrategyTest.OneShotStrategyTest.class, + StartupCheckStrategyTest.IndefiniteOneShotStrategyTest.class, + StartupCheckStrategyTest.MinimumDurationStrategyTest.class, + } +) public class StartupCheckStrategyTest { private static final String HELLO_TESTCONTAINERS = "Hello Testcontainers!"; private static void waitForHello(GenericContainer container) throws TimeoutException { WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, STDOUT); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - consumer.waitUntil(frame -> - frame.getUtf8String().contains(HELLO_TESTCONTAINERS), 30, TimeUnit.SECONDS); + consumer.waitUntil(frame -> frame.getUtf8String().contains(HELLO_TESTCONTAINERS), 30, TimeUnit.SECONDS); } public static class OneShotStrategyTest { + @Rule + // spotless:off // withOneShotStrategy { public GenericContainer bboxWithOneShot = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) .withCommand(String.format("echo %s", HELLO_TESTCONTAINERS)) .withStartupCheckStrategy( new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(3)) ); + // } + // spotless:on @SneakyThrows @Test @@ -53,14 +59,20 @@ public void testCommandIsExecuted() { } public static class IndefiniteOneShotStrategyTest { + @Rule + // spotless:off // withIndefiniteOneShotStrategy { - public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) + public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer<>( + DockerImageName.parse("busybox:1.31.1") + ) .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) .withStartupCheckStrategy( new IndefiniteWaitOneShotStartupCheckStrategy() ); + // } + // spotless:on @SneakyThrows @Test @@ -72,14 +84,20 @@ public void testCommandIsExecuted() { } public static class MinimumDurationStrategyTest { + @Rule + // spotless:off // withMinimumDurationStrategy { - public GenericContainer bboxWithMinimumDuration = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) + public GenericContainer bboxWithMinimumDuration = new GenericContainer<>( + DockerImageName.parse("busybox:1.31.1") + ) .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) .withStartupCheckStrategy( new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(1)) ); + // } + // spotless:on @SneakyThrows @Test diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index cbb49b5fdb3..1d3d178975f 100644 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -1,6 +1,5 @@ package quickstart; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -16,9 +15,9 @@ public class RedisBackedCacheIntTest { // rule { @Rule public GenericContainer redis = new GenericContainer(DockerImageName.parse("redis:5.0.3-alpine")) - .withExposedPorts(6379); - // } + .withExposedPorts(6379); + // } @Before public void setUp() { diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java index 61a86ac3f8b..f837b3af0d5 100644 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java +++ b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java @@ -1,6 +1,5 @@ package quickstart; - import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -9,6 +8,7 @@ @Ignore("This test class is deliberately invalid, as it relies on a non-existent local Redis") public class RedisBackedCacheIntTestStep0 { + private RedisBackedCache underTest; @Before diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index 9a3855ba23c..59d92210549 100644 --- a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -1,6 +1,5 @@ package quickstart; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; @@ -19,9 +18,9 @@ public class RedisBackedCacheIntTest { // container { @Container public GenericContainer redis = new GenericContainer(DockerImageName.parse("redis:5.0.3-alpine")) - .withExposedPorts(6379); - // } + .withExposedPorts(6379); + // } @BeforeEach public void setUp() { diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java index c81a185a188..d9f889a8943 100644 --- a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java @@ -1,6 +1,5 @@ package quickstart; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -9,6 +8,7 @@ @Disabled("This test class is deliberately invalid, as it relies on a non-existent local Redis") public class RedisBackedCacheIntTestStep0 { + private RedisBackedCache underTest; @BeforeEach diff --git a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy index 068c8079a7d..5cc04dc6b9d 100644 --- a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy +++ b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTest.groovy @@ -7,30 +7,30 @@ import spock.lang.Specification @org.testcontainers.spock.Testcontainers class RedisBackedCacheIntTest extends Specification { - private RedisBackedCache underTest + private RedisBackedCache underTest - // init { - GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") - .withExposedPorts(6379) - // } + // init { + GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine") + .withExposedPorts(6379) + // } - void setup() { - String address = redis.host - Integer port = redis.firstMappedPort + void setup() { + String address = redis.host + Integer port = redis.firstMappedPort - // Now we have an address and port for Redis, no matter where it is running - underTest = new RedisBackedCache(address, port) - } + // Now we have an address and port for Redis, no matter where it is running + underTest = new RedisBackedCache(address, port) + } - void testSimplePutAndGet() { - setup: - underTest.put("test", "example") + void testSimplePutAndGet() { + setup: + underTest.put("test", "example") - when: - String retrieved = underTest.get("test") + when: + String retrieved = underTest.get("test") - then: - retrieved == "example" - } + then: + retrieved == "example" + } } // } diff --git a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy index 52897c30097..d28942420da 100644 --- a/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy +++ b/docs/examples/spock/redis/src/test/groovy/quickstart/RedisBackedCacheIntTestStep0.groovy @@ -5,21 +5,21 @@ import spock.lang.Specification @Ignore("This test class is deliberately invalid, as it relies on a non-existent local Redis") class RedisBackedCacheIntTestStep0 extends Specification { - private RedisBackedCache underTest + private RedisBackedCache underTest - void setup() { - // Assume that we have Redis running locally? - underTest = new RedisBackedCache("localhost", 6379) - } + void setup() { + // Assume that we have Redis running locally? + underTest = new RedisBackedCache("localhost", 6379) + } - void testSimplePutAndGet() { - setup: - underTest.put("test", "example") + void testSimplePutAndGet() { + setup: + underTest.put("test", "example") - when: - String retrieved = underTest.get("test") + when: + String retrieved = underTest.get("test") - then: - retrieved == "example" - } + then: + retrieved == "example" + } } diff --git a/docs/modules/hivemq.md b/docs/modules/hivemq.md index 1e09bac4fc0..66f9670648c 100644 --- a/docs/modules/hivemq.md +++ b/docs/modules/hivemq.md @@ -31,7 +31,7 @@ Using the Community Edition: Using the Enterprise Edition: -[Enterprise Edition HiveMQ image](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:eeVersion +[Enterprise Edition HiveMQ image](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:hiveEEVersion Using a specifc version is possible by using the tag: @@ -138,7 +138,7 @@ The following example shows how to start a HiveMQ container with the extension c The following test then proceeds to enable and then disable the extension: -[Enable/Disable extension at runtime](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:runtimeEnable +[Enable/Disable extension at runtime](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:hiveRuntimeEnable ## Enable/Disable an extension loaded from a folder diff --git a/modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java index 9328d881666..57af95ef106 100644 --- a/modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java +++ b/modules/azure/src/main/java/org/testcontainers/containers/CosmosDBEmulatorContainer.java @@ -10,8 +10,9 @@ */ public class CosmosDBEmulatorContainer extends GenericContainer { - private static final DockerImageName DEFAULT_IMAGE_NAME = - DockerImageName.parse("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator"); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator" + ); private static final int PORT = 8081; diff --git a/modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java b/modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java index 0179e8d832a..f7b6af370ac 100644 --- a/modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java +++ b/modules/azure/src/main/java/org/testcontainers/containers/KeyStoreBuilder.java @@ -5,10 +5,6 @@ import okhttp3.Request; import okhttp3.Response; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; import java.io.InputStream; import java.security.KeyStore; import java.security.SecureRandom; @@ -17,6 +13,11 @@ import java.security.cert.X509Certificate; import java.util.Objects; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + final class KeyStoreBuilder { static KeyStore buildByDownloadingCertificate(String endpoint, String keyStorePassword) { @@ -38,20 +39,18 @@ static KeyStore buildByDownloadingCertificate(String endpoint, String keyStorePa private static TrustManager[] buildTrustAllManagers() { return new TrustManager[] { - new X509TrustManager() { - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) { - } + new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) {} - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) { - } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) {} - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[]{}; - } + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[] {}; } + }, }; } @@ -60,16 +59,13 @@ private static OkHttpClient buildTrustAllClient(TrustManager[] trustManagers) th sslContext.init(null, trustManagers, new SecureRandom()); SSLSocketFactory socketFactory = sslContext.getSocketFactory(); return new OkHttpClient.Builder() - .sslSocketFactory(socketFactory, (X509TrustManager) trustManagers[0]) - .hostnameVerifier((s, sslSession) -> true) - .build(); + .sslSocketFactory(socketFactory, (X509TrustManager) trustManagers[0]) + .hostnameVerifier((s, sslSession) -> true) + .build(); } private static Request buildRequest(String endpoint) { - return new Request.Builder() - .get() - .url(endpoint + "/_explorer/emulator.pem") - .build(); + return new Request.Builder().get().url(endpoint + "/_explorer/emulator.pem").build(); } private static KeyStore buildKeyStore(InputStream certificateStream, String keyStorePassword) throws Exception { @@ -85,8 +81,7 @@ private static void closeResponseSilently(Response response) { if (Objects.nonNull(response)) { response.close(); } - } catch (Exception ignored) { - } + } catch (Exception ignored) {} } private static void closeClientSilently(OkHttpClient client) { @@ -99,7 +94,6 @@ private static void closeClientSilently(OkHttpClient client) { cache.close(); } } - } catch (Exception ignored) { - } + } catch (Exception ignored) {} } } diff --git a/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java b/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java index dd9dc6b718f..37422b30af7 100644 --- a/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java +++ b/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java @@ -37,8 +37,9 @@ public static void restoreOriginalSystemProperties() { @Rule // emulatorContainer { public CosmosDBEmulatorContainer emulator = new CosmosDBEmulatorContainer( - DockerImageName.parse("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest") + DockerImageName.parse("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest") ); + // } @Test @@ -55,18 +56,19 @@ public void testWithCosmosClient() throws Exception { // } // buildClient { CosmosAsyncClient client = new CosmosClientBuilder() - .gatewayMode() - .endpointDiscoveryEnabled(false) - .endpoint(emulator.getEmulatorEndpoint()) - .key(emulator.getEmulatorKey()) - .buildAsyncClient(); + .gatewayMode() + .endpointDiscoveryEnabled(false) + .endpoint(emulator.getEmulatorEndpoint()) + .key(emulator.getEmulatorKey()) + .buildAsyncClient(); // } // testWithClientAgainstEmulatorContainer { - CosmosDatabaseResponse databaseResponse = - client.createDatabaseIfNotExists("Azure").block(); + CosmosDatabaseResponse databaseResponse = client.createDatabaseIfNotExists("Azure").block(); Assertions.assertThat(databaseResponse.getStatusCode()).isEqualTo(201); - CosmosContainerResponse containerResponse = - client.getDatabase("Azure").createContainerIfNotExists("ServiceContainer", "/name").block(); + CosmosContainerResponse containerResponse = client + .getDatabase("Azure") + .createContainerIfNotExists("ServiceContainer", "/name") + .block(); Assertions.assertThat(containerResponse.getStatusCode()).isEqualTo(201); // } } diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index e3ae084cb8a..3c78743fb62 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -10,12 +10,13 @@ import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; -import javax.script.ScriptException; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Optional; +import javax.script.ScriptException; + /** * Cassandra container * @@ -26,18 +27,24 @@ public class CassandraContainer> extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("cassandra"); + private static final String DEFAULT_TAG = "3.11.2"; @Deprecated public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); public static final Integer CQL_PORT = 9042; + private static final String CONTAINER_CONFIG_LOCATION = "/etc/cassandra"; + private static final String USERNAME = "cassandra"; + private static final String PASSWORD = "cassandra"; private String configLocation; + private String initScriptPath; + private boolean enableJmxReporting; /** @@ -54,17 +61,13 @@ public CassandraContainer(String dockerImageName) { public CassandraContainer(DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPort(CQL_PORT); this.enableJmxReporting = false; withEnv("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch"); - withEnv( - "JVM_OPTS", - "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0" - ); + withEnv("JVM_OPTS", "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0"); withEnv("HEAP_NEWSIZE", "128M"); withEnv("MAX_HEAP_SIZE", "1024M"); } @@ -88,7 +91,9 @@ private void runInitScriptIfRequired() { URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath); if (resource == null) { logger().warn("Could not load classpath init script: {}", initScriptPath); - throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath + ". Resource not found."); + throw new ScriptLoadException( + "Could not load classpath init script: " + initScriptPath + ". Resource not found." + ); } String cql = IOUtils.toString(resource, StandardCharsets.UTF_8); DatabaseDelegate databaseDelegate = getDatabaseDelegate(); @@ -98,7 +103,10 @@ private void runInitScriptIfRequired() { throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath, e); } catch (ScriptException e) { logger().error("Error while executing init script: {}", initScriptPath, e); - throw new ScriptUtils.UncategorizedScriptException("Error while executing init script: " + initScriptPath, e); + throw new ScriptUtils.UncategorizedScriptException( + "Error while executing init script: " + initScriptPath, + e + ); } } } @@ -112,9 +120,10 @@ private void runInitScriptIfRequired() { * @param resourceLocation relative classpath to resource */ protected void optionallyMapResourceParameterAsVolume(String pathNameInContainer, String resourceLocation) { - Optional.ofNullable(resourceLocation) - .map(MountableFile::forClasspathResource) - .ifPresent(mountableFile -> withCopyFileToContainer(mountableFile, pathNameInContainer)); + Optional + .ofNullable(resourceLocation) + .map(MountableFile::forClasspathResource) + .ifPresent(mountableFile -> withCopyFileToContainer(mountableFile, pathNameInContainer)); } /** @@ -184,7 +193,8 @@ public Cluster getCluster() { } public static Cluster getCluster(ContainerState containerState, boolean enableJmxReporting) { - final Cluster.Builder builder = Cluster.builder() + final Cluster.Builder builder = Cluster + .builder() .addContactPoint(containerState.getHost()) .withPort(containerState.getMappedPort(CQL_PORT)); if (!enableJmxReporting) { diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java b/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java index e55dd31b0ff..8bc72e7f154 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java @@ -25,8 +25,7 @@ public class CassandraDatabaseDelegate extends AbstractDatabaseDelegate @Override protected Session createNewConnection() { try { - return CassandraContainer.getCluster(container) - .newSession(); + return CassandraContainer.getCluster(container).newSession(); } catch (DriverException e) { log.error("Could not obtain cassandra connection"); throw new ConnectionCreationException("Could not obtain cassandra connection", e); @@ -34,7 +33,13 @@ protected Session createNewConnection() { } @Override - public void execute(String statement, String scriptPath, int lineNumber, boolean continueOnError, boolean ignoreFailedDrops) { + public void execute( + String statement, + String scriptPath, + int lineNumber, + boolean continueOnError, + boolean ignoreFailedDrops + ) { try { ResultSet result = getConnection().execute(statement); if (result.wasApplied()) { diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/wait/CassandraQueryWaitStrategy.java b/modules/cassandra/src/main/java/org/testcontainers/containers/wait/CassandraQueryWaitStrategy.java index cf7f3769985..aa2466cf7c4 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/wait/CassandraQueryWaitStrategy.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/wait/CassandraQueryWaitStrategy.java @@ -18,20 +18,26 @@ public class CassandraQueryWaitStrategy extends AbstractWaitStrategy { private static final String SELECT_VERSION_QUERY = "SELECT release_version FROM system.local"; + private static final String TIMEOUT_ERROR = "Timed out waiting for Cassandra to be accessible for query execution"; @Override protected void waitUntilReady() { // execute select version query until success or timeout try { - retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> { - getRateLimiter().doWhenReady(() -> { - try (DatabaseDelegate databaseDelegate = getDatabaseDelegate()) { - databaseDelegate.execute(SELECT_VERSION_QUERY, "", 1, false, false); - } - }); - return true; - }); + retryUntilSuccess( + (int) startupTimeout.getSeconds(), + TimeUnit.SECONDS, + () -> { + getRateLimiter() + .doWhenReady(() -> { + try (DatabaseDelegate databaseDelegate = getDatabaseDelegate()) { + databaseDelegate.execute(SELECT_VERSION_QUERY, "", 1, false, false); + } + }); + return true; + } + ); } catch (TimeoutException e) { throw new ContainerLaunchException(TIMEOUT_ERROR); } diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java index 76c8c8438d7..45cbba0abc7 100644 --- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java @@ -36,7 +36,11 @@ public void testSimple() { @Test public void testSpecificVersion() { String cassandraVersion = "3.0.15"; - try (CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE.withTag(cassandraVersion))) { + try ( + CassandraContainer cassandraContainer = new CassandraContainer<>( + CASSANDRA_IMAGE.withTag(cassandraVersion) + ) + ) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, "SELECT release_version FROM system.local"); assertTrue("Query was not applied", resultSet.wasApplied()); @@ -53,7 +57,11 @@ public void testConfigurationOverride() { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, "SELECT cluster_name FROM system.local"); assertTrue("Query was not applied", resultSet.wasApplied()); - assertEquals("Cassandra configuration is not overridden", TEST_CLUSTER_NAME_IN_CONF, resultSet.one().getString(0)); + assertEquals( + "Cassandra configuration is not overridden", + TEST_CLUSTER_NAME_IN_CONF, + resultSet.one().getString(0) + ); } } @@ -81,7 +89,9 @@ public void testInitScript() { @Test public void testInitScriptWithLegacyCassandra() { try ( - CassandraContainer cassandraContainer = new CassandraContainer<>(DockerImageName.parse("cassandra:2.2.11")) + CassandraContainer cassandraContainer = new CassandraContainer<>( + DockerImageName.parse("cassandra:2.2.11") + ) .withInitScript("initial.cql") ) { cassandraContainer.start(); @@ -107,7 +117,10 @@ public void testCassandraQueryWaitStrategy() { public void testCassandraGetCluster() { try (CassandraContainer cassandraContainer = new CassandraContainer<>()) { cassandraContainer.start(); - ResultSet resultSet = performQuery(cassandraContainer.getCluster(), "SELECT release_version FROM system.local"); + ResultSet resultSet = performQuery( + cassandraContainer.getCluster(), + "SELECT release_version FROM system.local" + ); assertTrue("Query was not applied", resultSet.wasApplied()); assertNotNull("Result set has no release_version", resultSet.one().getString(0)); } @@ -122,7 +135,8 @@ private void testInitScript(CassandraContainer cassandraContainer) { } private ResultSet performQuery(CassandraContainer cassandraContainer, String cql) { - Cluster explicitCluster = Cluster.builder() + Cluster explicitCluster = Cluster + .builder() .addContactPoint(cassandraContainer.getHost()) .withPort(cassandraContainer.getMappedPort(CassandraContainer.CQL_PORT)) .build(); diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 9b5f130a323..4528c48e935 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -8,6 +8,7 @@ import java.util.Set; public class ClickHouseContainer extends JdbcDatabaseContainer { + public static final String NAME = "clickhouse"; private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("yandex/clickhouse-server"); @@ -19,14 +20,19 @@ public class ClickHouseContainer extends JdbcDatabaseContainer { public static final String DEFAULT_TAG = "18.10.3"; public static final Integer HTTP_PORT = 8123; + public static final Integer NATIVE_PORT = 9000; private static final String DRIVER_CLASS_NAME = "ru.yandex.clickhouse.ClickHouseDriver"; + private static final String JDBC_URL_PREFIX = "jdbc:" + NAME + "://"; + private static final String TEST_QUERY = "SELECT 1"; private String databaseName = "default"; + private String username = "default"; + private String password = ""; /** @@ -43,7 +49,6 @@ public ClickHouseContainer(String dockerImageName) { public ClickHouseContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(HTTP_PORT, NATIVE_PORT); diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java index cd2453b8349..80fb71bd5da 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseProvider.java @@ -3,6 +3,7 @@ import org.testcontainers.utility.DockerImageName; public class ClickHouseProvider extends JdbcDatabaseContainerProvider { + @Override public boolean supports(String databaseType) { return databaseType.equals(ClickHouseContainer.NAME); diff --git a/modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java b/modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java index f3946c8a317..056aace7772 100644 --- a/modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java +++ b/modules/clickhouse/src/test/java/org/testcontainers/jdbc/clickhouse/ClickhouseJDBCDriverTest.java @@ -4,18 +4,18 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class ClickhouseJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken)}, - }); + return Arrays.asList( + new Object[][] { // + { "jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken) }, + } + ); } } diff --git a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java index 8f3879673a0..d2375891f8c 100644 --- a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java +++ b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java @@ -1,6 +1,7 @@ package org.testcontainers.junit.clickhouse; import org.junit.Test; +import org.testcontainers.ClickhouseTestImages; import org.testcontainers.containers.ClickHouseContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -8,13 +9,12 @@ import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.ClickhouseTestImages.CLICKHOUSE_IMAGE; public class SimpleClickhouseTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (ClickHouseContainer clickhouse = new ClickHouseContainer(CLICKHOUSE_IMAGE)) { + try (ClickHouseContainer clickhouse = new ClickHouseContainer(ClickhouseTestImages.CLICKHOUSE_IMAGE)) { clickhouse.start(); ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); diff --git a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java index f32e6bce385..dfec3988f15 100644 --- a/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java +++ b/modules/cockroachdb/src/main/java/org/testcontainers/containers/CockroachContainer.java @@ -8,6 +8,7 @@ public class CockroachContainer extends JdbcDatabaseContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("cockroachdb/cockroach"); + private static final String DEFAULT_TAG = "v19.2.11"; public static final String NAME = "cockroach"; @@ -19,13 +20,19 @@ public class CockroachContainer extends JdbcDatabaseContainer data() { - return asList( - new Object[][]{ - {"jdbc:tc:cockroach://hostname/databasename", EnumSet.noneOf(Options.class)}, - }); + return Arrays.asList( + new Object[][] { // + { "jdbc:tc:cockroach://hostname/databasename", EnumSet.noneOf(Options.class) }, + } + ); } } diff --git a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java index 3121ad82100..87e82fb30e3 100644 --- a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java +++ b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java @@ -1,6 +1,7 @@ package org.testcontainers.junit.cockroachdb; import org.junit.Test; +import org.testcontainers.CockroachDBTestImages; import org.testcontainers.containers.CockroachContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -9,13 +10,11 @@ import java.util.logging.Level; import java.util.logging.LogManager; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.CockroachDBTestImages.COCKROACHDB_IMAGE; public class SimpleCockroachDBTest extends AbstractContainerDatabaseTest { - static { // Postgres JDBC driver uses JUL; disable it to avoid annoying, irrelevant, stderr logs during connection testing LogManager.getLogManager().getLogger("").setLevel(Level.OFF); @@ -23,7 +22,7 @@ public class SimpleCockroachDBTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (CockroachContainer cockroach = new CockroachContainer(COCKROACHDB_IMAGE)) { + try (CockroachContainer cockroach = new CockroachContainer(CockroachDBTestImages.COCKROACHDB_IMAGE)) { cockroach.start(); ResultSet resultSet = performQuery(cockroach, "SELECT 1"); @@ -35,8 +34,10 @@ public void testSimple() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (CockroachContainer cockroach = new CockroachContainer(COCKROACHDB_IMAGE) - .withInitScript("somepath/init_postgresql.sql")) { // CockroachDB is expected to be compatible with Postgres + try ( + CockroachContainer cockroach = new CockroachContainer(CockroachDBTestImages.COCKROACHDB_IMAGE) + .withInitScript("somepath/init_postgresql.sql") + ) { // CockroachDB is expected to be compatible with Postgres cockroach.start(); ResultSet resultSet = performQuery(cockroach, "SELECT foo FROM bar"); @@ -48,7 +49,7 @@ public void testExplicitInitScript() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - CockroachContainer cockroach = new CockroachContainer(COCKROACHDB_IMAGE) + CockroachContainer cockroach = new CockroachContainer(CockroachDBTestImages.COCKROACHDB_IMAGE) .withUrlParam("sslmode", "disable") .withUrlParam("application_name", "cockroach"); diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java index 3778833182e..ad666b4ffef 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java @@ -22,8 +22,11 @@ public class BucketDefinition { private final String name; + private boolean flushEnabled = false; + private boolean queryPrimaryIndex = true; + private int quota = 100; public BucketDefinition(final String name) { @@ -49,7 +52,7 @@ public BucketDefinition withFlushEnabled(final boolean flushEnabled) { */ public BucketDefinition withQuota(final int quota) { if (quota < 100) { - throw new IllegalArgumentException("Bucket quota cannot be less than 100MB!"); + throw new IllegalArgumentException("Bucket quota cannot be less than 100MB!"); } this.quota = quota; return this; @@ -81,5 +84,4 @@ public boolean hasPrimaryIndex() { public int getQuota() { return quota; } - } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index c2becc68fc3..4f190a5413c 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.testcontainers.couchbase; import com.fasterxml.jackson.databind.JsonNode; @@ -139,7 +140,6 @@ public CouchbaseContainer(final String dockerImageName) { */ public CouchbaseContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); } @@ -182,8 +182,14 @@ public CouchbaseContainer withServiceQuota(final CouchbaseService service, final throw new IllegalArgumentException("The provided service (" + service + ") has no quota to configure"); } if (quotaMb < service.getMinimumQuotaMb()) { - throw new IllegalArgumentException("The custom quota (" + quotaMb + ") must not be smaller than the " + - "minimum quota for the service (" + service.getMinimumQuotaMb() + ")"); + throw new IllegalArgumentException( + "The custom quota (" + + quotaMb + + ") must not be smaller than the " + + "minimum quota for the service (" + + service.getMinimumQuotaMb() + + ")" + ); } this.customServiceQuotas.put(service, quotaMb); return this; @@ -255,54 +261,59 @@ protected void configure() { WaitAllStrategy waitStrategy = new WaitAllStrategy(); // Makes sure that all nodes in the cluster are healthy. - waitStrategy = waitStrategy.withStrategy( - new HttpWaitStrategy() - .forPath("/pools/default") - .forPort(MGMT_PORT) - .withBasicCredentials(username, password) - .forStatusCode(200) - .forResponsePredicate(response -> { - try { - return Optional.of(MAPPER.readTree(response)) - .map(n -> n.at("/nodes/0/status")) - .map(JsonNode::asText) - .map("healthy"::equals) - .orElse(false); - } catch (IOException e) { - logger().error("Unable to parse response: {}", response, e); - return false; - } - }) - ); - - if (enabledServices.contains(CouchbaseService.QUERY)) { - waitStrategy = waitStrategy.withStrategy( + waitStrategy = + waitStrategy.withStrategy( new HttpWaitStrategy() - .forPath("/admin/ping") - .forPort(QUERY_PORT) + .forPath("/pools/default") + .forPort(MGMT_PORT) .withBasicCredentials(username, password) .forStatusCode(200) + .forResponsePredicate(response -> { + try { + return Optional + .of(MAPPER.readTree(response)) + .map(n -> n.at("/nodes/0/status")) + .map(JsonNode::asText) + .map("healthy"::equals) + .orElse(false); + } catch (IOException e) { + logger().error("Unable to parse response: {}", response, e); + return false; + } + }) ); + + if (enabledServices.contains(CouchbaseService.QUERY)) { + waitStrategy = + waitStrategy.withStrategy( + new HttpWaitStrategy() + .forPath("/admin/ping") + .forPort(QUERY_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + ); } if (enabledServices.contains(CouchbaseService.ANALYTICS)) { - waitStrategy = waitStrategy.withStrategy( - new HttpWaitStrategy() - .forPath("/admin/ping") - .forPort(ANALYTICS_PORT) - .withBasicCredentials(username, password) - .forStatusCode(200) - ); + waitStrategy = + waitStrategy.withStrategy( + new HttpWaitStrategy() + .forPath("/admin/ping") + .forPort(ANALYTICS_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + ); } if (enabledServices.contains(CouchbaseService.EVENTING)) { - waitStrategy = waitStrategy.withStrategy( - new HttpWaitStrategy() - .forPath("/api/v1/config") - .forPort(EVENTING_PORT) - .withBasicCredentials(username, password) - .forStatusCode(200) - ); + waitStrategy = + waitStrategy.withStrategy( + new HttpWaitStrategy() + .forPath("/api/v1/config") + .forPort(EVENTING_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + ); } waitingFor(waitStrategy); @@ -329,25 +340,23 @@ protected void containerIsStarting(final InspectContainerResponse containerInfo) protected void containerIsStarted(InspectContainerResponse containerInfo) { timePhase("createBuckets", this::createBuckets); - logger().info("Couchbase container is ready! UI available at http://{}:{}", getHost(), getMappedPort(MGMT_PORT)); + logger() + .info("Couchbase container is ready! UI available at http://{}:{}", getHost(), getMappedPort(MGMT_PORT)); } /** * Before we can start configuring the host, we need to wait until the cluster manager is listening. */ private void waitUntilNodeIsOnline() { - new HttpWaitStrategy() - .forPort(MGMT_PORT) - .forPath("/pools") - .forStatusCode(200) - .waitUntilReady(this); + new HttpWaitStrategy().forPort(MGMT_PORT).forPath("/pools").forStatusCode(200).waitUntilReady(this); } /** * Fetches edition (enterprise or community) of started container. */ private void initializeIsEnterprise() { - @Cleanup Response response = doHttpRequest(MGMT_PORT, "/pools", "GET", null, true); + @Cleanup + Response response = doHttpRequest(MGMT_PORT, "/pools", "GET", null, true); try { isEnterprise = MAPPER.readTree(response.body().string()).get("isEnterprise").asBoolean(); @@ -374,9 +383,13 @@ private void initializeIsEnterprise() { private void renameNode() { logger().debug("Renaming Couchbase Node from localhost to {}", getHost()); - @Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/rename", "POST", new FormBody.Builder() - .add("hostname", getInternalIpAddress()) - .build(), false + @Cleanup + Response response = doHttpRequest( + MGMT_PORT, + "/node/controller/rename", + "POST", + new FormBody.Builder().add("hostname", getInternalIpAddress()).build(), + false ); checkSuccessfulResponse(response, "Could not rename couchbase node"); @@ -393,9 +406,13 @@ private void initializeServices() { .map(CouchbaseService::getIdentifier) .collect(Collectors.joining(",")); - @Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder() - .add("services", services) - .build(), false + @Cleanup + Response response = doHttpRequest( + MGMT_PORT, + "/node/controller/setupServices", + "POST", + new FormBody.Builder().add("services", services).build(), + false ); checkSuccessfulResponse(response, "Could not enable couchbase services"); @@ -423,9 +440,8 @@ private void setMemoryQuotas() { } } - @Cleanup Response response = doHttpRequest( - MGMT_PORT, "/pools/default", "POST", quotaBuilder.build(), false - ); + @Cleanup + Response response = doHttpRequest(MGMT_PORT, "/pools/default", "POST", quotaBuilder.build(), false); checkSuccessfulResponse(response, "Could not configure service memory quotas"); } @@ -438,11 +454,18 @@ private void setMemoryQuotas() { private void configureAdminUser() { logger().debug("Configuring couchbase admin user with username: \"{}\"", username); - @Cleanup Response response = doHttpRequest(MGMT_PORT, "/settings/web", "POST", new FormBody.Builder() - .add("username", username) - .add("password", password) - .add("port", Integer.toString(MGMT_PORT)) - .build(), false); + @Cleanup + Response response = doHttpRequest( + MGMT_PORT, + "/settings/web", + "POST", + new FormBody.Builder() + .add("username", username) + .add("password", password) + .add("port", Integer.toString(MGMT_PORT)) + .build(), + false + ); checkSuccessfulResponse(response, "Could not configure couchbase admin user"); } @@ -489,7 +512,8 @@ private void configureExternalPorts() { builder.add("eventingSSL", Integer.toString(getMappedPort(EVENTING_SSL_PORT))); } - @Cleanup Response response = doHttpRequest( + @Cleanup + Response response = doHttpRequest( MGMT_PORT, "/node/controller/setupAlternateAddresses/external", "PUT", @@ -506,9 +530,13 @@ private void configureExternalPorts() { private void configureIndexer() { logger().debug("Configuring the indexer service"); - @Cleanup Response response = doHttpRequest(MGMT_PORT, "/settings/indexes", "POST", new FormBody.Builder() - .add("storageMode", isEnterprise ? "memory_optimized" : "forestdb") - .build(), true + @Cleanup + Response response = doHttpRequest( + MGMT_PORT, + "/settings/indexes", + "POST", + new FormBody.Builder().add("storageMode", isEnterprise ? "memory_optimized" : "forestdb").build(), + true ); checkSuccessfulResponse(response, "Could not configure the indexing service"); @@ -523,22 +551,32 @@ private void createBuckets() { for (BucketDefinition bucket : buckets) { logger().debug("Creating bucket \"{}\"", bucket.getName()); - @Cleanup Response response = doHttpRequest(MGMT_PORT, "/pools/default/buckets", "POST", new FormBody.Builder() - .add("name", bucket.getName()) - .add("ramQuotaMB", Integer.toString(bucket.getQuota())) - .add("flushEnabled", bucket.hasFlushEnabled() ? "1" : "0") - .build(), true); + @Cleanup + Response response = doHttpRequest( + MGMT_PORT, + "/pools/default/buckets", + "POST", + new FormBody.Builder() + .add("name", bucket.getName()) + .add("ramQuotaMB", Integer.toString(bucket.getQuota())) + .add("flushEnabled", bucket.hasFlushEnabled() ? "1" : "0") + .build(), + true + ); checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName()); - timePhase("createBucket:" + bucket.getName() + ":waitForAllServicesEnabled", () -> - new HttpWaitStrategy() - .forPath("/pools/default/b/" + bucket.getName()) - .forPort(MGMT_PORT) - .withBasicCredentials(username, password) - .forStatusCode(200) - .forResponsePredicate(new AllServicesEnabledPredicate()) - .waitUntilReady(this) + timePhase( + "createBucket:" + bucket.getName() + ":waitForAllServicesEnabled", + () -> { + new HttpWaitStrategy() + .forPath("/pools/default/b/" + bucket.getName()) + .forPort(MGMT_PORT) + .withBasicCredentials(username, password) + .forStatusCode(200) + .forResponsePredicate(new AllServicesEnabledPredicate()) + .waitUntilReady(this); + } ); if (enabledServices.contains(CouchbaseService.QUERY)) { @@ -546,29 +584,62 @@ private void createBuckets() { // knows about the bucket in its metadata configuration. timePhase( "createBucket:" + bucket.getName() + ":queryKeyspacePresent", - () -> Unreliables.retryUntilTrue(1, TimeUnit.MINUTES, () -> { - @Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() - .add("statement", "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" + bucket.getName() + "\"") - .build(), true); - - String body = queryResponse.body() != null ? queryResponse.body().string() : null; - checkSuccessfulResponse(queryResponse, "Could not poll query service state for bucket: " + bucket.getName()); - - return Optional.of(MAPPER.readTree(body)) - .map(n -> n.at("/results/0/present")) - .map(JsonNode::asBoolean) - .orElse(false); - })); + () -> { + Unreliables.retryUntilTrue( + 1, + TimeUnit.MINUTES, + () -> { + @Cleanup + Response queryResponse = doHttpRequest( + QUERY_PORT, + "/query/service", + "POST", + new FormBody.Builder() + .add( + "statement", + "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" + + bucket.getName() + + "\"" + ) + .build(), + true + ); + + String body = queryResponse.body() != null ? queryResponse.body().string() : null; + checkSuccessfulResponse( + queryResponse, + "Could not poll query service state for bucket: " + bucket.getName() + ); + + return Optional + .of(MAPPER.readTree(body)) + .map(n -> n.at("/results/0/present")) + .map(JsonNode::asBoolean) + .orElse(false); + } + ); + } + ); } if (bucket.hasPrimaryIndex()) { if (enabledServices.contains(CouchbaseService.QUERY)) { - @Cleanup Response queryResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() - .add("statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`") - .build(), true); + @Cleanup + Response queryResponse = doHttpRequest( + QUERY_PORT, + "/query/service", + "POST", + new FormBody.Builder() + .add("statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`") + .build(), + true + ); try { - checkSuccessfulResponse(queryResponse, "Could not create primary index for bucket " + bucket.getName()); + checkSuccessfulResponse( + queryResponse, + "Could not create primary index for bucket " + bucket.getName() + ); } catch (IllegalStateException ex) { // potentially ignore the error, the index will be eventually built. if (!ex.getMessage().contains("Index creation will be retried in background")) { @@ -578,21 +649,48 @@ private void createBuckets() { timePhase( "createBucket:" + bucket.getName() + ":primaryIndexOnline", - () -> Unreliables.retryUntilTrue(1, TimeUnit.MINUTES, () -> { - @Cleanup Response stateResponse = doHttpRequest(QUERY_PORT, "/query/service", "POST", new FormBody.Builder() - .add("statement", "SELECT count(*) > 0 AS online FROM system:indexes where keyspace_id = \"" + bucket.getName() + "\" and is_primary = true and state = \"online\"") - .build(), true); - - String body = stateResponse.body() != null ? stateResponse.body().string() : null; - checkSuccessfulResponse(stateResponse, "Could not poll primary index state for bucket: " + bucket.getName()); - - return Optional.of(MAPPER.readTree(body)) - .map(n -> n.at("/results/0/online")) - .map(JsonNode::asBoolean) - .orElse(false); - })); + () -> { + Unreliables.retryUntilTrue( + 1, + TimeUnit.MINUTES, + () -> { + @Cleanup + Response stateResponse = doHttpRequest( + QUERY_PORT, + "/query/service", + "POST", + new FormBody.Builder() + .add( + "statement", + "SELECT count(*) > 0 AS online FROM system:indexes where keyspace_id = \"" + + bucket.getName() + + "\" and is_primary = true and state = \"online\"" + ) + .build(), + true + ); + + String body = stateResponse.body() != null ? stateResponse.body().string() : null; + checkSuccessfulResponse( + stateResponse, + "Could not poll primary index state for bucket: " + bucket.getName() + ); + + return Optional + .of(MAPPER.readTree(body)) + .map(n -> n.at("/results/0/online")) + .map(JsonNode::asBoolean) + .orElse(false); + } + ); + } + ); } else { - logger().info("Primary index creation for bucket {} ignored, since QUERY service is not present.", bucket.getName()); + logger() + .info( + "Primary index creation for bucket {} ignored, since QUERY service is not present.", + bucket.getName() + ); } } } @@ -602,7 +700,11 @@ private void createBuckets() { * Helper method to extract the internal IP address based on the network configuration. */ private String getInternalIpAddress() { - return getContainerInfo().getNetworkSettings().getNetworks().values().stream() + return getContainerInfo() + .getNetworkSettings() + .getNetworks() + .values() + .stream() .findFirst() .map(ContainerNetwork::getIpAddress) .orElseThrow(() -> new IllegalStateException("No network available to extract the internal IP from!")); @@ -648,8 +750,13 @@ private void checkNotRunning() { * @param auth if authentication with the admin user and password should be used. * @return the response of the request. */ - private Response doHttpRequest(final int port, final String path, final String method, final RequestBody body, - final boolean auth) { + private Response doHttpRequest( + final int port, + final String path, + final String method, + final RequestBody body, + final boolean auth + ) { try { Request.Builder requestBuilder = new Request.Builder() .url("http://" + getHost() + ":" + getMappedPort(port) + path); diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java index ffb0c9f7f1f..d9a9d2ffe3a 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java @@ -20,7 +20,6 @@ * Describes the different services that should be exposed on the container. */ public enum CouchbaseService { - /** * Key-Value service. */ @@ -88,5 +87,4 @@ int getMinimumQuotaMb() { boolean hasQuota() { return minimumQuotaMb > 0; } - } diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index c91f3f12d7c..1bdbe2ab1db 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -34,10 +34,13 @@ public class CouchbaseContainerTest { - private static final DockerImageName COUCHBASE_IMAGE_ENTERPRISE = - DockerImageName.parse("couchbase/server:enterprise-7.0.3"); - private static final DockerImageName COUCHBASE_IMAGE_COMMUNITY = - DockerImageName.parse("couchbase/server:community-7.0.2"); + private static final DockerImageName COUCHBASE_IMAGE_ENTERPRISE = DockerImageName.parse( + "couchbase/server:enterprise-7.0.3" + ); + + private static final DockerImageName COUCHBASE_IMAGE_COMMUNITY = DockerImageName.parse( + "couchbase/server:community-7.0.2" + ); @Test public void testBasicContainerUsageForEnterpriseContainer() { @@ -51,18 +54,21 @@ public void testBasicContainerUsageForEnterpriseContainer() { .withBucket(bucketDefinition) // } ) { - setUpClient(container, cluster -> { - Bucket bucket = cluster.bucket(bucketDefinition.getName()); - bucket.waitUntilReady(Duration.ofSeconds(10L)); + setUpClient( + container, + cluster -> { + Bucket bucket = cluster.bucket(bucketDefinition.getName()); + bucket.waitUntilReady(Duration.ofSeconds(10L)); - Collection collection = bucket.defaultCollection(); + Collection collection = bucket.defaultCollection(); - collection.upsert("foo", JsonObject.create().put("key", "value")); + collection.upsert("foo", JsonObject.create().put("key", "value")); - JsonObject fooObject = collection.get("foo").contentAsObject(); + JsonObject fooObject = collection.get("foo").contentAsObject(); - assertEquals("value", fooObject.getString("key")); - }); + assertEquals("value", fooObject.getString("key")); + } + ); } } @@ -74,42 +80,47 @@ public void testBasicContainerUsageForCommunityContainer() { CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) .withBucket(bucketDefinition) ) { - setUpClient(container, cluster -> { - Bucket bucket = cluster.bucket(bucketDefinition.getName()); - bucket.waitUntilReady(Duration.ofSeconds(10L)); + setUpClient( + container, + cluster -> { + Bucket bucket = cluster.bucket(bucketDefinition.getName()); + bucket.waitUntilReady(Duration.ofSeconds(10L)); - Collection collection = bucket.defaultCollection(); + Collection collection = bucket.defaultCollection(); - collection.upsert("foo", JsonObject.create().put("key", "value")); + collection.upsert("foo", JsonObject.create().put("key", "value")); - JsonObject fooObject = collection.get("foo").contentAsObject(); + JsonObject fooObject = collection.get("foo").contentAsObject(); - assertEquals("value", fooObject.getString("key")); - }); + assertEquals("value", fooObject.getString("key")); + } + ); } } @Test public void testBucketIsFlushableIfEnabled() { - BucketDefinition bucketDefinition = new BucketDefinition("mybucket") - .withFlushEnabled(true); + BucketDefinition bucketDefinition = new BucketDefinition("mybucket").withFlushEnabled(true); try ( CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_ENTERPRISE) .withBucket(bucketDefinition) ) { - setUpClient(container, cluster -> { - Bucket bucket = cluster.bucket(bucketDefinition.getName()); - bucket.waitUntilReady(Duration.ofSeconds(10L)); + setUpClient( + container, + cluster -> { + Bucket bucket = cluster.bucket(bucketDefinition.getName()); + bucket.waitUntilReady(Duration.ofSeconds(10L)); - Collection collection = bucket.defaultCollection(); + Collection collection = bucket.defaultCollection(); - collection.upsert("foo", JsonObject.create().put("key", "value")); + collection.upsert("foo", JsonObject.create().put("key", "value")); - cluster.buckets().flushBucket(bucketDefinition.getName()); + cluster.buckets().flushBucket(bucketDefinition.getName()); - await().untilAsserted(() -> assertFalse(collection.exists("foo").exists())); - }); + await().untilAsserted(() -> assertFalse(collection.exists("foo").exists())); + } + ); } } @@ -123,7 +134,12 @@ public void testFailureIfCommunityUsedWithAnalytics() { CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) .withEnabledServices(CouchbaseService.KV, CouchbaseService.ANALYTICS) ) { - assertThrows(ContainerLaunchException.class, () -> setUpClient(container, cluster -> {})); + assertThrows( + ContainerLaunchException.class, + () -> { + setUpClient(container, cluster -> {}); + } + ); } } @@ -137,7 +153,12 @@ public void testFailureIfCommunityUsedWithEventing() { CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) .withEnabledServices(CouchbaseService.KV, CouchbaseService.EVENTING) ) { - assertThrows(ContainerLaunchException.class, () -> setUpClient(container, cluster -> {})); + assertThrows( + ContainerLaunchException.class, + () -> { + setUpClient(container, cluster -> {}); + } + ); } } diff --git a/modules/database-commons/src/main/java/org/testcontainers/delegate/AbstractDatabaseDelegate.java b/modules/database-commons/src/main/java/org/testcontainers/delegate/AbstractDatabaseDelegate.java index 14572dec421..196eb485b5f 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/delegate/AbstractDatabaseDelegate.java +++ b/modules/database-commons/src/main/java/org/testcontainers/delegate/AbstractDatabaseDelegate.java @@ -27,7 +27,12 @@ protected CONNECTION getConnection() { } @Override - public void execute(Collection statements, String scriptPath, boolean continueOnError, boolean ignoreFailedDrops) { + public void execute( + Collection statements, + String scriptPath, + boolean continueOnError, + boolean ignoreFailedDrops + ) { int lineNumber = 0; for (String statement : statements) { lineNumber++; diff --git a/modules/database-commons/src/main/java/org/testcontainers/delegate/DatabaseDelegate.java b/modules/database-commons/src/main/java/org/testcontainers/delegate/DatabaseDelegate.java index 55886d88143..eda8f197008 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/delegate/DatabaseDelegate.java +++ b/modules/database-commons/src/main/java/org/testcontainers/delegate/DatabaseDelegate.java @@ -10,11 +10,16 @@ * @author Eugeny Karpov */ public interface DatabaseDelegate extends AutoCloseable { - /** * Execute statement by the implementation of the delegate */ - void execute(String statement, String scriptPath, int lineNumber, boolean continueOnError, boolean ignoreFailedDrops); + void execute( + String statement, + String scriptPath, + int lineNumber, + boolean continueOnError, + boolean ignoreFailedDrops + ); /** * Execute collection of statements diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java index 1b94b84f368..eca4989c70e 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java @@ -22,13 +22,14 @@ import org.slf4j.LoggerFactory; import org.testcontainers.delegate.DatabaseDelegate; -import javax.script.ScriptException; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; +import javax.script.ScriptException; + /** * This is a modified version of the Spring-JDBC ScriptUtils class, adapted to reduce * dependencies and slightly alter the API. @@ -48,278 +49,346 @@ */ public abstract class ScriptUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(ScriptUtils.class); - - /** - * Default statement separator within SQL scripts. - */ - public static final String DEFAULT_STATEMENT_SEPARATOR = ";"; + private static final Logger LOGGER = LoggerFactory.getLogger(ScriptUtils.class); - /** - * Fallback statement separator within SQL scripts. - *

Used if neither a custom defined separator nor the - * {@link #DEFAULT_STATEMENT_SEPARATOR} is present in a given script. - */ - public static final String FALLBACK_STATEMENT_SEPARATOR = "\n"; + /** + * Default statement separator within SQL scripts. + */ + public static final String DEFAULT_STATEMENT_SEPARATOR = ";"; - /** - * Default prefix for line comments within SQL scripts. - */ - public static final String DEFAULT_COMMENT_PREFIX = "--"; + /** + * Fallback statement separator within SQL scripts. + *

Used if neither a custom defined separator nor the + * {@link #DEFAULT_STATEMENT_SEPARATOR} is present in a given script. + */ + public static final String FALLBACK_STATEMENT_SEPARATOR = "\n"; - /** - * Default start delimiter for block comments within SQL scripts. - */ - public static final String DEFAULT_BLOCK_COMMENT_START_DELIMITER = "/*"; + /** + * Default prefix for line comments within SQL scripts. + */ + public static final String DEFAULT_COMMENT_PREFIX = "--"; - /** - * Default end delimiter for block comments within SQL scripts. - */ - public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/"; + /** + * Default start delimiter for block comments within SQL scripts. + */ + public static final String DEFAULT_BLOCK_COMMENT_START_DELIMITER = "/*"; + /** + * Default end delimiter for block comments within SQL scripts. + */ + public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/"; - /** - * Prevent instantiation of this utility class. - */ - private ScriptUtils() { - /* no-op */ - } + /** + * Prevent instantiation of this utility class. + */ + private ScriptUtils() { + /* no-op */ + } /** - * Split an SQL script into separate statements delimited by the provided - * separator string. Each individual statement will be added to the provided - * {@code List}. - *

Within the script, the provided {@code commentPrefix} will be honored: - * any text beginning with the comment prefix and extending to the end of the - * line will be omitted from the output. Similarly, the provided - * {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter} - * delimiters will be honored: any text enclosed in a block comment will be - * omitted from the output. In addition, multiple adjacent whitespace characters - * will be collapsed into a single space. - * @param resource the resource from which the script was read - * @param script the SQL script; never {@code null} or empty - * @param separator text separating each statement — typically a ';' or - * newline character; never {@code null} - * @param commentPrefix the prefix that identifies SQL line comments — - * typically "--"; never {@code null} or empty - * @param blockCommentStartDelimiter the start block comment delimiter; - * never {@code null} or empty - * @param blockCommentEndDelimiter the end block comment delimiter; - * never {@code null} or empty - * @param statements the list that will contain the individual statements - */ - public static void splitSqlScript(String resource, String script, String separator, String commentPrefix, - String blockCommentStartDelimiter, String blockCommentEndDelimiter, List statements) { - - checkArgument(StringUtils.isNotEmpty(script), "script must not be null or empty"); - checkArgument(separator != null, "separator must not be null"); - checkArgument(StringUtils.isNotEmpty(commentPrefix), "commentPrefix must not be null or empty"); - checkArgument(StringUtils.isNotEmpty(blockCommentStartDelimiter), "blockCommentStartDelimiter must not be null or empty"); - checkArgument(StringUtils.isNotEmpty(blockCommentEndDelimiter), "blockCommentEndDelimiter must not be null or empty"); - - StringBuilder sb = new StringBuilder(); - boolean inEscape = false; - boolean inLineComment = false; - boolean inBlockComment = false; - Character currentLiteralDelimiter = null; - - int compoundStatementDepth = 0; - final String lowerCaseScriptContent = script.toLowerCase(); - char[] content = script.toCharArray(); - for (int i = 0; i < script.length(); i++) { - char c = content[i]; - if (inEscape) { - inEscape = false; - sb.append(c); - continue; - } - // MySQL style escapes - if (c == '\\') { - inEscape = true; - sb.append(c); - continue; - } - // Determine whether we're entering/leaving a string literal - if (!inBlockComment && !inLineComment && (c == '\'' || c == '"' || c == '`')) { - if (currentLiteralDelimiter == null) { // ignore delimiters within an existing string literal - currentLiteralDelimiter = c; - } else if (currentLiteralDelimiter == c) { // find end of string literal - currentLiteralDelimiter = null; - } - } - final boolean inLiteral = currentLiteralDelimiter != null; - - if (!inLiteral && containsSubstringAtOffset(lowerCaseScriptContent, commentPrefix, i)) { - inLineComment = true; - } - if (inLineComment && c == '\n') { - inLineComment = false; - } - if (!inLiteral && containsSubstringAtOffset(lowerCaseScriptContent, blockCommentStartDelimiter, i)) { - inBlockComment = true; - } - if (!inLiteral && inBlockComment && containsSubstringAtOffset(lowerCaseScriptContent, blockCommentEndDelimiter, i)) { - inBlockComment = false; - } - final boolean inComment = inLineComment || inBlockComment; - - if (!inLiteral && !inComment && containsKeywordsAtOffset(lowerCaseScriptContent, "BEGIN", i, separator, commentPrefix, blockCommentStartDelimiter)) { - compoundStatementDepth++; - } - if (!inLiteral && !inComment && containsKeywordsAtOffset(lowerCaseScriptContent, "END", i, separator, commentPrefix, blockCommentStartDelimiter)) { - compoundStatementDepth--; - } - final boolean inCompoundStatement = compoundStatementDepth != 0; - - if (!inLiteral && !inCompoundStatement) { - if (script.startsWith(separator, i)) { - // we've reached the end of the current statement - sb = flushStringBuilder(sb, statements); - i += separator.length() - 1; - continue; - } - else if (script.startsWith(commentPrefix, i)) { - // skip over any content from the start of the comment to the EOL - int indexOfNextNewline = script.indexOf("\n", i); - if (indexOfNextNewline > i) { - i = indexOfNextNewline; - continue; - } - else { - // if there's no EOL, we must be at the end - // of the script, so stop here. - break; - } - } - else if (script.startsWith(blockCommentStartDelimiter, i)) { - // skip over any block comments - int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); - if (indexOfCommentEnd > i) { - i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; + * Split an SQL script into separate statements delimited by the provided + * separator string. Each individual statement will be added to the provided + * {@code List}. + *

Within the script, the provided {@code commentPrefix} will be honored: + * any text beginning with the comment prefix and extending to the end of the + * line will be omitted from the output. Similarly, the provided + * {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter} + * delimiters will be honored: any text enclosed in a block comment will be + * omitted from the output. In addition, multiple adjacent whitespace characters + * will be collapsed into a single space. + * @param resource the resource from which the script was read + * @param script the SQL script; never {@code null} or empty + * @param separator text separating each statement — typically a ';' or + * newline character; never {@code null} + * @param commentPrefix the prefix that identifies SQL line comments — + * typically "--"; never {@code null} or empty + * @param blockCommentStartDelimiter the start block comment delimiter; + * never {@code null} or empty + * @param blockCommentEndDelimiter the end block comment delimiter; + * never {@code null} or empty + * @param statements the list that will contain the individual statements + */ + public static void splitSqlScript( + String resource, + String script, + String separator, + String commentPrefix, + String blockCommentStartDelimiter, + String blockCommentEndDelimiter, + List statements + ) { + checkArgument(StringUtils.isNotEmpty(script), "script must not be null or empty"); + checkArgument(separator != null, "separator must not be null"); + checkArgument(StringUtils.isNotEmpty(commentPrefix), "commentPrefix must not be null or empty"); + checkArgument( + StringUtils.isNotEmpty(blockCommentStartDelimiter), + "blockCommentStartDelimiter must not be null or empty" + ); + checkArgument( + StringUtils.isNotEmpty(blockCommentEndDelimiter), + "blockCommentEndDelimiter must not be null or empty" + ); + + StringBuilder sb = new StringBuilder(); + boolean inEscape = false; + boolean inLineComment = false; + boolean inBlockComment = false; + Character currentLiteralDelimiter = null; + + int compoundStatementDepth = 0; + final String lowerCaseScriptContent = script.toLowerCase(); + char[] content = script.toCharArray(); + for (int i = 0; i < script.length(); i++) { + char c = content[i]; + if (inEscape) { + inEscape = false; + sb.append(c); + continue; + } + // MySQL style escapes + if (c == '\\') { + inEscape = true; + sb.append(c); + continue; + } + // Determine whether we're entering/leaving a string literal + if (!inBlockComment && !inLineComment && (c == '\'' || c == '"' || c == '`')) { + if (currentLiteralDelimiter == null) { // ignore delimiters within an existing string literal + currentLiteralDelimiter = c; + } else if (currentLiteralDelimiter == c) { // find end of string literal + currentLiteralDelimiter = null; + } + } + final boolean inLiteral = currentLiteralDelimiter != null; + + if (!inLiteral && containsSubstringAtOffset(lowerCaseScriptContent, commentPrefix, i)) { + inLineComment = true; + } + if (inLineComment && c == '\n') { + inLineComment = false; + } + if (!inLiteral && containsSubstringAtOffset(lowerCaseScriptContent, blockCommentStartDelimiter, i)) { + inBlockComment = true; + } + if ( + !inLiteral && + inBlockComment && + containsSubstringAtOffset(lowerCaseScriptContent, blockCommentEndDelimiter, i) + ) { + inBlockComment = false; + } + final boolean inComment = inLineComment || inBlockComment; + + if ( + !inLiteral && + !inComment && + containsKeywordsAtOffset( + lowerCaseScriptContent, + "BEGIN", + i, + separator, + commentPrefix, + blockCommentStartDelimiter + ) + ) { + compoundStatementDepth++; + } + if ( + !inLiteral && + !inComment && + containsKeywordsAtOffset( + lowerCaseScriptContent, + "END", + i, + separator, + commentPrefix, + blockCommentStartDelimiter + ) + ) { + compoundStatementDepth--; + } + final boolean inCompoundStatement = compoundStatementDepth != 0; + + if (!inLiteral && !inCompoundStatement) { + if (script.startsWith(separator, i)) { + // we've reached the end of the current statement + sb = flushStringBuilder(sb, statements); + i += separator.length() - 1; + continue; + } else if (script.startsWith(commentPrefix, i)) { + // skip over any content from the start of the comment to the EOL + int indexOfNextNewline = script.indexOf("\n", i); + if (indexOfNextNewline > i) { + i = indexOfNextNewline; + continue; + } else { + // if there's no EOL, we must be at the end + // of the script, so stop here. + break; + } + } else if (script.startsWith(blockCommentStartDelimiter, i)) { + // skip over any block comments + int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); + if (indexOfCommentEnd > i) { + i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; inBlockComment = false; - continue; - } - else { - throw new ScriptParseException(String.format("Missing block comment end delimiter [%s].", - blockCommentEndDelimiter), resource); - } - } - else if (c == ' ' || c == '\n' || c == '\t' || c == '\r') { - // avoid multiple adjacent whitespace characters - if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') { - c = ' '; - } - else { - continue; - } - } - } - sb.append(c); - } - flushStringBuilder(sb, statements); - } - - private static StringBuilder flushStringBuilder(StringBuilder sb, List statements) { - if (sb.length() == 0) { - return sb; - } - - final String s = sb.toString().trim(); - if (StringUtils.isNotEmpty(s)) { - statements.add(s); - } - - return new StringBuilder(); - } - - private static boolean isSeperator(char c, String separator, String commentPrefix, - String blockCommentStartDelimiter) { - return c == ' ' || c == '\r' || c == '\n' || c == '\t' || - c == separator.charAt(0) || c == separator.charAt(separator.length() - 1) || - c == commentPrefix.charAt(0) || c == blockCommentStartDelimiter.charAt(0) || - c == blockCommentStartDelimiter.charAt(blockCommentStartDelimiter.length() - 1); + continue; + } else { + throw new ScriptParseException( + String.format("Missing block comment end delimiter [%s].", blockCommentEndDelimiter), + resource + ); + } + } else if (c == ' ' || c == '\n' || c == '\t' || c == '\r') { + // avoid multiple adjacent whitespace characters + if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') { + c = ' '; + } else { + continue; + } + } + } + sb.append(c); + } + flushStringBuilder(sb, statements); + } + + private static StringBuilder flushStringBuilder(StringBuilder sb, List statements) { + if (sb.length() == 0) { + return sb; + } + + final String s = sb.toString().trim(); + if (StringUtils.isNotEmpty(s)) { + statements.add(s); + } + + return new StringBuilder(); } - private static boolean containsSubstringAtOffset(String lowercaseString, String substring, int offset) { - String lowercaseSubstring = substring.toLowerCase(); + private static boolean isSeperator( + char c, + String separator, + String commentPrefix, + String blockCommentStartDelimiter + ) { + return ( + c == ' ' || + c == '\r' || + c == '\n' || + c == '\t' || + c == separator.charAt(0) || + c == separator.charAt(separator.length() - 1) || + c == commentPrefix.charAt(0) || + c == blockCommentStartDelimiter.charAt(0) || + c == blockCommentStartDelimiter.charAt(blockCommentStartDelimiter.length() - 1) + ); + } - return lowercaseString.startsWith(lowercaseSubstring, offset); - } + private static boolean containsSubstringAtOffset(String lowercaseString, String substring, int offset) { + String lowercaseSubstring = substring.toLowerCase(); - private static boolean containsKeywordsAtOffset(String lowercaseString, String keywords, int offset, - String separator, String commentPrefix, - String blockCommentStartDelimiter) { + return lowercaseString.startsWith(lowercaseSubstring, offset); + } + + private static boolean containsKeywordsAtOffset( + String lowercaseString, + String keywords, + int offset, + String separator, + String commentPrefix, + String blockCommentStartDelimiter + ) { String lowercaseKeywords = keywords.toLowerCase(); - boolean backSeperated = (offset == 0) || isSeperator(lowercaseString.charAt(offset - 1), - separator, commentPrefix, blockCommentStartDelimiter); - boolean frontSeperated = (offset >= (lowercaseString.length() - keywords.length())) || - isSeperator(lowercaseString.charAt(offset + keywords.length()), - separator, commentPrefix, blockCommentStartDelimiter); + boolean backSeperated = + (offset == 0) || + isSeperator(lowercaseString.charAt(offset - 1), separator, commentPrefix, blockCommentStartDelimiter); + boolean frontSeperated = + (offset >= (lowercaseString.length() - keywords.length())) || + isSeperator( + lowercaseString.charAt(offset + keywords.length()), + separator, + commentPrefix, + blockCommentStartDelimiter + ); return backSeperated && frontSeperated && lowercaseString.startsWith(lowercaseKeywords, offset); } - private static void checkArgument(boolean expression, String errorMessage) { - if (!expression) { - throw new IllegalArgumentException(errorMessage); - } - } - - /** - * Does the provided SQL script contain the specified delimiter? - * @param script the SQL script - * @param delim String delimiting each statement - typically a ';' character - */ - public static boolean containsSqlScriptDelimiters(String script, String delim) { - boolean inLiteral = false; - char[] content = script.toCharArray(); - for (int i = 0; i < script.length(); i++) { - if (content[i] == '\'') { - inLiteral = !inLiteral; - } - if (!inLiteral && script.startsWith(delim, i)) { - return true; - } - } - return false; - } - - /** - * Load script from classpath and apply it to the given database - * - * @param databaseDelegate database delegate for script execution - * @param initScriptPath the resource to load the init script from - */ - public static void runInitScript(DatabaseDelegate databaseDelegate, String initScriptPath) { - try { - URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath); - if (resource == null) { - resource = ScriptUtils.class.getClassLoader().getResource(initScriptPath); - if (resource == null) { - LOGGER.warn("Could not load classpath init script: {}", initScriptPath); - throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath + ". Resource not found."); - } - } - String scripts = IOUtils.toString(resource, StandardCharsets.UTF_8); - executeDatabaseScript(databaseDelegate, initScriptPath, scripts); - } catch (IOException e) { - LOGGER.warn("Could not load classpath init script: {}", initScriptPath); - throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath, e); - } catch (ScriptException e) { - LOGGER.error("Error while executing init script: {}", initScriptPath, e); - throw new UncategorizedScriptException("Error while executing init script: " + initScriptPath, e); - } - } - - public static void executeDatabaseScript(DatabaseDelegate databaseDelegate, String scriptPath, String script) throws ScriptException { - executeDatabaseScript(databaseDelegate, scriptPath, script, false, false, DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + private static void checkArgument(boolean expression, String errorMessage) { + if (!expression) { + throw new IllegalArgumentException(errorMessage); + } + } + + /** + * Does the provided SQL script contain the specified delimiter? + * @param script the SQL script + * @param delim String delimiting each statement - typically a ';' character + */ + public static boolean containsSqlScriptDelimiters(String script, String delim) { + boolean inLiteral = false; + char[] content = script.toCharArray(); + for (int i = 0; i < script.length(); i++) { + if (content[i] == '\'') { + inLiteral = !inLiteral; + } + if (!inLiteral && script.startsWith(delim, i)) { + return true; + } + } + return false; + } + + /** + * Load script from classpath and apply it to the given database + * + * @param databaseDelegate database delegate for script execution + * @param initScriptPath the resource to load the init script from + */ + public static void runInitScript(DatabaseDelegate databaseDelegate, String initScriptPath) { + try { + URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath); + if (resource == null) { + resource = ScriptUtils.class.getClassLoader().getResource(initScriptPath); + if (resource == null) { + LOGGER.warn("Could not load classpath init script: {}", initScriptPath); + throw new ScriptLoadException( + "Could not load classpath init script: " + initScriptPath + ". Resource not found." + ); + } + } + String scripts = IOUtils.toString(resource, StandardCharsets.UTF_8); + executeDatabaseScript(databaseDelegate, initScriptPath, scripts); + } catch (IOException e) { + LOGGER.warn("Could not load classpath init script: {}", initScriptPath); + throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath, e); + } catch (ScriptException e) { + LOGGER.error("Error while executing init script: {}", initScriptPath, e); + throw new UncategorizedScriptException("Error while executing init script: " + initScriptPath, e); + } + } + + public static void executeDatabaseScript(DatabaseDelegate databaseDelegate, String scriptPath, String script) + throws ScriptException { + executeDatabaseScript( + databaseDelegate, + scriptPath, + script, + false, + false, + DEFAULT_COMMENT_PREFIX, + DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, + DEFAULT_BLOCK_COMMENT_END_DELIMITER + ); } /** - * Execute the given database script. - *

Statement separators and comments will be removed before executing - * individual statements within the supplied script. + * Execute the given database script. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. *

Do not use this method to execute DDL if you expect rollback. * @param databaseDelegate database delegate for script execution * @param scriptPath the resource (potentially associated with a specific encoding) @@ -328,85 +397,104 @@ public static void executeDatabaseScript(DatabaseDelegate databaseDelegate, Stri *@param continueOnError whether or not to continue without throwing an exception * in the event of an error * @param ignoreFailedDrops whether or not to continue in the event of specifically -* an error on a {@code DROP} statement + * an error on a {@code DROP} statement * @param commentPrefix the prefix that identifies comments in the SQL script — -* typically "--" + * typically "--" * @param separator the script statement separator; defaults to -* {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to -* {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort + * {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to + * {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort * @param blockCommentStartDelimiter the start block comment delimiter; never -* {@code null} or empty + * {@code null} or empty * @param blockCommentEndDelimiter the end block comment delimiter; never -* {@code null} or empty @throws ScriptException if an error occurred while executing the SQL script - */ - public static void executeDatabaseScript(DatabaseDelegate databaseDelegate, String scriptPath, String script, boolean continueOnError, - boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter, - String blockCommentEndDelimiter) throws ScriptException { - - try { - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Executing database script from " + scriptPath); - } - - long startTime = System.currentTimeMillis(); - List statements = new LinkedList<>(); - - if (separator == null) { - separator = DEFAULT_STATEMENT_SEPARATOR; - } - if (!containsSqlScriptDelimiters(script, separator)) { - separator = FALLBACK_STATEMENT_SEPARATOR; - } - - splitSqlScript(scriptPath, script, separator, commentPrefix, blockCommentStartDelimiter, - blockCommentEndDelimiter, statements); - - try (DatabaseDelegate closeableDelegate = databaseDelegate) { - closeableDelegate.execute(statements, scriptPath, continueOnError, ignoreFailedDrops); - } - - long elapsedTime = System.currentTimeMillis() - startTime; - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Executed database script from " + scriptPath + " in " + elapsedTime + " ms."); - } - } - catch (Exception ex) { - if (ex instanceof ScriptException) { - throw (ScriptException) ex; - } - - throw new UncategorizedScriptException( - "Failed to execute database script from resource [" + script + "]", ex); - } - } - - public static class ScriptLoadException extends RuntimeException { - public ScriptLoadException(String message) { - super(message); - } - - public ScriptLoadException(String message, Throwable cause) { - super(message, cause); - } - } - - public static class ScriptParseException extends RuntimeException { - public ScriptParseException(String format, String scriptPath) { - super(String.format(format, scriptPath)); - } - } - - public static class ScriptStatementFailedException extends RuntimeException { - public ScriptStatementFailedException(String statement, int lineNumber, String scriptPath) { - this(statement, lineNumber, scriptPath, null); - } - - public ScriptStatementFailedException(String statement, int lineNumber, String scriptPath, Exception ex) { - super(String.format("Script execution failed (%s:%d): %s", scriptPath, lineNumber, statement), ex); - } - } + * {@code null} or empty @throws ScriptException if an error occurred while executing the SQL script + */ + public static void executeDatabaseScript( + DatabaseDelegate databaseDelegate, + String scriptPath, + String script, + boolean continueOnError, + boolean ignoreFailedDrops, + String commentPrefix, + String separator, + String blockCommentStartDelimiter, + String blockCommentEndDelimiter + ) throws ScriptException { + try { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Executing database script from " + scriptPath); + } + + long startTime = System.currentTimeMillis(); + List statements = new LinkedList<>(); + + if (separator == null) { + separator = DEFAULT_STATEMENT_SEPARATOR; + } + if (!containsSqlScriptDelimiters(script, separator)) { + separator = FALLBACK_STATEMENT_SEPARATOR; + } + + splitSqlScript( + scriptPath, + script, + separator, + commentPrefix, + blockCommentStartDelimiter, + blockCommentEndDelimiter, + statements + ); + + try (DatabaseDelegate closeableDelegate = databaseDelegate) { + closeableDelegate.execute(statements, scriptPath, continueOnError, ignoreFailedDrops); + } + + long elapsedTime = System.currentTimeMillis() - startTime; + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Executed database script from " + scriptPath + " in " + elapsedTime + " ms."); + } + } catch (Exception ex) { + if (ex instanceof ScriptException) { + throw (ScriptException) ex; + } + + throw new UncategorizedScriptException( + "Failed to execute database script from resource [" + script + "]", + ex + ); + } + } + + public static class ScriptLoadException extends RuntimeException { + + public ScriptLoadException(String message) { + super(message); + } + + public ScriptLoadException(String message, Throwable cause) { + super(message, cause); + } + } + + public static class ScriptParseException extends RuntimeException { + + public ScriptParseException(String format, String scriptPath) { + super(String.format(format, scriptPath)); + } + } + + public static class ScriptStatementFailedException extends RuntimeException { + + public ScriptStatementFailedException(String statement, int lineNumber, String scriptPath) { + this(statement, lineNumber, scriptPath, null); + } + + public ScriptStatementFailedException(String statement, int lineNumber, String scriptPath, Exception ex) { + super(String.format("Script execution failed (%s:%d): %s", scriptPath, lineNumber, statement), ex); + } + } public static class UncategorizedScriptException extends RuntimeException { + public UncategorizedScriptException(String s, Exception ex) { super(s, ex); } diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java index 202a3b995db..bc9476cc83d 100644 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java @@ -4,11 +4,10 @@ import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import static java.util.Arrays.asList; import static org.junit.Assert.fail; -import static org.testcontainers.ext.ScriptUtils.*; public class ScriptSplittingTest { @@ -16,18 +15,15 @@ public class ScriptSplittingTest { public void testStringDemarcation() { String script = "SELECT 'foo `bar`'; SELECT 'foo -- `bar`'; SELECT 'foo /* `bar`';"; - List expected = asList( - "SELECT 'foo `bar`'", - "SELECT 'foo -- `bar`'", - "SELECT 'foo /* `bar`'" - ); + List expected = Arrays.asList("SELECT 'foo `bar`'", "SELECT 'foo -- `bar`'", "SELECT 'foo /* `bar`'"); splitAndCompare(script, expected); } @Test public void testIssue1547Case1() { - String script = "create database if not exists ttt;\n" + + String script = + "create database if not exists ttt;\n" + "\n" + "use ttt;\n" + "\n" + @@ -43,7 +39,7 @@ public void testIssue1547Case1() { " id bigint auto_increment primary key\n" + ") comment 'bbb';"; - List expected = asList( + List expected = Arrays.asList( "create database if not exists ttt", "use ttt", "create table aaa ( id bigint auto_increment primary key, end_time datetime null COMMENT 'end_time', data_status varchar(16) not null ) comment 'aaa'", @@ -55,14 +51,15 @@ public void testIssue1547Case1() { @Test public void testIssue1547Case2() { - String script = "CREATE TABLE bar (\n" + + String script = + "CREATE TABLE bar (\n" + " end_time VARCHAR(255)\n" + ");\n" + "CREATE TABLE bar (\n" + " end_time VARCHAR(255)\n" + ");"; - List expected = asList( + List expected = Arrays.asList( "CREATE TABLE bar ( end_time VARCHAR(255) )", "CREATE TABLE bar ( end_time VARCHAR(255) )" ); @@ -74,25 +71,17 @@ public void testIssue1547Case2() { public void testUnusualSemicolonPlacement() { String script = "SELECT 1;;;;;SELECT 2;\n;SELECT 3\n; SELECT 4;\n SELECT 5"; - List expected = asList( - "SELECT 1", - "SELECT 2", - "SELECT 3", - "SELECT 4", - "SELECT 5" - ); + List expected = Arrays.asList("SELECT 1", "SELECT 2", "SELECT 3", "SELECT 4", "SELECT 5"); splitAndCompare(script, expected); } @Test public void testCommentedSemicolon() { - String script = "CREATE TABLE bar (\n" + - " foo VARCHAR(255)\n" + - "); \nDROP PROCEDURE IF EXISTS -- ;\n" + - " count_foo"; + String script = + "CREATE TABLE bar (\n" + " foo VARCHAR(255)\n" + "); \nDROP PROCEDURE IF EXISTS -- ;\n" + " count_foo"; - List expected = asList( + List expected = Arrays.asList( "CREATE TABLE bar ( foo VARCHAR(255) )", "DROP PROCEDURE IF EXISTS count_foo" ); @@ -102,11 +91,12 @@ public void testCommentedSemicolon() { @Test public void testStringEscaping() { - String script = "SELECT \"a /* string literal containing comment characters like -- here\";\n" + + String script = + "SELECT \"a /* string literal containing comment characters like -- here\";\n" + "SELECT \"a 'quoting' \\\"scenario ` involving BEGIN keyword\\\" here\";\n" + "SELECT * from `bar`;"; - List expected = asList( + List expected = Arrays.asList( "SELECT \"a /* string literal containing comment characters like -- here\"", "SELECT \"a 'quoting' \\\"scenario ` involving BEGIN keyword\\\" here\"", "SELECT * from `bar`" @@ -119,18 +109,17 @@ public void testStringEscaping() { public void testBlockCommentExclusion() { String script = "INSERT INTO bar (foo) /* ; */ VALUES ('hello world');"; - List expected = asList( - "INSERT INTO bar (foo) VALUES ('hello world')" - ); + List expected = Arrays.asList("INSERT INTO bar (foo) VALUES ('hello world')"); splitAndCompare(script, expected); } @Test public void testBeginEndKeywordCorrectDetection() { - String script = "INSERT INTO something_end (begin_with_the_token, another_field) /*end*/ VALUES /* end */ (' begin ', `end`)-- begin\n;"; + String script = + "INSERT INTO something_end (begin_with_the_token, another_field) /*end*/ VALUES /* end */ (' begin ', `end`)-- begin\n;"; - List expected = asList( + List expected = Arrays.asList( "INSERT INTO something_end (begin_with_the_token, another_field) VALUES (' begin ', `end`)" ); @@ -139,16 +128,17 @@ public void testBeginEndKeywordCorrectDetection() { @Test public void testCommentInStrings() { - String script = "CREATE TABLE bar (foo VARCHAR(255));\n" + + String script = + "CREATE TABLE bar (foo VARCHAR(255));\n" + "\n" + "/* Insert Values */\n" + "INSERT INTO bar (foo) values ('--1');\n" + "INSERT INTO bar (foo) values ('--2');\n" + "INSERT INTO bar (foo) values ('/* something */');\n" + - "/* INSERT INTO bar (foo) values (' */'); -- '*/;\n" + // purposefully broken, to see if it breaks our splitting + "/* INSERT INTO bar (foo) values (' */'); -- '*/;\n" + // purposefully broken, to see if it breaks our splitting "INSERT INTO bar (foo) values ('foo');"; - List expected = asList( + List expected = Arrays.asList( "CREATE TABLE bar (foo VARCHAR(255))", "INSERT INTO bar (foo) values ('--1')", "INSERT INTO bar (foo) values ('--2')", @@ -162,7 +152,8 @@ public void testCommentInStrings() { @Test public void testMultipleBeginEndDetection() { - String script = "CREATE TABLE bar (foo VARCHAR(255));\n" + + String script = + "CREATE TABLE bar (foo VARCHAR(255));\n" + "\n" + "CREATE TABLE gender (gender VARCHAR(255));\n" + "CREATE TABLE ending (ending VARCHAR(255));\n" + @@ -187,24 +178,16 @@ public void testMultipleBeginEndDetection() { "\n" + "CREATE TABLE foo (bar VARCHAR(255));"; - List expected = asList( + List expected = Arrays.asList( "CREATE TABLE bar (foo VARCHAR(255))", "CREATE TABLE gender (gender VARCHAR(255))", "CREATE TABLE ending (ending VARCHAR(255))", "CREATE TABLE end2 (end2 VARCHAR(255))", "CREATE TABLE end_2 (end2 VARCHAR(255))", - "BEGIN\n" + - " INSERT INTO ending values ('ending');\n" + - "END", - "BEGIN\n" + - " INSERT INTO ending values ('ending');\n" + - "END", - "BEGIN--Hello\n" + - " INSERT INTO ending values ('ending');\n" + - "END", - "BEGIN\n" + - " INSERT INTO ending values ('ending');\n" + - "END", + "BEGIN\n" + " INSERT INTO ending values ('ending');\n" + "END", + "BEGIN\n" + " INSERT INTO ending values ('ending');\n" + "END", + "BEGIN--Hello\n" + " INSERT INTO ending values ('ending');\n" + "END", + "BEGIN\n" + " INSERT INTO ending values ('ending');\n" + "END", "CREATE TABLE foo (bar VARCHAR(255))" ); @@ -213,7 +196,8 @@ public void testMultipleBeginEndDetection() { @Test public void testProcedureBlock() { - String script = "CREATE PROCEDURE count_foo()\n" + + String script = + "CREATE PROCEDURE count_foo()\n" + " BEGIN\n" + "\n" + " BEGIN\n" + @@ -239,31 +223,31 @@ public void testProcedureBlock() { "\n" + " END /*; */;"; - List expected = asList( + List expected = Arrays.asList( "CREATE PROCEDURE count_foo() BEGIN\n" + - "\n" + - " BEGIN\n" + - " SELECT *\n" + - " FROM bar;\n" + - " SELECT 1\n" + - " FROM dual;\n" + - " END;\n" + - "\n" + - " BEGIN\n" + - " select * from bar;\n" + - " END;\n" + - "\n" + - " -- we can do comments\n" + - "\n" + - " /* including block\n" + - " comments\n" + - " */\n" + - "\n" + - " /* what if BEGIN appears inside a comment? */\n" + - "\n" + - " select \"or what if BEGIN appears inside a literal?\";\n" + - "\n" + - " END" + "\n" + + " BEGIN\n" + + " SELECT *\n" + + " FROM bar;\n" + + " SELECT 1\n" + + " FROM dual;\n" + + " END;\n" + + "\n" + + " BEGIN\n" + + " select * from bar;\n" + + " END;\n" + + "\n" + + " -- we can do comments\n" + + "\n" + + " /* including block\n" + + " comments\n" + + " */\n" + + "\n" + + " /* what if BEGIN appears inside a comment? */\n" + + "\n" + + " select \"or what if BEGIN appears inside a literal?\";\n" + + "\n" + + " END" ); splitAndCompare(script, expected); @@ -283,12 +267,13 @@ public void testUnclosedBlockComment() { @Test public void testIssue1452Case() { - String script = "create table test (text VARCHAR(255));\n" + + String script = + "create table test (text VARCHAR(255));\n" + "\n" + "/* some comment */\n" + "insert into `test` (`text`) values ('a b');"; - List expected = asList( + List expected = Arrays.asList( "create table test (text VARCHAR(255))", "insert into `test` (`text`) values ('a b')" ); @@ -303,7 +288,15 @@ private void splitAndCompare(String script, List expected) { private List doSplit(String script) { final List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript("ignored", script, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_COMMENT_PREFIX, DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements); + ScriptUtils.splitSqlScript( + "ignored", + script, + ScriptUtils.DEFAULT_STATEMENT_SEPARATOR, + ScriptUtils.DEFAULT_COMMENT_PREFIX, + ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, + ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER, + statements + ); return statements; } } diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index c1a252936ea..29e2ce8aa07 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -20,10 +20,13 @@ public class Db2Container extends JdbcDatabaseContainer { @Deprecated public static final String DEFAULT_TAG = "11.5.0.0a"; + public static final int DB2_PORT = 50000; private String databaseName = "test"; + private String username = "db2inst1"; + private String password = "foobar1234"; /** @@ -40,11 +43,11 @@ public Db2Container(String dockerImageName) { public Db2Container(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withPrivilegedMode(true); - this.waitStrategy = new LogMessageWaitStrategy() + this.waitStrategy = + new LogMessageWaitStrategy() .withRegEx(".*Setup has completed\\..*") .withStartupTimeout(Duration.of(10, ChronoUnit.MINUTES)); @@ -69,10 +72,12 @@ protected void configure() { addEnv("DB2INST1_PASSWORD", password); // These settings help the DB2 container start faster - if (!getEnvMap().containsKey("AUTOCONFIG")) + if (!getEnvMap().containsKey("AUTOCONFIG")) { addEnv("AUTOCONFIG", "false"); - if (!getEnvMap().containsKey("ARCHIVE_LOGS")) + } + if (!getEnvMap().containsKey("ARCHIVE_LOGS")) { addEnv("ARCHIVE_LOGS", "false"); + } } /** @@ -92,8 +97,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { String additionalUrlParams = constructUrlParameters(":", ";", ";"); - return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + - "/" + databaseName + additionalUrlParams; + return "jdbc:db2://" + getHost() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java index 618b97c3ca6..42ac21f271b 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2ContainerProvider.java @@ -3,6 +3,7 @@ import org.testcontainers.utility.DockerImageName; public class Db2ContainerProvider extends JdbcDatabaseContainerProvider { + @Override public boolean supports(String databaseType) { return databaseType.equals(Db2Container.NAME); diff --git a/modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java b/modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java index 2c87a4a1a65..4a03f824a28 100644 --- a/modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java +++ b/modules/db2/src/test/java/org/testcontainers/jdbc/db2/DB2JDBCDriverTest.java @@ -4,18 +4,18 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class DB2JDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)} - }); + return Arrays.asList( + new Object[][] { // + { "jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class) }, + } + ); } } diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java index b7a1d5478e8..8f3489eae95 100644 --- a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -1,24 +1,22 @@ package org.testcontainers.junit.db2; import org.junit.Test; +import org.testcontainers.Db2TestImages; import org.testcontainers.containers.Db2Container; import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.Db2TestImages.DB2_IMAGE; public class SimpleDb2Test extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (Db2Container db2 = new Db2Container(DB2_IMAGE) - .acceptLicense()) { - + try (Db2Container db2 = new Db2Container(Db2TestImages.DB2_IMAGE).acceptLicense()) { db2.start(); ResultSet resultSet = performQuery(db2, "SELECT 1 FROM SYSIBM.SYSDUMMY1"); @@ -30,10 +28,11 @@ public void testSimple() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - try (Db2Container db2 = new Db2Container(DB2_IMAGE) - .withUrlParam("sslConnection", "false") - .acceptLicense()) { - + try ( + Db2Container db2 = new Db2Container(Db2TestImages.DB2_IMAGE) + .withUrlParam("sslConnection", "false") + .acceptLicense() + ) { db2.start(); String jdbcUrl = db2.getJdbcUrl(); diff --git a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java index 8900964a8bb..401fa8782b1 100644 --- a/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java +++ b/modules/dynalite/src/main/java/org/testcontainers/dynamodb/DynaliteContainer.java @@ -15,7 +15,9 @@ public class DynaliteContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("quay.io/testcontainers/dynalite"); + private static final String DEFAULT_TAG = "v1.2.1-1"; + private static final int MAPPED_PORT = 4567; /** @@ -32,13 +34,11 @@ public DynaliteContainer(String dockerImageName) { public DynaliteContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(MAPPED_PORT); } - /** * Gets a preconfigured {@link AmazonDynamoDB} client object for connecting to this * container. @@ -46,10 +46,11 @@ public DynaliteContainer(final DockerImageName dockerImageName) { * @return preconfigured client */ public AmazonDynamoDB getClient() { - return AmazonDynamoDBClientBuilder.standard() - .withEndpointConfiguration(getEndpointConfiguration()) - .withCredentials(getCredentials()) - .build(); + return AmazonDynamoDBClientBuilder + .standard() + .withEndpointConfiguration(getEndpointConfiguration()) + .withCredentials(getCredentials()) + .build(); } /** @@ -59,9 +60,10 @@ public AmazonDynamoDB getClient() { * @return endpoint configuration */ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration() { - return new AwsClientBuilder.EndpointConfiguration("http://" + - this.getHost() + ":" + - this.getMappedPort(MAPPED_PORT), null); + return new AwsClientBuilder.EndpointConfiguration( + "http://" + this.getHost() + ":" + this.getMappedPort(MAPPED_PORT), + null + ); } /** @@ -72,6 +74,4 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration() { public AWSCredentialsProvider getCredentials() { return new AWSStaticCredentialsProvider(new BasicAWSCredentials("dummy", "dummy")); } - - } diff --git a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java index 0b440939139..ced5931de31 100644 --- a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java +++ b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java @@ -18,17 +18,20 @@ public class DynaliteContainerTest { - private static final DockerImageName DYNALITE_IMAGE = DockerImageName.parse("quay.io/testcontainers/dynalite:v1.2.1-1"); + private static final DockerImageName DYNALITE_IMAGE = DockerImageName.parse( + "quay.io/testcontainers/dynalite:v1.2.1-1" + ); @Rule public DynaliteContainer dynamoDB = new DynaliteContainer(DYNALITE_IMAGE); @Test public void simpleTestWithManualClientCreation() { - final AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard() - .withEndpointConfiguration(dynamoDB.getEndpointConfiguration()) - .withCredentials(dynamoDB.getCredentials()) - .build(); + final AmazonDynamoDB client = AmazonDynamoDBClientBuilder + .standard() + .withEndpointConfiguration(dynamoDB.getEndpointConfiguration()) + .withCredentials(dynamoDB.getCredentials()) + .build(); runTest(client); } @@ -42,13 +45,10 @@ public void simpleTestWithProvidedClient() { private void runTest(AmazonDynamoDB client) { CreateTableRequest request = new CreateTableRequest() - .withAttributeDefinitions(new AttributeDefinition( - "Name", ScalarAttributeType.S)) - .withKeySchema(new KeySchemaElement("Name", KeyType.HASH)) - .withProvisionedThroughput(new ProvisionedThroughput( - 10L, 10L)) - .withTableName("foo"); - + .withAttributeDefinitions(new AttributeDefinition("Name", ScalarAttributeType.S)) + .withKeySchema(new KeySchemaElement("Name", KeyType.HASH)) + .withProvisionedThroughput(new ProvisionedThroughput(10L, 10L)) + .withTableName("foo"); client.createTable(request); @@ -56,6 +56,10 @@ private void runTest(AmazonDynamoDB client) { assertNotNull("the description is not null", tableDescription); assertEquals("the table has the right name", "foo", tableDescription.getTableName()); - assertEquals("the name has the right primary key", "Name", tableDescription.getKeySchema().get(0).getAttributeName()); + assertEquals( + "the name has the right primary key", + "Name", + tableDescription.getKeySchema().get(0).getAttributeName() + ); } } diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index ac0b367f403..5a64a5e67a2 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -11,8 +11,6 @@ import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; import java.io.ByteArrayInputStream; import java.net.InetSocketAddress; import java.security.KeyStore; @@ -20,6 +18,9 @@ import java.security.cert.CertificateFactory; import java.util.Optional; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + /** * Represents an elasticsearch docker instance which exposes by default port 9200 and 9300 (transport.tcp.port) * The docker image is by default fetched from docker.elastic.co/elasticsearch/elasticsearch @@ -47,8 +48,13 @@ public class ElasticsearchContainer extends GenericContainer caCertAsBytes = Optional.empty(); + private String certPath = "/usr/share/elasticsearch/config/certs/http_ca.crt"; /** @@ -83,7 +92,6 @@ public ElasticsearchContainer(String dockerImageName) { */ public ElasticsearchContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, DEFAULT_OSS_IMAGE_NAME); this.isOss = dockerImageName.isCompatibleWith(DEFAULT_OSS_IMAGE_NAME); @@ -91,7 +99,8 @@ public ElasticsearchContainer(final DockerImageName dockerImageName) { withNetworkAliases("elasticsearch-" + Base58.randomString(6)); withEnv("discovery.type", "single-node"); addExposedPorts(ELASTICSEARCH_DEFAULT_PORT, ELASTICSEARCH_DEFAULT_TCP_PORT); - this.isAtLeastMajorVersion8 = new ComparableVersion(dockerImageName.getVersionPart()).isGreaterThanOrEqualTo("8.0.0"); + this.isAtLeastMajorVersion8 = + new ComparableVersion(dockerImageName.getVersionPart()).isGreaterThanOrEqualTo("8.0.0"); // regex that // matches 8.0 JSON logging with no whitespace between message field and content // matches 7.x JSON logging with whitespace between message field and content @@ -159,8 +168,9 @@ public SSLContext createSslContextFromCa() { */ public ElasticsearchContainer withPassword(String password) { if (isOss) { - throw new IllegalArgumentException("You can not activate security on Elastic OSS Image. " + - "Please switch to the default distribution"); + throw new IllegalArgumentException( + "You can not activate security on Elastic OSS Image. " + "Please switch to the default distribution" + ); } withEnv("ELASTIC_PASSWORD", password); if (!isAtLeastMajorVersion8) { diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 5b6b5ce3194..4427163ca56 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -25,12 +25,13 @@ import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; -import javax.net.ssl.SSLHandshakeException; import java.io.IOException; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; +import javax.net.ssl.SSLHandshakeException; + import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; public class ElasticsearchContainerTest { @@ -39,10 +40,10 @@ public class ElasticsearchContainerTest { * Elasticsearch version which should be used for the Tests */ private static final String ELASTICSEARCH_VERSION = "7.9.2"; - private static final DockerImageName ELASTICSEARCH_IMAGE = - DockerImageName - .parse("docker.elastic.co/elasticsearch/elasticsearch") - .withTag(ELASTICSEARCH_VERSION); + + private static final DockerImageName ELASTICSEARCH_IMAGE = DockerImageName + .parse("docker.elastic.co/elasticsearch/elasticsearch") + .withTag(ELASTICSEARCH_VERSION); /** * Elasticsearch default username, when secured @@ -55,6 +56,7 @@ public class ElasticsearchContainerTest { private static final String ELASTICSEARCH_PASSWORD = "changeme"; private RestClient client = null; + private RestClient anonymousClient = null; @After @@ -74,8 +76,8 @@ public void stopRestClient() throws IOException { @Deprecated // We will remove this test in the future public void elasticsearchDeprecatedCtorTest() throws IOException { // Create the elasticsearch container. - try (ElasticsearchContainer container = new ElasticsearchContainer() - .withEnv("foo", "bar") // dummy env for compiler checking correct generics usage + try ( + ElasticsearchContainer container = new ElasticsearchContainer().withEnv("foo", "bar") // dummy env for compiler checking correct generics usage ) { // Start the container. This step might take some time... container.start(); @@ -96,8 +98,8 @@ public void elasticsearchDeprecatedCtorTest() throws IOException { @Test public void elasticsearchDefaultTest() throws IOException { // Create the elasticsearch container. - try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) - .withEnv("foo", "bar") // dummy env for compiler checking correct generics usage + try ( + ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE).withEnv("foo", "bar") // dummy env for compiler checking correct generics usage ) { // Start the container. This step might take some time... container.start(); @@ -117,14 +119,18 @@ public void elasticsearchDefaultTest() throws IOException { @Test public void elasticsearchSecuredTest() throws IOException { - try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) - .withPassword(ELASTICSEARCH_PASSWORD)) { + try ( + ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) + .withPassword(ELASTICSEARCH_PASSWORD) + ) { container.start(); // The cluster should be secured so it must fail when we try to access / without credentials - assertThrows("We should not be able to access / URI with an anonymous client.", + assertThrows( + "We should not be able to access / URI with an anonymous client.", ResponseException.class, - () -> getAnonymousClient(container).performRequest(new Request("GET", "/"))); + () -> getAnonymousClient(container).performRequest(new Request("GET", "/")) + ); // But it should work when we try to access / with the proper login and password Response response = getClient(container).performRequest(new Request("GET", "/")); @@ -146,22 +152,24 @@ public void elasticsearchVersion() throws IOException { @Test public void elasticsearchOssImage() throws IOException { - try (ElasticsearchContainer container = - // ossContainer { - new ElasticsearchContainer( - DockerImageName - .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") - .withTag(ELASTICSEARCH_VERSION) - ) - // } + try ( + // ossContainer { + ElasticsearchContainer container = new ElasticsearchContainer( + DockerImageName + .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") + .withTag(ELASTICSEARCH_VERSION) + ) + // } ) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); assertThat(response.getStatusLine().getStatusCode(), is(200)); // The OSS image does not have any feature under Elastic License - assertThrows("We should not have /_xpack endpoint with an OSS License", + assertThrows( + "We should not have /_xpack endpoint with an OSS License", ResponseException.class, - () -> getClient(container).performRequest(new Request("GET", "/_xpack/"))); + () -> getClient(container).performRequest(new Request("GET", "/_xpack/")) + ); } } @@ -175,12 +183,18 @@ public void restClientClusterHealth() throws IOException { // Do whatever you want with the rest client ... final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(AuthScope.ANY, - new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)); - - client = RestClient.builder(HttpHost.create(container.getHttpHostAddress())) - .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)) - .build(); + credentialsProvider.setCredentials( + AuthScope.ANY, + new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD) + ); + + client = + RestClient + .builder(HttpHost.create(container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> { + return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + }) + .build(); Response response = client.performRequest(new Request("GET", "/_cluster/health")); // }} @@ -195,20 +209,28 @@ public void restClientClusterHealth() throws IOException { public void restClientSecuredClusterHealth() throws IOException { // httpClientSecuredContainer { // Create the elasticsearch container. - try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) - // With a password - .withPassword(ELASTICSEARCH_PASSWORD)) { + try ( + ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) + // With a password + .withPassword(ELASTICSEARCH_PASSWORD) + ) { // Start the container. This step might take some time... container.start(); // Create the secured client. final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(AuthScope.ANY, - new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)); - - client = RestClient.builder(HttpHost.create(container.getHttpHostAddress())) - .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)) - .build(); + credentialsProvider.setCredentials( + AuthScope.ANY, + new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD) + ); + + client = + RestClient + .builder(HttpHost.create(container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> { + return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + }) + .build(); Response response = client.performRequest(new Request("GET", "/_cluster/health")); // }} @@ -224,7 +246,7 @@ public void restClientSecuredClusterHealth() throws IOException { public void transportClientClusterHealth() { // transportClientContainer { // Create the elasticsearch container. - try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)){ + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)) { // Start the container. This step might take some time... container.start(); @@ -232,8 +254,10 @@ public void transportClientClusterHealth() { TransportAddress transportAddress = new TransportAddress(container.getTcpHost()); String expectedClusterName = "docker-cluster"; Settings settings = Settings.builder().put("cluster.name", expectedClusterName).build(); - try (TransportClient transportClient = new PreBuiltTransportClient(settings) - .addTransportAddress(transportAddress)) { + try ( + TransportClient transportClient = new PreBuiltTransportClient(settings) + .addTransportAddress(transportAddress) + ) { ClusterHealthResponse healths = transportClient.admin().cluster().prepareHealth().get(); String clusterName = healths.getClusterName(); // }}} @@ -247,19 +271,27 @@ public void transportClientClusterHealth() { @Test public void incompatibleSettingsTest() { // The OSS image can not use security feature - assertThrows("We should not be able to activate security with an OSS License", + assertThrows( + "We should not be able to activate security with an OSS License", IllegalArgumentException.class, - () -> new ElasticsearchContainer( - DockerImageName - .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") - .withTag(ELASTICSEARCH_VERSION)) - .withPassword("foo") + () -> { + new ElasticsearchContainer( + DockerImageName + .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") + .withTag(ELASTICSEARCH_VERSION) + ) + .withPassword("foo"); + } ); } @Test public void testElasticsearch8SecureByDefault() throws Exception { - try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.1.2")) { + try ( + ElasticsearchContainer container = new ElasticsearchContainer( + "docker.elastic.co/elasticsearch/elasticsearch:8.1.2" + ) + ) { // Start the container. This step might take some time... container.start(); @@ -273,29 +305,40 @@ public void testElasticsearch8SecureByDefault() throws Exception { public void testElasticsearch8SecureByDefaultCustomCaCertFails() throws Exception { final MountableFile mountableFile = MountableFile.forClasspathResource("http_ca.crt"); String caPath = "/tmp/http_ca.crt"; - try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.1.2") - .withCopyToContainer(mountableFile, caPath) - .withCertPath(caPath)) { - + try ( + ElasticsearchContainer container = new ElasticsearchContainer( + "docker.elastic.co/elasticsearch/elasticsearch:8.1.2" + ) + .withCopyToContainer(mountableFile, caPath) + .withCertPath(caPath) + ) { container.start(); // this is expected, as a different cert is used for creating the SSL context - assertThrows("PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors", SSLHandshakeException.class, () -> getClusterHealth(container)); + assertThrows( + "PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors", + SSLHandshakeException.class, + () -> getClusterHealth(container) + ); } } @Test public void testElasticsearch8SecureByDefaultHttpWaitStrategy() throws Exception { - final HttpWaitStrategy httpsWaitStrategy = Wait.forHttps("/") + final HttpWaitStrategy httpsWaitStrategy = Wait + .forHttps("/") .forPort(9200) .forStatusCode(200) .withBasicCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD) // trusting self-signed certificate .allowInsecure(); - try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.1.2") - .waitingFor(httpsWaitStrategy)) { - + try ( + ElasticsearchContainer container = new ElasticsearchContainer( + "docker.elastic.co/elasticsearch/elasticsearch:8.1.2" + ) + .waitingFor(httpsWaitStrategy) + ) { // Start the container. This step might take some time... container.start(); @@ -311,7 +354,9 @@ public void testElasticsearch8SecureByDefaultFailsSilentlyOnLatestImages() throw // even though the version might be older than version 8 // this tags an old 7.x version as :latest tagImage("docker.elastic.co/elasticsearch/elasticsearch:7.9.2", "elasticsearch-tc-older-release", "latest"); - DockerImageName image = DockerImageName.parse("elasticsearch-tc-older-release:latest").asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch"); + DockerImageName image = DockerImageName + .parse("elasticsearch-tc-older-release:latest") + .asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch"); try (ElasticsearchContainer container = new ElasticsearchContainer(image)) { container.start(); @@ -324,27 +369,31 @@ public void testElasticsearch8SecureByDefaultFailsSilentlyOnLatestImages() throw private void tagImage(String sourceImage, String targetImage, String targetTag) throws InterruptedException { DockerClient dockerClient = DockerClientFactory.instance().client(); - dockerClient.tagImageCmd( - new RemoteDockerImage(DockerImageName.parse(sourceImage)).get(), - targetImage, - targetTag - ) + dockerClient + .tagImageCmd(new RemoteDockerImage(DockerImageName.parse(sourceImage)).get(), targetImage, targetTag) .exec(); } private Response getClusterHealth(ElasticsearchContainer container) throws IOException { // Create the secured client. final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(AuthScope.ANY, - new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)); + credentialsProvider.setCredentials( + AuthScope.ANY, + new UsernamePasswordCredentials( + ELASTICSEARCH_USERNAME, + ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD + ) + ); - client = RestClient.builder(HttpHost.create("https://" + container.getHttpHostAddress())) - .setHttpClientConfigCallback(httpClientBuilder -> { - httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); - httpClientBuilder.setSSLContext(container.createSslContextFromCa()); - return httpClientBuilder; - }) - .build(); + client = + RestClient + .builder(HttpHost.create("https://" + container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> { + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + httpClientBuilder.setSSLContext(container.createSslContextFromCa()); + return httpClientBuilder; + }) + .build(); return client.performRequest(new Request("GET", "/_cluster/health")); } @@ -352,12 +401,18 @@ private Response getClusterHealth(ElasticsearchContainer container) throws IOExc private RestClient getClient(ElasticsearchContainer container) { if (client == null) { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(AuthScope.ANY, - new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)); - - client = RestClient.builder(HttpHost.create(container.getHttpHostAddress())) - .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)) - .build(); + credentialsProvider.setCredentials( + AuthScope.ANY, + new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD) + ); + + client = + RestClient + .builder(HttpHost.create(container.getHttpHostAddress())) + .setHttpClientConfigCallback(httpClientBuilder -> { + return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + }) + .build(); } return client; diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java index 4b81e3964ce..84515fc7244 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/BigtableEmulatorContainer.java @@ -13,19 +13,20 @@ */ public class BigtableEmulatorContainer extends GenericContainer { - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "gcr.io/google.com/cloudsdktool/cloud-sdk" + ); private static final String CMD = "gcloud beta emulators bigtable start --host-port 0.0.0.0:9000"; + private static final int PORT = 9000; public BigtableEmulatorContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(PORT); - setWaitStrategy(new LogMessageWaitStrategy() - .withRegEx("(?s).*running.*$")); + setWaitStrategy(new LogMessageWaitStrategy().withRegEx("(?s).*running.*$")); withCommand("/bin/sh", "-c", CMD); } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java index 58e5c023a0e..b0716829875 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java @@ -12,14 +12,17 @@ */ public class DatastoreEmulatorContainer extends GenericContainer { - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "gcr.io/google.com/cloudsdktool/cloud-sdk" + ); + + private static final String CMD = + "gcloud beta emulators datastore start --project test-project --host-port 0.0.0.0:8081"; - private static final String CMD = "gcloud beta emulators datastore start --project test-project --host-port 0.0.0.0:8081"; private static final int HTTP_PORT = 8081; public DatastoreEmulatorContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(HTTP_PORT); diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java index c36082dfeb6..a04c1e5831f 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/FirestoreEmulatorContainer.java @@ -12,19 +12,20 @@ */ public class FirestoreEmulatorContainer extends GenericContainer { - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "gcr.io/google.com/cloudsdktool/cloud-sdk" + ); private static final String CMD = "gcloud beta emulators firestore start --host-port 0.0.0.0:8080"; + private static final int PORT = 8080; public FirestoreEmulatorContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(PORT); - setWaitStrategy(new LogMessageWaitStrategy() - .withRegEx("(?s).*running.*$")); + setWaitStrategy(new LogMessageWaitStrategy().withRegEx("(?s).*running.*$")); withCommand("/bin/sh", "-c", CMD); } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java index 231f7626044..8d9f76e44ae 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/PubSubEmulatorContainer.java @@ -12,19 +12,20 @@ */ public class PubSubEmulatorContainer extends GenericContainer { - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk"); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "gcr.io/google.com/cloudsdktool/cloud-sdk" + ); private static final String CMD = "gcloud beta emulators pubsub start --host-port 0.0.0.0:8085"; + private static final int PORT = 8085; public PubSubEmulatorContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(8085); - setWaitStrategy(new LogMessageWaitStrategy() - .withRegEx("(?s).*started.*$")); + setWaitStrategy(new LogMessageWaitStrategy().withRegEx("(?s).*started.*$")); withCommand("/bin/sh", "-c", CMD); } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java index 0ae8e89dc06..dc45b004c6c 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/SpannerEmulatorContainer.java @@ -10,19 +10,20 @@ */ public class SpannerEmulatorContainer extends GenericContainer { - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator"); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "gcr.io/cloud-spanner-emulator/emulator" + ); private static final int GRPC_PORT = 9010; + private static final int HTTP_PORT = 9020; public SpannerEmulatorContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(GRPC_PORT, HTTP_PORT); - setWaitStrategy(new LogMessageWaitStrategy() - .withRegEx(".*Cloud Spanner emulator running\\..*")); + setWaitStrategy(new LogMessageWaitStrategy().withRegEx(".*Cloud Spanner emulator running\\..*")); } /** diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java index 4ba59a75488..3e22231220b 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/BigtableEmulatorContainerTest.java @@ -1,22 +1,13 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.assertThat; - -import com.google.api.core.ApiFuture; -import com.google.api.gax.batching.Batcher; import com.google.api.gax.core.CredentialsProvider; import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.grpc.GrpcTransportChannel; import com.google.api.gax.rpc.FixedTransportChannelProvider; import com.google.api.gax.rpc.TransportChannelProvider; -import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminClient; import com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient; -import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest; import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest; -import com.google.cloud.bigtable.admin.v2.models.Instance; import com.google.cloud.bigtable.admin.v2.models.Table; -import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub; -import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStubSettings; import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings; import com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub; import com.google.cloud.bigtable.data.v2.BigtableDataClient; @@ -24,20 +15,22 @@ import com.google.cloud.bigtable.data.v2.models.Row; import com.google.cloud.bigtable.data.v2.models.RowCell; import com.google.cloud.bigtable.data.v2.models.RowMutation; -import com.google.cloud.bigtable.data.v2.models.RowMutationEntry; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; -import java.io.IOException; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.ExecutionException; import org.junit.Rule; import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; + public class BigtableEmulatorContainerTest { public static final String PROJECT_ID = "test-project"; + public static final String INSTANCE_ID = "test-instance"; @Rule @@ -45,28 +38,31 @@ public class BigtableEmulatorContainerTest { public BigtableEmulatorContainer emulator = new BigtableEmulatorContainer( DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); + // } @Test // testWithEmulatorContainer { public void testSimple() throws IOException, InterruptedException, ExecutionException { - ManagedChannel channel = ManagedChannelBuilder.forTarget(emulator.getEmulatorEndpoint()) - .usePlaintext().build(); + ManagedChannel channel = ManagedChannelBuilder.forTarget(emulator.getEmulatorEndpoint()).usePlaintext().build(); - TransportChannelProvider channelProvider = FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel)); + TransportChannelProvider channelProvider = FixedTransportChannelProvider.create( + GrpcTransportChannel.create(channel) + ); NoCredentialsProvider credentialsProvider = NoCredentialsProvider.create(); try { - createTable(channelProvider, credentialsProvider, "test-table" ); + createTable(channelProvider, credentialsProvider, "test-table"); - BigtableDataClient client = BigtableDataClient.create(BigtableDataSettings - .newBuilderForEmulator(emulator.getHost(), emulator.getEmulatorPort()) - .setProjectId(PROJECT_ID) - .setInstanceId(INSTANCE_ID) - .build()); + BigtableDataClient client = BigtableDataClient.create( + BigtableDataSettings + .newBuilderForEmulator(emulator.getHost(), emulator.getEmulatorPort()) + .setProjectId(PROJECT_ID) + .setInstanceId(INSTANCE_ID) + .build() + ); - client.mutateRow(RowMutation.create("test-table", "1") - .setCell("name", "firstName", "Ray")); + client.mutateRow(RowMutation.create("test-table", "1").setCell("name", "firstName", "Ray")); Row row = client.readRow("test-table", "1"); List cells = row.getCells("name", "firstName"); @@ -77,15 +73,22 @@ public void testSimple() throws IOException, InterruptedException, ExecutionExce channel.shutdown(); } } + // } // createTable { - private void createTable(TransportChannelProvider channelProvider, CredentialsProvider credentialsProvider, String tableName) throws IOException { - EnhancedBigtableTableAdminStub stub = EnhancedBigtableTableAdminStub - .createEnhanced(BigtableTableAdminStubSettings.newBuilder() + private void createTable( + TransportChannelProvider channelProvider, + CredentialsProvider credentialsProvider, + String tableName + ) throws IOException { + EnhancedBigtableTableAdminStub stub = EnhancedBigtableTableAdminStub.createEnhanced( + BigtableTableAdminStubSettings + .newBuilder() .setTransportChannelProvider(channelProvider) .setCredentialsProvider(credentialsProvider) - .build()); + .build() + ); try (BigtableTableAdminClient client = BigtableTableAdminClient.create(PROJECT_ID, INSTANCE_ID, stub)) { Table table = client.createTable(CreateTableRequest.of(tableName).addFamily("name")); diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java index ba998e402ce..a7fe340791d 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java @@ -1,7 +1,5 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.assertThat; - import com.google.cloud.NoCredentials; import com.google.cloud.ServiceOptions; import com.google.cloud.datastore.Datastore; @@ -12,6 +10,8 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import static org.assertj.core.api.Assertions.assertThat; + public class DatastoreEmulatorContainerTest { @Rule @@ -19,17 +19,19 @@ public class DatastoreEmulatorContainerTest { public DatastoreEmulatorContainer emulator = new DatastoreEmulatorContainer( DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); + // } // startingDatastoreEmulatorContainer { @Test public void testSimple() { - DatastoreOptions options = DatastoreOptions.newBuilder() - .setHost(emulator.getEmulatorEndpoint()) - .setCredentials(NoCredentials.getInstance()) - .setRetrySettings(ServiceOptions.getNoRetrySettings()) - .setProjectId("test-project") - .build(); + DatastoreOptions options = DatastoreOptions + .newBuilder() + .setHost(emulator.getEmulatorEndpoint()) + .setCredentials(NoCredentials.getInstance()) + .setRetrySettings(ServiceOptions.getNoRetrySettings()) + .setProjectId("test-project") + .build(); Datastore datastore = options.getService(); Key key = datastore.newKeyFactory().setKind("Task").newKey("sample"); diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java index 04939ecc30e..c87f8e5176a 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java @@ -1,7 +1,5 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.assertThat; - import com.google.api.core.ApiFuture; import com.google.cloud.NoCredentials; import com.google.cloud.firestore.CollectionReference; @@ -10,13 +8,16 @@ import com.google.cloud.firestore.FirestoreOptions; import com.google.cloud.firestore.QuerySnapshot; import com.google.cloud.firestore.WriteResult; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutionException; import org.junit.Rule; import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; + public class FirestoreEmulatorContainerTest { @Rule @@ -24,16 +25,19 @@ public class FirestoreEmulatorContainerTest { public FirestoreEmulatorContainer emulator = new FirestoreEmulatorContainer( DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); + // } // testWithEmulatorContainer { @Test public void testSimple() throws ExecutionException, InterruptedException { - FirestoreOptions options = FirestoreOptions.getDefaultInstance().toBuilder() - .setHost(emulator.getEmulatorEndpoint()) - .setCredentials(NoCredentials.getInstance()) - .setProjectId("test-project") - .build(); + FirestoreOptions options = FirestoreOptions + .getDefaultInstance() + .toBuilder() + .setHost(emulator.getEmulatorEndpoint()) + .setCredentials(NoCredentials.getInstance()) + .setProjectId("test-project") + .build(); Firestore firestore = options.getService(); CollectionReference users = firestore.collection("users"); diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java index 61d56a279d7..aeb92bc4a69 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java @@ -1,7 +1,5 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.assertThat; - import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.grpc.GrpcTransportChannel; import com.google.api.gax.rpc.FixedTransportChannelProvider; @@ -24,11 +22,14 @@ import com.google.pubsub.v1.TopicName; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; -import java.io.IOException; import org.junit.Rule; import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + public class PubSubEmulatorContainerTest { public static final String PROJECT_ID = "my-project-id"; @@ -38,8 +39,8 @@ public class PubSubEmulatorContainerTest { public PubSubEmulatorContainer emulator = new PubSubEmulatorContainer( DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators") ); - // } + // } @Test // testWithEmulatorContainer { @@ -47,8 +48,9 @@ public void testSimple() throws IOException { String hostport = emulator.getEmulatorEndpoint(); ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build(); try { - TransportChannelProvider channelProvider = - FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel)); + TransportChannelProvider channelProvider = FixedTransportChannelProvider.create( + GrpcTransportChannel.create(channel) + ); NoCredentialsProvider credentialsProvider = NoCredentialsProvider.create(); String topicId = "my-topic-id"; @@ -57,56 +59,77 @@ public void testSimple() throws IOException { String subscriptionId = "my-subscription-id"; createSubscription(subscriptionId, topicId, channelProvider, credentialsProvider); - Publisher publisher = Publisher.newBuilder(TopicName.of(PROJECT_ID, topicId)) - .setChannelProvider(channelProvider) - .setCredentialsProvider(credentialsProvider) - .build(); + Publisher publisher = Publisher + .newBuilder(TopicName.of(PROJECT_ID, topicId)) + .setChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); PubsubMessage message = PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8("test message")).build(); publisher.publish(message); - SubscriberStubSettings subscriberStubSettings = - SubscriberStubSettings.newBuilder() - .setTransportChannelProvider(channelProvider) - .setCredentialsProvider(credentialsProvider) - .build(); + SubscriberStubSettings subscriberStubSettings = SubscriberStubSettings + .newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); try (SubscriberStub subscriber = GrpcSubscriberStub.create(subscriberStubSettings)) { - PullRequest pullRequest = PullRequest.newBuilder() - .setMaxMessages(1) - .setSubscription(ProjectSubscriptionName.format(PROJECT_ID, subscriptionId)) - .build(); + PullRequest pullRequest = PullRequest + .newBuilder() + .setMaxMessages(1) + .setSubscription(ProjectSubscriptionName.format(PROJECT_ID, subscriptionId)) + .build(); PullResponse pullResponse = subscriber.pullCallable().call(pullRequest); assertThat(pullResponse.getReceivedMessagesList()).hasSize(1); - assertThat(pullResponse.getReceivedMessages(0).getMessage().getData().toStringUtf8()).isEqualTo("test message"); + assertThat(pullResponse.getReceivedMessages(0).getMessage().getData().toStringUtf8()) + .isEqualTo("test message"); } } finally { channel.shutdown(); } } + // } // createTopic { - private void createTopic(String topicId, TransportChannelProvider channelProvider, NoCredentialsProvider credentialsProvider) throws IOException { - TopicAdminSettings topicAdminSettings = TopicAdminSettings.newBuilder() - .setTransportChannelProvider(channelProvider) - .setCredentialsProvider(credentialsProvider) - .build(); + private void createTopic( + String topicId, + TransportChannelProvider channelProvider, + NoCredentialsProvider credentialsProvider + ) throws IOException { + TopicAdminSettings topicAdminSettings = TopicAdminSettings + .newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); try (TopicAdminClient topicAdminClient = TopicAdminClient.create(topicAdminSettings)) { TopicName topicName = TopicName.of(PROJECT_ID, topicId); topicAdminClient.createTopic(topicName); } } + // } // createSubscription { - private void createSubscription(String subscriptionId, String topicId, TransportChannelProvider channelProvider, NoCredentialsProvider credentialsProvider) throws IOException { - SubscriptionAdminSettings subscriptionAdminSettings = SubscriptionAdminSettings.newBuilder() - .setTransportChannelProvider(channelProvider) - .setCredentialsProvider(credentialsProvider) - .build(); + private void createSubscription( + String subscriptionId, + String topicId, + TransportChannelProvider channelProvider, + NoCredentialsProvider credentialsProvider + ) throws IOException { + SubscriptionAdminSettings subscriptionAdminSettings = SubscriptionAdminSettings + .newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider) + .build(); SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create(subscriptionAdminSettings); SubscriptionName subscriptionName = SubscriptionName.of(PROJECT_ID, subscriptionId); - subscriptionAdminClient.createSubscription(subscriptionName, TopicName.of(PROJECT_ID, topicId), PushConfig.getDefaultInstance(), 10); + subscriptionAdminClient.createSubscription( + subscriptionName, + TopicName.of(PROJECT_ID, topicId), + PushConfig.getDefaultInstance(), + 10 + ); } // } diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java index 64b81546499..b246e7e1f0d 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java @@ -1,7 +1,5 @@ package org.testcontainers.containers; -import static org.assertj.core.api.Assertions.assertThat; - import com.google.cloud.NoCredentials; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseAdminClient; @@ -16,12 +14,15 @@ import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.SpannerOptions; import com.google.cloud.spanner.Statement; -import java.util.Arrays; -import java.util.concurrent.ExecutionException; import org.junit.Rule; import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import java.util.Arrays; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; + public class SpannerEmulatorContainerTest { @Rule @@ -29,20 +30,24 @@ public class SpannerEmulatorContainerTest { public SpannerEmulatorContainer emulator = new SpannerEmulatorContainer( DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.4.0") ); + // } private static final String PROJECT_NAME = "test-project"; + private static final String INSTANCE_NAME = "test-instance"; + private static final String DATABASE_NAME = "test-database"; // testWithEmulatorContainer { @Test public void testSimple() throws ExecutionException, InterruptedException { - SpannerOptions options = SpannerOptions.newBuilder() - .setEmulatorHost(emulator.getEmulatorGrpcEndpoint()) - .setCredentials(NoCredentials.getInstance()) - .setProjectId(PROJECT_NAME) - .build(); + SpannerOptions options = SpannerOptions + .newBuilder() + .setEmulatorHost(emulator.getEmulatorGrpcEndpoint()) + .setCredentials(NoCredentials.getInstance()) + .setProjectId(PROJECT_NAME) + .build(); Spanner spanner = options.getService(); @@ -52,28 +57,38 @@ public void testSimple() throws ExecutionException, InterruptedException { DatabaseId databaseId = DatabaseId.of(instanceId, DATABASE_NAME); DatabaseClient dbClient = spanner.getDatabaseClient(databaseId); - dbClient.readWriteTransaction() - .run(tx -> { - String sql1 = "Delete from TestTable where 1=1"; - tx.executeUpdate(Statement.of(sql1)); - String sql = "INSERT INTO TestTable (Key, Value) VALUES (1, 'Java'), (2, 'Go')"; - tx.executeUpdate(Statement.of(sql)); - return null; - }); - - ResultSet resultSet = dbClient.readOnlyTransaction() - .executeQuery(Statement.of("select * from TestTable order by Key")); + dbClient + .readWriteTransaction() + .run(tx -> { + String sql1 = "Delete from TestTable where 1=1"; + tx.executeUpdate(Statement.of(sql1)); + String sql = "INSERT INTO TestTable (Key, Value) VALUES (1, 'Java'), (2, 'Go')"; + tx.executeUpdate(Statement.of(sql)); + return null; + }); + + ResultSet resultSet = dbClient + .readOnlyTransaction() + .executeQuery(Statement.of("select * from TestTable order by Key")); resultSet.next(); assertThat(resultSet.getLong(0)).isEqualTo(1); assertThat(resultSet.getString(1)).isEqualTo("Java"); } + // } // createDatabase { private void createDatabase(Spanner spanner) throws InterruptedException, ExecutionException { DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient(); - Database database = dbAdminClient.createDatabase(INSTANCE_NAME, DATABASE_NAME, Arrays.asList("CREATE TABLE TestTable (Key INT64, Value STRING(MAX)) PRIMARY KEY (Key)")).get(); + Database database = dbAdminClient + .createDatabase( + INSTANCE_NAME, + DATABASE_NAME, + Arrays.asList("CREATE TABLE TestTable (Key INT64, Value STRING(MAX)) PRIMARY KEY (Key)") + ) + .get(); } + // } // createInstance { @@ -81,7 +96,16 @@ private InstanceId createInstance(Spanner spanner) throws InterruptedException, InstanceConfigId instanceConfig = InstanceConfigId.of(PROJECT_NAME, "emulator-config"); InstanceId instanceId = InstanceId.of(PROJECT_NAME, INSTANCE_NAME); InstanceAdminClient insAdminClient = spanner.getInstanceAdminClient(); - Instance instance = insAdminClient.createInstance(InstanceInfo.newBuilder(instanceId).setNodeCount(1).setDisplayName("Test instance").setInstanceConfigId(instanceConfig).build()).get(); + Instance instance = insAdminClient + .createInstance( + InstanceInfo + .newBuilder(instanceId) + .setNodeCount(1) + .setDisplayName("Test instance") + .setInstanceConfigId(instanceConfig) + .build() + ) + .get(); return instanceId; } // } diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 5bb8935c39e..242cc7bdb43 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -34,27 +34,38 @@ public class HiveMQContainer extends GenericContainer { private static final Logger LOGGER = LoggerFactory.getLogger(HiveMQContainer.class); private static final DockerImageName DEFAULT_HIVEMQ_EE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq4"); + private static final DockerImageName DEFAULT_HIVEMQ_CE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq-ce"); private static final int DEBUGGING_PORT = 9000; + private static final int MQTT_PORT = 1883; + private static final int CONTROL_CENTER_PORT = 8080; + @SuppressWarnings("OctalInteger") private static final int MODE = 0777; - private static final @NotNull Pattern EXTENSION_ID_PATTERN = Pattern.compile("(.+?)"); - private final @NotNull ConcurrentHashMap containerOutputLatches = new ConcurrentHashMap<>(); + @NotNull + private static final Pattern EXTENSION_ID_PATTERN = Pattern.compile("(.+?)"); + + @NotNull + private final ConcurrentHashMap containerOutputLatches = new ConcurrentHashMap<>(); + private boolean controlCenterEnabled = false; + private boolean debugging = false; - private final @NotNull Set prepackagedExtensionsToRemove = new HashSet<>(); + @NotNull + private final Set prepackagedExtensionsToRemove = new HashSet<>(); + private boolean removeAllPrepackagedExtensions = false; - private final @NotNull WaitAllStrategy waitStrategy = new WaitAllStrategy(); + @NotNull + private final WaitAllStrategy waitStrategy = new WaitAllStrategy(); public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_HIVEMQ_CE_IMAGE_NAME, DEFAULT_HIVEMQ_EE_IMAGE_NAME); addExposedPort(MQTT_PORT); @@ -96,13 +107,14 @@ protected void configure() { withCreateContainerCmdModifier(it -> it.withEntrypoint("/bin/sh")); if (removeAllPrepackagedExtensions || !prepackagedExtensionsToRemove.isEmpty()) { - if (removeAllPrepackagedExtensions) { removeCommand = "rm -rf /opt/hivemq/extensions/** &&"; } else { - removeCommand = prepackagedExtensionsToRemove.stream() - .map(extensionId -> "rm -rf /opt/hivemq/extensions/" + extensionId + "&&") - .collect(Collectors.joining()); + removeCommand = + prepackagedExtensionsToRemove + .stream() + .map(extensionId -> "rm -rf /opt/hivemq/extensions/" + extensionId + "&&") + .collect(Collectors.joining()); } } else { removeCommand = ""; @@ -110,16 +122,20 @@ protected void configure() { setCommand( "-c", removeCommand + - "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ " + - "; rm -rf /opt/hivemq/temp-extensions/** " + - "&& chmod -R 777 /opt/hivemq/extensions " + - "&& /opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" + "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ " + + "; rm -rf /opt/hivemq/temp-extensions/** " + + "&& chmod -R 777 /opt/hivemq/extensions " + + "&& /opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" ); } protected void containerIsStarted(final @NotNull InspectContainerResponse containerInfo) { if (controlCenterEnabled) { - LOGGER.info("The HiveMQ Control Center is reachable under: http://{}:{}", getHost(), getMappedPort(CONTROL_CENTER_PORT)); + LOGGER.info( + "The HiveMQ Control Center is reachable under: http://{}:{}", + getHost(), + getMappedPort(CONTROL_CENTER_PORT) + ); } } @@ -159,7 +175,10 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai public @NotNull HiveMQContainer withDebugging() { debugging = true; addExposedPorts(DEBUGGING_PORT); - withEnv("JAVA_OPTS", "-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:" + DEBUGGING_PORT + ",server=y,suspend=y"); + withEnv( + "JAVA_OPTS", + "-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:" + DEBUGGING_PORT + ",server=y,suspend=y" + ); return self(); } @@ -213,10 +232,16 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai public @NotNull HiveMQContainer withExtension(final @NotNull MountableFile mountableExtension) { final File extensionDir = new File(mountableExtension.getResolvedPath()); if (!extensionDir.exists()) { - throw new ContainerLaunchException("Extension '" + mountableExtension.getFilesystemPath() + "' could not be mounted. It does not exist."); + throw new ContainerLaunchException( + "Extension '" + mountableExtension.getFilesystemPath() + "' could not be mounted. It does not exist." + ); } if (!extensionDir.isDirectory()) { - throw new ContainerLaunchException("Extension '" + mountableExtension.getFilesystemPath() + "' could not be mounted. It is not a directory."); + throw new ContainerLaunchException( + "Extension '" + + mountableExtension.getFilesystemPath() + + "' could not be mounted. It is not a directory." + ); } try { final String extensionDirName = getExtensionDirectoryName(extensionDir); @@ -277,10 +302,14 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai public @NotNull HiveMQContainer withLicense(final @NotNull MountableFile mountableLicense) { final File licenseFile = new File(mountableLicense.getResolvedPath()); if (!licenseFile.exists()) { - throw new ContainerLaunchException("License file '" + mountableLicense.getFilesystemPath() + "' does not exist."); + throw new ContainerLaunchException( + "License file '" + mountableLicense.getFilesystemPath() + "' does not exist." + ); } if (!licenseFile.getName().endsWith(".lic") && !licenseFile.getName().endsWith(".elic")) { - throw new ContainerLaunchException("License file '" + mountableLicense.getFilesystemPath() + "' does not end wit '.lic' or '.elic'."); + throw new ContainerLaunchException( + "License file '" + mountableLicense.getFilesystemPath() + "' does not end wit '.lic' or '.elic'." + ); } final String containerPath = "/opt/hivemq/license/" + licenseFile.getName(); withCopyFileToContainer(cloneWithFileMode(mountableLicense), containerPath); @@ -299,7 +328,9 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai public @NotNull HiveMQContainer withHiveMQConfig(final @NotNull MountableFile mountableConfig) { final File config = new File(mountableConfig.getResolvedPath()); if (!config.exists()) { - throw new ContainerLaunchException("HiveMQ config file '" + mountableConfig.getFilesystemPath() + "' does not exist."); + throw new ContainerLaunchException( + "HiveMQ config file '" + mountableConfig.getFilesystemPath() + "' does not exist." + ); } final String containerPath = "/opt/hivemq/conf/config.xml"; withCopyFileToContainer(cloneWithFileMode(mountableConfig), containerPath); @@ -320,8 +351,8 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai */ public @NotNull HiveMQContainer withFileInExtensionHomeFolder( final @NotNull MountableFile file, - final @NotNull String extensionId) { - + final @NotNull String extensionId + ) { return withFileInExtensionHomeFolder(file, extensionId, ""); } @@ -340,9 +371,12 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai public @NotNull HiveMQContainer withFileInExtensionHomeFolder( final @NotNull MountableFile file, final @NotNull String extensionId, - final @NotNull String pathInExtensionHome) { - - return withFileInHomeFolder(file, "/temp-extensions/" + extensionId + PathUtil.prepareAppendPath(pathInExtensionHome)); + final @NotNull String pathInExtensionHome + ) { + return withFileInHomeFolder( + file, + "/temp-extensions/" + extensionId + PathUtil.prepareAppendPath(pathInExtensionHome) + ); } /** @@ -356,8 +390,8 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai */ public @NotNull HiveMQContainer withFileInHomeFolder( final @NotNull MountableFile mountableFile, - final @NotNull String pathInHomeFolder) { - + final @NotNull String pathInHomeFolder + ) { final File file = new File(mountableFile.getResolvedPath()); if (pathInHomeFolder.trim().isEmpty()) { @@ -388,11 +422,12 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai public void disableExtension( final @NotNull String extensionName, final @NotNull String extensionDirectory, - final @NotNull Duration timeout) throws TimeoutException { - + final @NotNull Duration timeout + ) throws TimeoutException { final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) stopped successfully(.*)"; try { - final String containerPath = "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; + final String containerPath = + "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; final CountDownLatch latch = new CountDownLatch(1); containerOutputLatches.put(regEX, latch); @@ -402,9 +437,13 @@ public void disableExtension( final boolean await = latch.await(timeout.getSeconds(), TimeUnit.SECONDS); if (!await) { - throw new TimeoutException("Extension disabling timed out after '" + timeout.getSeconds() + "' seconds. " + + throw new TimeoutException( + "Extension disabling timed out after '" + + timeout.getSeconds() + + "' seconds. " + "Maybe you are using a HiveMQ Community Edition image, " + - "which does not support disabling of extensions"); + "which does not support disabling of extensions" + ); } } catch (final InterruptedException | IOException e) { throw new RuntimeException(e); @@ -424,9 +463,8 @@ public void disableExtension( * @param extensionDirectory the name of the extension's directory * @throws TimeoutException if the extension was not disabled within 60 seconds */ - public void disableExtension( - final @NotNull String extensionName, - final @NotNull String extensionDirectory) throws TimeoutException { + public void disableExtension(final @NotNull String extensionName, final @NotNull String extensionDirectory) + throws TimeoutException { disableExtension(extensionName, extensionDirectory, Duration.ofSeconds(60)); } @@ -441,9 +479,8 @@ public void disableExtension( * @param timeout the timeout * @throws TimeoutException if the extension was not disabled within the configured timeout */ - public void disableExtension( - final @NotNull HiveMQExtension hiveMQExtension, - final @NotNull Duration timeout) throws TimeoutException { + public void disableExtension(final @NotNull HiveMQExtension hiveMQExtension, final @NotNull Duration timeout) + throws TimeoutException { disableExtension(hiveMQExtension.getName(), hiveMQExtension.getId(), timeout); } @@ -476,11 +513,12 @@ public void disableExtension(final @NotNull HiveMQExtension hiveMQExtension) thr public void enableExtension( final @NotNull String extensionName, final @NotNull String extensionDirectory, - final @NotNull Duration timeout) throws TimeoutException { - + final @NotNull Duration timeout + ) throws TimeoutException { final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) started successfully(.*)"; try { - final String containerPath = "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; + final String containerPath = + "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; final CountDownLatch latch = new CountDownLatch(1); containerOutputLatches.put(regEX, latch); @@ -490,9 +528,13 @@ public void enableExtension( final boolean await = latch.await(timeout.getSeconds(), TimeUnit.SECONDS); if (!await) { - throw new TimeoutException("Extension enabling timed out after '" + timeout.getSeconds() + "' seconds. " + + throw new TimeoutException( + "Extension enabling timed out after '" + + timeout.getSeconds() + + "' seconds. " + "Maybe you are using a HiveMQ Community Edition image, " + - "which does not support disabling of extensions"); + "which does not support disabling of extensions" + ); } } catch (final InterruptedException | IOException e) { throw new RuntimeException(e); @@ -512,9 +554,8 @@ public void enableExtension( * @param extensionDirectory the name of the extension's directory * @throws TimeoutException if the extension was not enabled within 60 seconds */ - public void enableExtension( - final @NotNull String extensionName, - final @NotNull String extensionDirectory) throws TimeoutException { + public void enableExtension(final @NotNull String extensionName, final @NotNull String extensionDirectory) + throws TimeoutException { enableExtension(extensionName, extensionDirectory, Duration.ofSeconds(60)); } @@ -529,9 +570,8 @@ public void enableExtension( * @param timeout the timeout * @throws TimeoutException if the extension was not enabled within the configured timeout */ - public void enableExtension( - final @NotNull HiveMQExtension hiveMQExtension, - final @NotNull Duration timeout) throws TimeoutException { + public void enableExtension(final @NotNull HiveMQExtension hiveMQExtension, final @NotNull Duration timeout) + throws TimeoutException { enableExtension(hiveMQExtension.getName(), hiveMQExtension.getId(), timeout); } diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java index 934dfd0c29c..91e984835d6 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -1,7 +1,5 @@ package org.testcontainers.hivemq; -import javassist.ClassPool; -import javassist.NotFoundException; import lombok.Getter; import org.apache.commons.io.FileUtils; import org.jboss.shrinkwrap.api.ExtensionLoader; @@ -23,28 +21,35 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import javassist.ClassPool; +import javassist.NotFoundException; public class HiveMQExtension { private static final String VALID_EXTENSION_XML = "" + // - " %s" + // - " %s" + // - " %s" + // - " %s" + // - " %s" + // - ""; + " %s" + // + " %s" + // + " %s" + // + " %s" + // + " %s" + // + ""; + private static final String EXTENSION_MAIN_CLASS_NAME = "com.hivemq.extension.sdk.api.ExtensionMain"; + private static final Logger LOGGER = LoggerFactory.getLogger(HiveMQExtension.class); @Getter - private final @NotNull String id; + @NotNull + private final String id; @Getter - private final @NotNull String name; + @NotNull + private final String name; @Getter - private final @NotNull String version; + @NotNull + private final String version; @Getter private final int priority; @@ -56,9 +61,11 @@ public class HiveMQExtension { private final boolean disabledOnStartup; @Getter - private final @NotNull Class mainClass; + @NotNull + private final Class mainClass; - private final @NotNull List> additionalClasses; + @NotNull + private final List> additionalClasses; private HiveMQExtension( final @NotNull String id, @@ -68,8 +75,8 @@ private HiveMQExtension( final int startPriority, final boolean disabledOnStartup, final @NotNull Class mainClass, - final @NotNull List> additionalClasses) { - + final @NotNull List> additionalClasses + ) { this.id = id; this.name = name; this.version = version; @@ -80,27 +87,31 @@ private HiveMQExtension( this.additionalClasses = additionalClasses; } - @NotNull File createExtension(final @NotNull HiveMQExtension hiveMQExtension) - throws Exception { - + @NotNull + File createExtension(final @NotNull HiveMQExtension hiveMQExtension) throws Exception { final File tempDir = Files.createTempDirectory("").toFile(); final File extensionDir = new File(tempDir, hiveMQExtension.getId()); - FileUtils.writeStringToFile(new File(extensionDir, "hivemq-extension.xml"), + FileUtils.writeStringToFile( + new File(extensionDir, "hivemq-extension.xml"), String.format( VALID_EXTENSION_XML, hiveMQExtension.getId(), hiveMQExtension.getName(), hiveMQExtension.getVersion(), hiveMQExtension.getPriority(), - hiveMQExtension.getStartPriority()), - Charset.defaultCharset()); + hiveMQExtension.getStartPriority() + ), + Charset.defaultCharset() + ); if (hiveMQExtension.isDisabledOnStartup()) { final File disabled = new File(extensionDir, "DISABLED"); final boolean newFile = disabled.createNewFile(); if (!newFile) { - throw new ContainerLaunchException("Could not create DISABLED file '" + disabled.getAbsolutePath() + "' on host machine."); + throw new ContainerLaunchException( + "Could not create DISABLED file '" + disabled.getAbsolutePath() + "' on host machine." + ); } } @@ -129,11 +140,15 @@ private HiveMQExtension( private void putSubclassesIntoJar( final @NotNull String extensionId, final @Nullable Class clazz, - final @NotNull JavaArchive javaArchive) throws NotFoundException { - + final @NotNull JavaArchive javaArchive + ) throws NotFoundException { if (clazz != null) { - final Set subClassNames = - ClassPool.getDefault().get(clazz.getName()).getClassFile().getConstPool().getClassNames(); + final Set subClassNames = ClassPool + .getDefault() + .get(clazz.getName()) + .getClassFile() + .getConstPool() + .getClassNames(); for (final String subClassName : subClassNames) { final String className = subClassName.replaceAll("/", "."); @@ -156,14 +171,27 @@ private void putSubclassesIntoJar( } public static final class Builder { - private @Nullable String id; - private @Nullable String name; - private @Nullable String version; + + @Nullable + private String id; + + @Nullable + private String name; + + @Nullable + private String version; + private int priority = 0; + private int startPriority = 0; + private boolean disabledOnStartup = false; - private @Nullable Class mainClass; - private final @NotNull LinkedList> additionalClasses = new LinkedList<>(); + + @Nullable + private Class mainClass; + + @NotNull + private final LinkedList> additionalClasses = new LinkedList<>(); /** * Builds the {@link HiveMQExtension} with the provided values or default values. @@ -274,12 +302,16 @@ public static final class Builder { try { final Class extensionMain = Class.forName(EXTENSION_MAIN_CLASS_NAME); if (!extensionMain.isAssignableFrom(mainClass)) { - throw new IllegalArgumentException("The provided class does not implement '" + EXTENSION_MAIN_CLASS_NAME + "'"); + throw new IllegalArgumentException( + "The provided class does not implement '" + EXTENSION_MAIN_CLASS_NAME + "'" + ); } this.mainClass = mainClass; return this; } catch (final ClassNotFoundException e) { - throw new IllegalStateException("The class '" + EXTENSION_MAIN_CLASS_NAME + "' was not found in the classpath."); + throw new IllegalStateException( + "The class '" + EXTENSION_MAIN_CLASS_NAME + "' was not found in the classpath." + ); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java index f88d60b22ed..a3e8a20216d 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -17,18 +17,18 @@ public class ContainerWithControlCenterIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) public void test() throws Exception { - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) - .withControlCenter()) { - + try ( + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withControlCenter() + ) { hivemq.start(); try (final CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { - final HttpUriRequest request = new HttpGet("http://" + hivemq.getHost() + ":" + hivemq.getMappedPort(CONTROL_CENTER_PORT)); + final HttpUriRequest request = new HttpGet( + "http://" + hivemq.getHost() + ":" + hivemq.getMappedPort(CONTROL_CENTER_PORT) + ); httpClient.execute(request); } } - } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java index 57d3b75bc24..fe119854c80 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -18,13 +18,14 @@ public class ContainerWithCustomConfigIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - - try (final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) - .withHiveMQConfig(MountableFile.forClasspathResource("/config.xml"))) { - + try ( + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withHiveMQConfig(MountableFile.forClasspathResource("/config.xml")) + ) { hivemq.start(); - final Mqtt5BlockingClient publisher = Mqtt5Client.builder() + final Mqtt5BlockingClient publisher = Mqtt5Client + .builder() .identifier("publisher") .serverPort(hivemq.getMqttPort()) .serverHost(hivemq.getHost()) @@ -32,13 +33,13 @@ void test() throws Exception { publisher.connect(); - assertThrows(MqttSessionExpiredException.class, () -> { - // this should fail since only QoS 0 is allowed by the configuration - publisher.publishWith() - .topic("test/topic") - .qos(MqttQos.EXACTLY_ONCE) - .send(); - }); + assertThrows( + MqttSessionExpiredException.class, + () -> { + // this should fail since only QoS 0 is allowed by the configuration + publisher.publishWith().topic("test/topic").qos(MqttQos.EXACTLY_ONCE).send(); + } + ); } } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java index 4b89e418b05..c1e6e72cc32 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -15,13 +15,14 @@ public class ContainerWithExtensionFromDirectoryIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { try ( - final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withExtension(MountableFile.forClasspathResource("/modifier-extension")) - .waitForExtension("Modifier Extension") - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .withLogLevel(Level.DEBUG)) { - + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension") + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withLogLevel(Level.DEBUG) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } @@ -30,12 +31,14 @@ void test() throws Exception { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test_wrongDirectoryName() throws Exception { - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) .withExtension(MountableFile.forClasspathResource("/modifier-extension-wrong-name")) .waitForExtension("Modifier Extension") - .withLogLevel(Level.DEBUG)) { - + .withLogLevel(Level.DEBUG) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java index 8979d2c17b0..01a67e0dcfb 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -14,18 +14,22 @@ public class ContainerWithExtensionIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(MyExtension.class).build(); - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .waitForExtension(hiveMQExtension) - .withExtension(hiveMQExtension)) { - + .mainClass(MyExtension.class) + .build(); + + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.stop(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java index 53714123aff..1f3d9de4aeb 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -15,19 +15,23 @@ public class ContainerWithExtensionSubclassIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(MyExtensionWithSubclasses.class).build(); - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .waitForExtension(hiveMQExtension) - .withExtension(hiveMQExtension) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .withLogLevel(Level.DEBUG)) { + .mainClass(MyExtensionWithSubclasses.class) + .build(); + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withLogLevel(Level.DEBUG) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java index 559737c8868..a5b5238ce25 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -22,26 +22,30 @@ public class ContainerWithFileInExtensionHomeIT { - @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(FileCheckerExtension.class).build(); - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .withExtension(hiveMQExtension) - .waitForExtension(hiveMQExtension) - .withFileInExtensionHomeFolder( - MountableFile.forClasspathResource("/additionalFile.txt"), - "extension-1", - "/additionalFiles/my-file.txt")) { - + .mainClass(FileCheckerExtension.class) + .build(); + + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInExtensionHomeFolder( + MountableFile.forClasspathResource("/additionalFile.txt"), + "extension-1", + "/additionalFiles/my-file.txt" + ) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } @@ -50,28 +54,33 @@ void test() throws Exception { public static class FileCheckerExtension implements ExtensionMain { @Override - public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { - + public void extensionStart( + final @NotNull ExtensionStartInput extensionStartInput, + final @NotNull ExtensionStartOutput extensionStartOutput + ) { final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { - final File extensionHomeFolder = extensionStartInput.getExtensionInformation().getExtensionHomeFolder(); final File additionalFile = new File(extensionHomeFolder, "additionalFiles/my-file.txt"); if (additionalFile.exists()) { - publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + publishInboundOutput + .getPublishPacket() + .setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); } }; - final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; Services.initializerRegistry().setClientInitializer(clientInitializer); } @Override - public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { - - } + public void extensionStop( + final @NotNull ExtensionStopInput extensionStopInput, + final @NotNull ExtensionStopOutput extensionStopOutput + ) {} } - } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java index efdf6ad298d..2fd387f394c 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -25,21 +25,26 @@ public class ContainerWithFileInHomeIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(FileCheckerExtension.class).build(); - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .withExtension(hiveMQExtension) - .waitForExtension(hiveMQExtension) - .withFileInHomeFolder(MountableFile.forClasspathResource("/additionalFile.txt"), - "/additionalFiles/my-file.txt")) { - - + .mainClass(FileCheckerExtension.class) + .build(); + + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInHomeFolder( + MountableFile.forClasspathResource("/additionalFile.txt"), + "/additionalFiles/my-file.txt" + ) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } @@ -48,28 +53,33 @@ void test() throws Exception { public static class FileCheckerExtension implements ExtensionMain { @Override - public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { - + public void extensionStart( + @NotNull ExtensionStartInput extensionStartInput, + @NotNull ExtensionStartOutput extensionStartOutput + ) { final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { - final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); final File additionalFile = new File(homeFolder, "additionalFiles/my-file.txt"); if (additionalFile.exists()) { - publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + publishInboundOutput + .getPublishPacket() + .setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); } }; - final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; Services.initializerRegistry().setClientInitializer(clientInitializer); } @Override - public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { - - } + public void extensionStop( + @NotNull ExtensionStopInput extensionStopInput, + @NotNull ExtensionStopOutput extensionStopOutput + ) {} } - } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java index ba2dc472cdb..9d82188c35c 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -25,21 +25,24 @@ public class ContainerWithLicenseIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(LicenceCheckerExtension.class).build(); - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .withExtension(hiveMQExtension) - .waitForExtension(hiveMQExtension) - .withLicense(MountableFile.forClasspathResource("/myLicense.lic")) - .withLicense(MountableFile.forClasspathResource("/myExtensionLicense.elic"))) { - - + .mainClass(LicenceCheckerExtension.class) + .build(); + + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withLicense(MountableFile.forClasspathResource("/myLicense.lic")) + .withLicense(MountableFile.forClasspathResource("/myExtensionLicense.elic")) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } @@ -49,16 +52,19 @@ void test() throws Exception { public static class LicenceCheckerExtension implements ExtensionMain { @Override - public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { - + public void extensionStart( + @NotNull ExtensionStartInput extensionStartInput, + @NotNull ExtensionStartOutput extensionStartOutput + ) { final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { - final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); final File myLicence = new File(homeFolder, "license/myLicense.lic"); final File myExtensionLicence = new File(homeFolder, "license/myExtensionLicense.elic"); if (myLicence.exists() && myExtensionLicence.exists()) { - publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + publishInboundOutput + .getPublishPacket() + .setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); } }; @@ -70,9 +76,9 @@ public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @No } @Override - public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { - - } + public void extensionStop( + @NotNull ExtensionStopInput extensionStopInput, + @NotNull ExtensionStopOutput extensionStopOutput + ) {} } - } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java index eaec72cb038..75d308e3f90 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -29,25 +29,28 @@ public class ContainerWithoutPlatformExtensionsIT { - private final @NotNull HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + @NotNull + private final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .name("MyExtension") .id("my-extension") .version("1.0.0") - .mainClass(CheckerExtension.class).build(); - + .mainClass(CheckerExtension.class) + .build(); @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) public void removeAllPlatformExtensions() throws InterruptedException { - - try (final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) - .withExtension(hiveMQExtension) - .waitForExtension(hiveMQExtension) - .withoutPrepackagedExtensions()) { - + try ( + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withoutPrepackagedExtensions() + ) { hivemq.start(); - final Mqtt5BlockingClient client = MqttClient.builder() + final Mqtt5BlockingClient client = MqttClient + .builder() .serverPort(hivemq.getMqttPort()) .serverHost(hivemq.getHost()) .useMqttVersion5() @@ -73,15 +76,16 @@ public void removeAllPlatformExtensions() throws InterruptedException { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) public void removeKafkaExtension() throws InterruptedException { - - try (final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) - .withExtension(hiveMQExtension) - .waitForExtension(hiveMQExtension) - .withoutPrepackagedExtensions("hivemq-kafka-extension")) { - + try ( + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withoutPrepackagedExtensions("hivemq-kafka-extension") + ) { hivemq.start(); - final Mqtt5BlockingClient client = MqttClient.builder() + final Mqtt5BlockingClient client = MqttClient + .builder() .serverPort(hivemq.getMqttPort()) .serverHost(hivemq.getHost()) .useMqttVersion5() @@ -107,31 +111,32 @@ public static class CheckerExtension implements ExtensionMain { @Override public void extensionStart( final @NotNull ExtensionStartInput extensionStartInput, - final @NotNull ExtensionStartOutput extensionStartOutput) { - - final String extensionFolders = Arrays.stream(extensionStartInput.getServerInformation().getExtensionsFolder().listFiles()) + final @NotNull ExtensionStartOutput extensionStartOutput + ) { + final String extensionFolders = Arrays + .stream(extensionStartInput.getServerInformation().getExtensionsFolder().listFiles()) .filter(File::isDirectory) .map(File::getName) .collect(Collectors.joining("\n")); final byte[] bytes = extensionFolders.getBytes(StandardCharsets.UTF_8); - Services.publishService().publish(Builders.publish() - .topic("extensions") - .retain(true) - .payload(ByteBuffer.wrap(bytes)) - .build()); - - Services.securityRegistry().setAuthenticatorProvider(authenticatorProviderInput -> - (SimpleAuthenticator) (simpleAuthInput, simpleAuthOutput) -> - simpleAuthOutput.authenticateSuccessfully()); - + Services + .publishService() + .publish(Builders.publish().topic("extensions").retain(true).payload(ByteBuffer.wrap(bytes)).build()); + + Services + .securityRegistry() + .setAuthenticatorProvider(authenticatorProviderInput -> { + return (SimpleAuthenticator) (simpleAuthInput, simpleAuthOutput) -> { + simpleAuthOutput.authenticateSuccessfully(); + }; + }); } @Override public void extensionStop( final @NotNull ExtensionStopInput extensionStopInput, - final @NotNull ExtensionStopOutput extensionStopOutput) { - - } + final @NotNull ExtensionStopOutput extensionStopOutput + ) {} } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java index 58b70c3d1d9..191ea41f303 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -37,19 +37,23 @@ public class CreateFileInCopiedDirectoryIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQExtension extension = HiveMQExtension.builder() + final HiveMQExtension extension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(FileCreatorExtension.class).build(); - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .withExtension(extension) - .waitForExtension(extension) - .withFileInHomeFolder(createDirectory(), "directory")) { - + .mainClass(FileCreatorExtension.class) + .build(); + + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(extension) + .waitForExtension(extension) + .withFileInHomeFolder(createDirectory(), "directory") + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } @@ -58,10 +62,11 @@ void test() throws Exception { public static class FileCreatorExtension implements ExtensionMain { @Override - public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { - + public void extensionStart( + @NotNull ExtensionStartInput extensionStartInput, + @NotNull ExtensionStartOutput extensionStartOutput + ) { final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { - final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); final File dir = new File(homeFolder, "directory"); @@ -71,22 +76,26 @@ public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @No try { if (dirFile.createNewFile() && subDirFile.createNewFile()) { - publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + publishInboundOutput + .getPublishPacket() + .setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); } } catch (IOException e) { e.printStackTrace(); } }; - final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; Services.initializerRegistry().setClientInitializer(clientInitializer); } @Override - public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { - - } + public void extensionStop( + @NotNull ExtensionStopInput extensionStopInput, + @NotNull ExtensionStopOutput extensionStopOutput + ) {} } - } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java index c41137f58c3..44f5f4f632d 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -26,18 +26,22 @@ public class CreateFileInExtensionDirectoryIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(FileCreatorExtension.class).build(); - - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .waitForExtension(hiveMQExtension) - .withExtension(hiveMQExtension)) { - + .mainClass(FileCreatorExtension.class) + .build(); + + try ( + final HiveMQContainer hivemq = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension) + ) { hivemq.start(); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } @@ -46,31 +50,36 @@ void test() throws Exception { public static class FileCreatorExtension implements ExtensionMain { @Override - public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { - + public void extensionStart( + @NotNull ExtensionStartInput extensionStartInput, + @NotNull ExtensionStartOutput extensionStartOutput + ) { final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { - final File extensionHomeFolder = extensionStartInput.getExtensionInformation().getExtensionHomeFolder(); final File file = new File(extensionHomeFolder, "myfile.txt"); try { if (file.createNewFile()) { - publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + publishInboundOutput + .getPublishPacket() + .setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); } } catch (IOException e) { e.printStackTrace(); } }; - final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; Services.initializerRegistry().setClientInitializer(clientInitializer); } @Override - public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { - - } + public void extensionStop( + @NotNull ExtensionStopInput extensionStopInput, + @NotNull ExtensionStopOutput extensionStopOutput + ) {} } - } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java index f6b1b9b5cd7..9588e3404e6 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -17,21 +17,22 @@ public class DisableEnableExtensionFromDirectoryIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) - .withExtension(MountableFile.forClasspathResource("/modifier-extension")) - .waitForExtension("Modifier Extension") - .withLogLevel(Level.DEBUG)) { - + try ( + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension") + .withLogLevel(Level.DEBUG) + ) { hivemq.start(); - TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.disableExtension("Modifier Extension", "modifier-extension"); - assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); + assertThrows( + ExecutionException.class, + () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()) + ); hivemq.enableExtension("Modifier Extension", "modifier-extension"); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } - } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java index 5b3c6ab107f..e50664f240e 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -15,32 +15,39 @@ public class DisableEnableExtensionIT { - private final @NotNull HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + @NotNull + private final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") .disabledOnStartup(true) - .mainClass(MyExtension.class).build(); + .mainClass(MyExtension.class) + .build(); @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - try (final HiveMQContainer hivemq = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) - .withExtension(hiveMQExtension) - .withLogLevel(Level.DEBUG)) { - - + try ( + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + .withExtension(hiveMQExtension) + .withLogLevel(Level.DEBUG) + ) { hivemq.start(); - assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); + assertThrows( + ExecutionException.class, + () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()) + ); hivemq.enableExtension(hiveMQExtension); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.disableExtension(hiveMQExtension); - assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); + assertThrows( + ExecutionException.class, + () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()) + ); hivemq.enableExtension(hiveMQExtension); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } } - } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java index d614a59bd8c..08e1df797a1 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java @@ -8,6 +8,9 @@ class HiveMQExtensionTest { @Test void builder_classDoesNotImplementExtensionMain_exception() { - assertThrows(IllegalArgumentException.class, () -> HiveMQExtension.builder().mainClass(HiveMQExtensionTest.class)); + assertThrows( + IllegalArgumentException.class, + () -> HiveMQExtension.builder().mainClass(HiveMQExtensionTest.class) + ); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java index 40820e33ded..d4dd2be9621 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java @@ -15,7 +15,8 @@ class HiveMQTestContainerCore { - final @NotNull HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")); + @NotNull + final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")); @TempDir File tempDir; @@ -69,14 +70,23 @@ void withFileInHomeFolder_pathEmpty_Exception() { @Test void withFileInExtensionHomeFolder_withPath_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows(ContainerLaunchException.class, () -> container.withFileInExtensionHomeFolder(mountableFile, "my-extension", "some/path")); + assertThrows( + ContainerLaunchException.class, + () -> container.withFileInExtensionHomeFolder(mountableFile, "my-extension", "some/path") + ); } @Test void withFileInExtensionHomeFolder_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows(ContainerLaunchException.class, () -> { - final HiveMQContainer hiveMQContainer = container.withFileInExtensionHomeFolder(mountableFile, "my-extension"); - }); + assertThrows( + ContainerLaunchException.class, + () -> { + final HiveMQContainer hiveMQContainer = container.withFileInExtensionHomeFolder( + mountableFile, + "my-extension" + ); + } + ); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java index e9d9463653e..97a1365ac91 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java @@ -14,43 +14,54 @@ public class DemoDisableExtensionsIT { // noExtensions { @Container - final HiveMQContainer hivemqNoExtensions = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + final HiveMQContainer hivemqNoExtensions = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4") + ) .withoutPrepackagedExtensions(); + // } // noKafkaExtension { @Container - final HiveMQContainer hivemqNoKafkaExtension = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + final HiveMQContainer hivemqNoKafkaExtension = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4") + ) .withoutPrepackagedExtensions("hivemq-kafka-extension"); + // } // startDisabled { - private final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + private final HiveMQExtension hiveMQExtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") .disabledOnStartup(true) - .mainClass(MyExtension.class).build(); + .mainClass(MyExtension.class) + .build(); @Container final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) .withExtension(hiveMQExtension); - // } + // } // startFromFilesystem { @Container - final HiveMQContainer hivemqExtensionFromFilesystem = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) + final HiveMQContainer hivemqExtensionFromFilesystem = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4") + ) .withExtension(MountableFile.forHostPath("src/test/resources/modifier-extension")); - // } + // } - // runtimeEnable { + // hiveRuntimeEnable { @Test void test_disable_enable_extension() throws Exception { hivemq.enableExtension(hiveMQExtension); hivemq.disableExtension(hiveMQExtension); } + // } // runtimeEnableFilesystem { diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java index 3a8ccc1bebe..e5385369d3a 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java @@ -19,33 +19,39 @@ public class DemoExtensionTestsIT { // waitStrategy { @Container - final HiveMQContainer hivemqWithWaitStrategy = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")) - .withExtension(MountableFile.forClasspathResource("/modifier-extension")) - .waitForExtension("Modifier Extension"); + final HiveMQContainer hivemqWithWaitStrategy = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4") + ) + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension"); + // } // extensionClasspath { - final HiveMQExtension hiveMQEClasspathxtension = HiveMQExtension.builder() + final HiveMQExtension hiveMQEClasspathxtension = HiveMQExtension + .builder() .id("extension-1") .name("my-extension") .version("1.0") - .mainClass(MyExtensionWithSubclasses.class).build(); + .mainClass(MyExtensionWithSubclasses.class) + .build(); @Container - final HiveMQContainer hivemqWithClasspathExtension = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .waitForExtension(hiveMQEClasspathxtension) - .withExtension(hiveMQEClasspathxtension) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")); + final HiveMQContainer hivemqWithClasspathExtension = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .waitForExtension(hiveMQEClasspathxtension) + .withExtension(hiveMQEClasspathxtension) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")); + // } @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) public void test() throws Exception { - // mqtt5client { - final Mqtt5BlockingClient client = Mqtt5Client.builder() + final Mqtt5BlockingClient client = Mqtt5Client + .builder() .serverPort(hivemqWithClasspathExtension.getMqttPort()) .serverHost(hivemqWithClasspathExtension.getHost()) .buildBlocking(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java index 7ec777d02b8..d0bf6fc6b9c 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java @@ -18,24 +18,36 @@ public class DemoFilesIT { // hivemqHome { - final HiveMQContainer hivemqFileInHome = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + final HiveMQContainer hivemqFileInHome = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) .withFileInHomeFolder( MountableFile.forHostPath("src/test/resources/additionalFile.txt"), - "/path/in/home/folder"); + "/path/in/home/folder" + ); + // } // extensionHome { @Container - final HiveMQContainer hivemqFileInExtensionHome = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withExtension(HiveMQExtension.builder() - .id("extension-1") - .name("my-extension") - .version("1.0") - .mainClass(MyExtension.class).build()) + final HiveMQContainer hivemqFileInExtensionHome = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withExtension( + HiveMQExtension + .builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtension.class) + .build() + ) .withFileInExtensionHomeFolder( MountableFile.forHostPath("src/test/resources/additionalFile.txt"), "extension-1", - "/path/in/extension/home"); + "/path/in/extension/home" + ); + // } // withLicenses { @@ -43,14 +55,15 @@ public class DemoFilesIT { final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) .withLicense(MountableFile.forHostPath("src/test/resources/myLicense.lic")) .withLicense(MountableFile.forHostPath("src/test/resources/myExtensionLicense.elic")); + // } @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) public void test() throws Exception { - // mqtt5client { - final Mqtt5BlockingClient client = Mqtt5Client.builder() + final Mqtt5BlockingClient client = Mqtt5Client + .builder() .serverPort(hivemq.getMqttPort()) .serverHost(hivemq.getHost()) .buildBlocking(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java index 51e3a43d9e5..be39fe6d7f2 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java @@ -18,38 +18,41 @@ public class DemoHiveMQContainerIT { // ceVersion { @Container - final HiveMQContainer hivemqCe = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withLogLevel(Level.DEBUG); + final HiveMQContainer hivemqCe = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withLogLevel(Level.DEBUG); + // } - // eeVersion { + // hiveEEVersion { @Container - final HiveMQContainer hivemqEe = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withLogLevel(Level.DEBUG); + final HiveMQContainer hivemqEe = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + .withLogLevel(Level.DEBUG); + // } // eeVersionWithControlCenter { @Container - final HiveMQContainer hivemqEeWithControLCenter = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) - .withLogLevel(Level.DEBUG) - .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) - .withControlCenter(); + final HiveMQContainer hivemqEeWithControlCenter = new HiveMQContainer( + DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + ) + .withLogLevel(Level.DEBUG) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withControlCenter(); + // } // specificVersion { @Container final HiveMQContainer hivemqSpecificVersion = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce:2021.3")); + // } @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) public void test() throws Exception { - // mqtt5client { - final Mqtt5BlockingClient client = Mqtt5Client.builder() + final Mqtt5BlockingClient client = Mqtt5Client + .builder() .serverPort(hivemqCe.getMqttPort()) .serverHost(hivemqCe.getHost()) .buildBlocking(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java index e707859be77..4c3991122d7 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java @@ -1,7 +1,6 @@ package org.testcontainers.hivemq.util; import com.hivemq.extension.sdk.api.ExtensionMain; -import org.jetbrains.annotations.NotNull; import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; @@ -9,6 +8,7 @@ import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; import com.hivemq.extension.sdk.api.services.Services; import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -17,10 +17,14 @@ public class MyExtension implements ExtensionMain { @Override - public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { - + public void extensionStart( + final @NotNull ExtensionStartInput extensionStartInput, + final @NotNull ExtensionStartOutput extensionStartOutput + ) { final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { - publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + publishInboundOutput + .getPublishPacket() + .setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); }; final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { @@ -31,7 +35,8 @@ public void extensionStart(final @NotNull ExtensionStartInput extensionStartInpu } @Override - public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { - - } + public void extensionStop( + final @NotNull ExtensionStopInput extensionStopInput, + final @NotNull ExtensionStopOutput extensionStopOutput + ) {} } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java index abc24585358..9e4565b15c9 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java @@ -1,26 +1,31 @@ package org.testcontainers.hivemq.util; import com.hivemq.extension.sdk.api.ExtensionMain; -import org.jetbrains.annotations.NotNull; import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; import com.hivemq.extension.sdk.api.services.Services; import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; public class MyExtensionWithSubclasses implements ExtensionMain { @Override - public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { - - final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(new PublishModifier()); + public void extensionStart( + final @NotNull ExtensionStartInput extensionStartInput, + final @NotNull ExtensionStartOutput extensionStartOutput + ) { + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(new PublishModifier()); + }; Services.initializerRegistry().setClientInitializer(clientInitializer); } @Override - public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { - - } + public void extensionStop( + final @NotNull ExtensionStopInput extensionStopInput, + final @NotNull ExtensionStopOutput extensionStopOutput + ) {} } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java index d33f29a9c10..ec5b63ee1e6 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java @@ -1,16 +1,22 @@ package org.testcontainers.hivemq.util; -import org.jetbrains.annotations.NotNull; import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundInput; import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundOutput; +import org.jetbrains.annotations.NotNull; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; public class PublishModifier implements PublishInboundInterceptor { + @Override - public void onInboundPublish(final @NotNull PublishInboundInput publishInboundInput, final @NotNull PublishInboundOutput publishInboundOutput) { - publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + public void onInboundPublish( + final @NotNull PublishInboundInput publishInboundInput, + final @NotNull PublishInboundOutput publishInboundOutput + ) { + publishInboundOutput + .getPublishPacket() + .setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java index f2f1cfd692f..963570c07c4 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java @@ -14,27 +14,38 @@ public class TestPublishModifiedUtil { public static void testPublishModified(final int mqttPort, final @NotNull String host) throws Exception { final CompletableFuture publishReceived = new CompletableFuture<>(); - final Mqtt5BlockingClient publisher = Mqtt5Client.builder() + final Mqtt5BlockingClient publisher = Mqtt5Client + .builder() .serverPort(mqttPort) .serverHost(host) .identifier("publisher") .buildBlocking(); publisher.connect(); - final Mqtt5BlockingClient subscriber = Mqtt5Client.builder() + final Mqtt5BlockingClient subscriber = Mqtt5Client + .builder() .serverPort(mqttPort) .serverHost(host) .identifier("subscriber") .buildBlocking(); subscriber.connect(); subscriber.subscribeWith().topicFilter("test/topic").send(); - subscriber.toAsync().publishes(MqttGlobalPublishFilter.ALL, publish -> { - if (Arrays.equals(publish.getPayloadAsBytes(), "modified".getBytes(StandardCharsets.UTF_8))) { - publishReceived.complete(null); - } else { - publishReceived.completeExceptionally(new IllegalArgumentException("unexpected payload: " + new String(publish.getPayloadAsBytes()))); - } - }); + subscriber + .toAsync() + .publishes( + MqttGlobalPublishFilter.ALL, + publish -> { + if (Arrays.equals(publish.getPayloadAsBytes(), "modified".getBytes(StandardCharsets.UTF_8))) { + publishReceived.complete(null); + } else { + publishReceived.completeExceptionally( + new IllegalArgumentException( + "unexpected payload: " + new String(publish.getPayloadAsBytes()) + ) + ); + } + } + ); publisher.publishWith().topic("test/topic").payload("unmodified".getBytes(StandardCharsets.UTF_8)).send(); @@ -45,6 +56,4 @@ public static void testPublishModified(final int mqttPort, final @NotNull String subscriber.disconnect(); } } - - } diff --git a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java index 7ebfbff1a86..40eea721b57 100644 --- a/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java +++ b/modules/influxdb/src/main/java/org/testcontainers/containers/InfluxDBContainer.java @@ -17,17 +17,22 @@ public class InfluxDBContainer> extends Gen public static final Integer INFLUXDB_PORT = 8086; private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("influxdb"); + private static final String DEFAULT_TAG = "1.4.3"; @Deprecated public static final String VERSION = DEFAULT_TAG; private boolean authEnabled = true; + private String admin = "admin"; + private String adminPassword = "password"; private String database; + private String username = "any"; + private String password = "any"; /** @@ -48,12 +53,12 @@ public InfluxDBContainer(final String version) { public InfluxDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); - waitStrategy = new WaitAllStrategy() - .withStrategy(Wait.forHttp("/ping").withBasicCredentials(username, password).forStatusCode(204)) - .withStrategy(Wait.forListeningPort()); + waitStrategy = + new WaitAllStrategy() + .withStrategy(Wait.forHttp("/ping").withBasicCredentials(username, password).forStatusCode(204)) + .withStrategy(Wait.forListeningPort()); addExposedPort(INFLUXDB_PORT); } @@ -144,7 +149,6 @@ public SELF withPassword(final String password) { return self(); } - /** * @return a url to influxDb */ diff --git a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java index 7acf030b5e4..c7fc71a3a19 100644 --- a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java +++ b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java @@ -4,14 +4,16 @@ import org.junit.ClassRule; import org.junit.Test; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; public class InfluxDBContainerTest { @ClassRule - public static InfluxDBContainer influxDBContainer = new InfluxDBContainer<>(InfluxDBTestImages.INFLUXDB_TEST_IMAGE); + public static InfluxDBContainer influxDBContainer = new InfluxDBContainer<>( + InfluxDBTestImages.INFLUXDB_TEST_IMAGE + ); @Test public void getUrl() { diff --git a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java index b045ca297c1..a7ae347e7cc 100644 --- a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java +++ b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java @@ -9,17 +9,20 @@ import java.util.concurrent.TimeUnit; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; public class InfluxDBContainerWithUserTest { private static final String TEST_VERSION = InfluxDBTestImages.INFLUXDB_TEST_IMAGE.getVersionPart(); + private static final String DATABASE = "test"; + private static final String USER = "test-user"; + private static final String PASSWORD = "test-password"; @Rule @@ -52,7 +55,8 @@ public void checkVersion() { public void queryForWriteAndRead() { InfluxDB influxDB = influxDBContainer.getNewInfluxDB(); - Point point = Point.measurement("cpu") + Point point = Point + .measurement("cpu") .time(System.currentTimeMillis(), TimeUnit.MILLISECONDS) .addField("idle", 90L) .addField("user", 9L) @@ -67,6 +71,5 @@ public void queryForWriteAndRead() { assertThat(actual.getError(), nullValue()); assertThat(actual.getResults(), notNullValue()); assertThat(actual.getResults().size(), is(1)); - } } diff --git a/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java index 6a5ca5094d6..6d3080c7ee3 100644 --- a/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/db/AbstractContainerDatabaseTest.java @@ -4,11 +4,12 @@ import com.zaxxer.hikari.HikariDataSource; import org.testcontainers.containers.JdbcDatabaseContainer; -import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import javax.sql.DataSource; + public abstract class AbstractContainerDatabaseTest { protected ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLException { diff --git a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java index 4e5eb03bb49..5566db6244e 100644 --- a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java @@ -25,22 +25,19 @@ protected enum Options { CharacterSet, CustomIniFile, JDBCParams, - PmdKnownBroken + PmdKnownBroken, } @Parameter public String jdbcUrl; + @Parameter(1) public EnumSet options; public static void sampleInitFunction(Connection connection) throws SQLException { - connection.createStatement().execute("CREATE TABLE bar (\n" + - " foo VARCHAR(255)\n" + - ");"); + connection.createStatement().execute("CREATE TABLE bar (\n" + " foo VARCHAR(255)\n" + ");"); connection.createStatement().execute("INSERT INTO bar (foo) VALUES ('hello world');"); - connection.createStatement().execute("CREATE TABLE my_counter (\n" + - " n INT\n" + - ");"); + connection.createStatement().execute("CREATE TABLE my_counter (\n" + " n INT\n" + ");"); } @AfterClass @@ -79,67 +76,99 @@ private void performSimpleTest(HikariDataSource dataSource) throws SQLException query = "SELECT 1 FROM SYSIBM.SYSDUMMY1"; } - boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)).query(query, rs -> { - rs.next(); - int resultSetInt = rs.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - return true; - }); + boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)) + .query( + query, + rs -> { + rs.next(); + int resultSetInt = rs.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + return true; + } + ); assertTrue("The database returned a record as expected", result); } private void performTestForScriptedSchema(HikariDataSource dataSource) throws SQLException { - boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%world'", rs -> { - rs.next(); - String resultSetString = rs.getString(1); - assertEquals("A basic SELECT query succeeds where the schema has been applied from a script", "hello world", resultSetString); - return true; - }); + boolean result = new QueryRunner(dataSource) + .query( + "SELECT foo FROM bar WHERE foo LIKE '%world'", + rs -> { + rs.next(); + String resultSetString = rs.getString(1); + assertEquals( + "A basic SELECT query succeeds where the schema has been applied from a script", + "hello world", + resultSetString + ); + return true; + } + ); assertTrue("The database returned a record as expected", result); } private void performTestForJDBCParamUsage(HikariDataSource dataSource) throws SQLException { - boolean result = new QueryRunner(dataSource).query("select CURRENT_USER", rs -> { - rs.next(); - String resultUser = rs.getString(1); - // Not all databases (eg. Postgres) return @% at the end of user name. We just need to make sure the user name matches. - if (resultUser.endsWith("@%")) { - resultUser = resultUser.substring(0, resultUser.length() - 2); - } - assertEquals("User from query param is created.", "someuser", resultUser); - return true; - }); + boolean result = new QueryRunner(dataSource) + .query( + "select CURRENT_USER", + rs -> { + rs.next(); + String resultUser = rs.getString(1); + // Not all databases (eg. Postgres) return @% at the end of user name. We just need to make sure the user name matches. + if (resultUser.endsWith("@%")) { + resultUser = resultUser.substring(0, resultUser.length() - 2); + } + assertEquals("User from query param is created.", "someuser", resultUser); + return true; + } + ); assertTrue("The database returned a record as expected", result); String databaseQuery = "SELECT DATABASE()"; // Postgres does not have Database() as a function String databaseType = ConnectionUrl.newInstance(jdbcUrl).getDatabaseType(); - if (databaseType.equalsIgnoreCase("postgresql") || + if ( + databaseType.equalsIgnoreCase("postgresql") || databaseType.equalsIgnoreCase("postgis") || - databaseType.equalsIgnoreCase("timescaledb")) { + databaseType.equalsIgnoreCase("timescaledb") + ) { databaseQuery = "SELECT CURRENT_DATABASE()"; } - result = new QueryRunner(dataSource).query(databaseQuery, rs -> { - rs.next(); - String resultDB = rs.getString(1); - assertEquals("Database name from URL String is used.", "databasename", resultDB); - return true; - }); + result = + new QueryRunner(dataSource) + .query( + databaseQuery, + rs -> { + rs.next(); + String resultDB = rs.getString(1); + assertEquals("Database name from URL String is used.", "databasename", resultDB); + return true; + } + ); assertTrue("The database returned a record as expected", result); } - private void performTestForCharacterEncodingForInitialScriptConnection(HikariDataSource dataSource) throws SQLException { - boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%мир'", rs -> { - rs.next(); - String resultSetString = rs.getString(1); - assertEquals("A SELECT query succeed and the correct charset has been applied for the init script", "привет мир", resultSetString); - return true; - }); + private void performTestForCharacterEncodingForInitialScriptConnection(HikariDataSource dataSource) + throws SQLException { + boolean result = new QueryRunner(dataSource) + .query( + "SELECT foo FROM bar WHERE foo LIKE '%мир'", + rs -> { + rs.next(); + String resultSetString = rs.getString(1); + assertEquals( + "A SELECT query succeed and the correct charset has been applied for the init script", + "привет мир", + resultSetString + ); + return true; + } + ); assertTrue("The database returned a record as expected", result); } @@ -160,12 +189,19 @@ private void performSimpleTestWithCharacterSet(String jdbcUrl) throws SQLExcepti private HikariDataSource verifyCharacterSet(String jdbcUrl) throws SQLException { HikariDataSource dataSource = getDataSource(jdbcUrl, 1); - boolean result = new QueryRunner(dataSource).query("SHOW VARIABLES LIKE 'character\\_set\\_connection'", rs -> { - rs.next(); - String resultSetString = rs.getString(2); - assertTrue("Passing query parameters to set DB connection encoding is successful", resultSetString.startsWith("utf8")); - return true; - }); + boolean result = new QueryRunner(dataSource) + .query( + "SHOW VARIABLES LIKE 'character\\_set\\_connection'", + rs -> { + rs.next(); + String resultSetString = rs.getString(2); + assertTrue( + "Passing query parameters to set DB connection encoding is successful", + resultSetString.startsWith("utf8") + ); + return true; + } + ); assertTrue("The database returned a record as expected", result); return dataSource; diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 5e5342f1ee1..84d242a29c7 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -20,23 +20,29 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.Future; - -import static java.util.stream.Collectors.joining; +import java.util.stream.Collectors; /** * Base class for containers that expose a JDBC connection * * @author richardnorth */ -public abstract class JdbcDatabaseContainer> extends GenericContainer implements LinkableContainer { +public abstract class JdbcDatabaseContainer> + extends GenericContainer + implements LinkableContainer { private static final Object DRIVER_LOAD_MUTEX = new Object(); + private Driver driver; + private String initScriptPath; + protected Map parameters = new HashMap<>(); + protected Map urlParameters = new HashMap<>(); private int startupTimeoutSeconds = 120; + private int connectTimeoutSeconds = 120; private static final String QUERY_PARAM_SEPARATOR = "&"; @@ -135,7 +141,12 @@ public SELF withInitScript(String initScriptPath) { @SneakyThrows(InterruptedException.class) @Override protected void waitUntilContainerStarted() { - logger().info("Waiting for database connection to become available at {} using query '{}'", getJdbcUrl(), getTestQueryString()); + logger() + .info( + "Waiting for database connection to become available at {} using query '{}'", + getJdbcUrl(), + getTestQueryString() + ); // Repeatedly try and open a connection to the DB and execute a test query long start = System.currentTimeMillis(); @@ -144,8 +155,7 @@ protected void waitUntilContainerStarted() { if (!isRunning()) { Thread.sleep(100L); } else { - try (Connection connection = createConnection(""); - Statement statement = connection.createStatement()) { + try (Connection connection = createConnection(""); Statement statement = connection.createStatement()) { boolean testQuerySucceeded = statement.execute(this.getTestQueryString()); if (testQuerySucceeded) { logger().info("Container is started (JDBC URL: {})", this.getJdbcUrl()); @@ -163,8 +173,10 @@ protected void waitUntilContainerStarted() { } throw new IllegalStateException( - String.format("Container is started, but cannot be accessed by (JDBC URL: %s), please check container logs", - this.getJdbcUrl()) + String.format( + "Container is started, but cannot be accessed by (JDBC URL: %s), please check container logs", + this.getJdbcUrl() + ) ); } @@ -179,7 +191,6 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { * @return a JDBC Driver */ public Driver getJdbcDriverInstance() throws NoDriverFoundException { - synchronized (DRIVER_LOAD_MUTEX) { if (driver == null) { try { @@ -215,7 +226,13 @@ public Connection createConnection(String queryString) throws SQLException, NoDr // give up if we hit the time limit or the container stops running for some reason while (System.currentTimeMillis() < start + (1000 * connectTimeoutSeconds) && isRunning()) { try { - logger().debug("Trying to create JDBC connection using {} to {} with properties: {}", driver.getClass().getName(), url, info); + logger() + .debug( + "Trying to create JDBC connection using {} to {} with properties: {}", + driver.getClass().getName(), + url, + info + ); return jdbcDriverInstance.connect(url, info); } catch (SQLException e) { @@ -261,15 +278,18 @@ protected String constructUrlParameters(String startCharacter, String delimiter) protected String constructUrlParameters(String startCharacter, String delimiter, String endCharacter) { String urlParameters = ""; if (!this.urlParameters.isEmpty()) { - String additionalParameters = this.urlParameters.entrySet().stream() - .map(Object::toString) - .collect(joining(delimiter)); + String additionalParameters = + this.urlParameters.entrySet().stream().map(Object::toString).collect(Collectors.joining(delimiter)); urlParameters = startCharacter + additionalParameters + endCharacter; } return urlParameters; } - protected void optionallyMapResourceParameterAsVolume(@NotNull String paramName, @NotNull String pathNameInContainer, @NotNull String defaultResource) { + protected void optionallyMapResourceParameterAsVolume( + @NotNull String paramName, + @NotNull String pathNameInContainer, + @NotNull String defaultResource + ) { String resourceName = parameters.getOrDefault(paramName, defaultResource); if (resourceName != null) { @@ -319,6 +339,7 @@ protected DatabaseDelegate getDatabaseDelegate() { } public static class NoDriverFoundException extends RuntimeException { + public NoDriverFoundException(String message, Throwable e) { super(message, e); } diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java index f8694306384..3cd74dc98d4 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainerProvider.java @@ -1,8 +1,7 @@ package org.testcontainers.containers; -import org.testcontainers.jdbc.ConnectionUrl; - import lombok.extern.slf4j.Slf4j; +import org.testcontainers.jdbc.ConnectionUrl; import java.util.Objects; @@ -26,9 +25,12 @@ public abstract class JdbcDatabaseContainerProvider { * @return Instance of {@link JdbcDatabaseContainer} */ public JdbcDatabaseContainer newInstance() { - log.warn("No explicit version tag was provided in JDBC URL and this class ({}) does not " + + log.warn( + "No explicit version tag was provided in JDBC URL and this class ({}) does not " + "override newInstance() to set a default tag. `latest` will be used but results may " + - "be unreliable!", this.getClass().getCanonicalName()); + "be unreliable!", + this.getClass().getCanonicalName() + ); return this.newInstance("latest"); } @@ -55,7 +57,11 @@ public JdbcDatabaseContainer newInstance(ConnectionUrl url) { return result; } - protected JdbcDatabaseContainer newInstanceFromConnectionUrl(ConnectionUrl connectionUrl, final String userParamName, final String pwdParamName) { + protected JdbcDatabaseContainer newInstanceFromConnectionUrl( + ConnectionUrl connectionUrl, + final String userParamName, + final String pwdParamName + ) { Objects.requireNonNull(connectionUrl, "Connection URL cannot be null"); final String databaseName = connectionUrl.getDatabaseName().orElse("test"); diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java index e7f59b2df4f..47d3cadc823 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionDelegate.java @@ -1,13 +1,13 @@ package org.testcontainers.jdbc; import lombok.RequiredArgsConstructor; -import lombok.Value; import lombok.experimental.Delegate; import java.sql.Connection; @RequiredArgsConstructor class ConnectionDelegate implements Connection { + @Delegate private final Connection delegate; } diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java index 3354ed45c39..b4aef740da0 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java @@ -1,5 +1,10 @@ package org.testcontainers.jdbc; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.testcontainers.UnstableAPI; + import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -10,13 +15,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import org.testcontainers.UnstableAPI; - -import static java.util.stream.Collectors.toMap; - /** * This is an Immutable class holding JDBC Connection Url and its parsed components, used by {@link ContainerDatabaseDriver}. *

@@ -60,6 +58,7 @@ public class ConnectionUrl { private Map containerParameters; private Map queryParameters; + private Map tmpfsOptions = new HashMap<>(); public static ConnectionUrl newInstance(final String url) { @@ -94,7 +93,9 @@ private void parseUrl() { //Try for Oracle pattern urlMatcher = Patterns.ORACLE_URL_MATCHING_PATTERN.matcher(this.getUrl()); if (!urlMatcher.matches()) { - throw new IllegalArgumentException("JDBC URL matches jdbc:tc: prefix but the database or tag name could not be identified"); + throw new IllegalArgumentException( + "JDBC URL matches jdbc:tc: prefix but the database or tag name could not be identified" + ); } } databaseType = urlMatcher.group("databaseType"); @@ -113,9 +114,10 @@ private void parseUrl() { databaseName = Optional.of(dbInstanceMatcher.group("databaseName")); } - queryParameters = Collections.unmodifiableMap( - parseQueryParameters( - Optional.ofNullable(urlMatcher.group("queryParameters")).orElse(""))); + queryParameters = + Collections.unmodifiableMap( + parseQueryParameters(Optional.ofNullable(urlMatcher.group("queryParameters")).orElse("")) + ); String query = queryParameters .entrySet() @@ -133,7 +135,6 @@ private void parseUrl() { tmpfsOptions = parseTmpfsOptions(containerParameters); - initScriptPath = Optional.ofNullable(containerParameters.get("TC_INITSCRIPT")); reusable = Boolean.parseBoolean(containerParameters.get("TC_REUSABLE")); @@ -145,7 +146,6 @@ private void parseUrl() { Matcher daemonMatcher = Patterns.DAEMON_MATCHING_PATTERN.matcher(this.getUrl()); inDaemonMode = daemonMatcher.matches() && Boolean.parseBoolean(daemonMatcher.group(2)); - } private Map parseTmpfsOptions(Map containerParameters) { @@ -155,10 +155,9 @@ private Map parseTmpfsOptions(Map containerParam String tmpfsOptions = containerParameters.get("TC_TMPFS"); - return Stream.of(tmpfsOptions.split(",")) - .collect(toMap( - string -> string.split(":")[0], - string -> string.split(":")[1])); + return Stream + .of(tmpfsOptions.split(",")) + .collect(Collectors.toMap(string -> string.split(":")[0], string -> string.split(":")[1])); } /** @@ -167,7 +166,6 @@ private Map parseTmpfsOptions(Map containerParam * @return {@link Map} */ private Map parseContainerParameters() { - Map results = new HashMap<>(); Matcher matcher = Patterns.TC_PARAM_MATCHING_PATTERN.matcher(this.getUrl()); @@ -186,14 +184,14 @@ private Map parseContainerParameters() { * @return {@link Map} */ private Map parseQueryParameters(final String queryString) { - Map results = new HashMap<>(); Matcher matcher = Patterns.QUERY_PARAM_MATCHING_PATTERN.matcher(queryString); while (matcher.find()) { String key = matcher.group(1); String value = matcher.group(2); - if (!key.matches(Patterns.TC_PARAM_NAME_PATTERN)) + if (!key.matches(Patterns.TC_PARAM_NAME_PATTERN)) { results.put(key, value); + } } return results; @@ -211,36 +209,36 @@ public Map getTmpfsOptions() { public interface Patterns { Pattern URL_MATCHING_PATTERN = Pattern.compile( "jdbc:tc:" + - "(?[a-z0-9]+)" + - "(:(?[^:]+))?" + - "://" + - "(?[^?]+)" + - "(?\\?.*)?" + "(?[a-z0-9]+)" + + "(:(?[^:]+))?" + + "://" + + "(?[^?]+)" + + "(?\\?.*)?" ); Pattern ORACLE_URL_MATCHING_PATTERN = Pattern.compile( "jdbc:tc:" + - "(?[a-z]+)" + - "(:(?(?!thin).+))?:thin:(//)?" + - "(" + - "(?[^:" + - "?^/]+)/(?[^?^/]+)" + - ")?" + - "@" + - "(?[^?]+)" + - "(?\\?.*)?" + "(?[a-z]+)" + + "(:(?(?!thin).+))?:thin:(//)?" + + "(" + + "(?[^:" + + "?^/]+)/(?[^?^/]+)" + + ")?" + + "@" + + "(?[^?]+)" + + "(?\\?.*)?" ); //Matches to part of string - hostname:port/databasename Pattern DB_INSTANCE_MATCHING_PATTERN = Pattern.compile( "(?[^:]+)" + - "(:(?[0-9]+))?" + - "(" + - "(?[:/])" + - "|" + - ";databaseName=" + - ")" + - "(?[^\\\\?]+)" + "(:(?[0-9]+))?" + + "(" + + "(?[:/])" + + "|" + + ";databaseName=" + + ")" + + "(?[^\\\\?]+)" ); Pattern DAEMON_MATCHING_PATTERN = Pattern.compile(".*([?&]?)TC_DAEMON=([^?&]+).*"); @@ -251,24 +249,27 @@ public interface Patterns { @Deprecated Pattern INITSCRIPT_MATCHING_PATTERN = Pattern.compile(".*([?&]?)TC_INITSCRIPT=([^?&]+).*"); - Pattern INITFUNCTION_MATCHING_PATTERN = Pattern.compile(".*([?&]?)TC_INITFUNCTION=" + + Pattern INITFUNCTION_MATCHING_PATTERN = Pattern.compile( + ".*([?&]?)TC_INITFUNCTION=" + "((\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.)*\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)" + "::" + "(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)" + - ".*"); + ".*" + ); String TC_PARAM_NAME_PATTERN = "(TC_[A-Z_]+)"; Pattern TC_PARAM_MATCHING_PATTERN = Pattern.compile(TC_PARAM_NAME_PATTERN + "=([^?&]+)"); Pattern QUERY_PARAM_MATCHING_PATTERN = Pattern.compile("([^?&=]+)=([^?&]*)"); - } @Getter @AllArgsConstructor public class InitFunctionDef { + private String className; + private String methodName; } } diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java index 3e1f67c5b86..4f245590f78 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionWrapper.java @@ -17,7 +17,7 @@ public void close() throws SQLException { super.close(); try { closeCallback.run(); - } catch(Exception e) { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java index 4b3a7ba98f7..23ed9d78b25 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java @@ -7,7 +7,6 @@ import org.testcontainers.delegate.DatabaseDelegate; import org.testcontainers.ext.ScriptUtils; -import javax.script.ScriptException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -17,6 +16,8 @@ import java.util.*; import java.util.logging.Logger; +import javax.script.ScriptException; + /** * Test Containers JDBC proxy driver. This driver will handle JDBC URLs of the form: *

@@ -38,9 +39,13 @@ public class ContainerDatabaseDriver implements Driver { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ContainerDatabaseDriver.class); private Driver delegate; + private static final Map> containerConnections = new HashMap<>(); + private static final Map jdbcUrlContainerCache = new HashMap<>(); + private static final Set initializedContainers = new HashSet<>(); + private static final String FILE_PATH_PREFIX = "file:"; static { @@ -62,7 +67,6 @@ public boolean acceptsURL(String url) throws SQLException { @Override public synchronized Connection connect(String url, final Properties info) throws SQLException { - /* The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. */ @@ -73,7 +77,6 @@ public synchronized Connection connect(String url, final Properties info) throws ConnectionUrl connectionUrl = ConnectionUrl.newInstance(url); synchronized (jdbcUrlContainerCache) { - String queryString = connectionUrl.getQueryString().orElse(""); /* If we already have a running container for this exact connection string, we want to connect @@ -81,7 +84,6 @@ public synchronized Connection connect(String url, final Properties info) throws */ JdbcDatabaseContainer container = jdbcUrlContainerCache.get(connectionUrl.getUrl()); if (container == null) { - LOGGER.debug("Container not found in cache, creating new instance"); Map parameters = connectionUrl.getContainerParameters(); @@ -89,7 +91,9 @@ public synchronized Connection connect(String url, final Properties info) throws /* Find a matching container type using ServiceLoader. */ - ServiceLoader databaseContainers = ServiceLoader.load(JdbcDatabaseContainerProvider.class); + ServiceLoader databaseContainers = ServiceLoader.load( + JdbcDatabaseContainerProvider.class + ); for (JdbcDatabaseContainerProvider candidateContainerType : databaseContainers) { if (candidateContainerType.supports(connectionUrl.getDatabaseType())) { container = candidateContainerType.newInstance(connectionUrl); @@ -98,7 +102,9 @@ public synchronized Connection connect(String url, final Properties info) throws } } if (container == null) { - throw new UnsupportedOperationException("Database name " + connectionUrl.getDatabaseType() + " not supported"); + throw new UnsupportedOperationException( + "Database name " + connectionUrl.getDatabaseType() + " not supported" + ); } /* @@ -138,7 +144,6 @@ public synchronized Connection connect(String url, final Properties info) throws } } - /** * Wrap the connection, setting up a callback to be called when the connection is closed. *

@@ -149,25 +154,34 @@ public synchronized Connection connect(String url, final Properties info) throws * @param connectionUrl {@link ConnectionUrl} instance representing JDBC Url for this connection * @return the connection, wrapped */ - private Connection wrapConnection(final Connection connection, final JdbcDatabaseContainer container, final ConnectionUrl connectionUrl) { - + private Connection wrapConnection( + final Connection connection, + final JdbcDatabaseContainer container, + final ConnectionUrl connectionUrl + ) { final boolean isDaemon = connectionUrl.isInDaemonMode() || connectionUrl.isReusable(); - Set connections = containerConnections.computeIfAbsent(container.getContainerId(), k -> new HashSet<>()); + Set connections = containerConnections.computeIfAbsent( + container.getContainerId(), + k -> new HashSet<>() + ); connections.add(connection); final Set finalConnections = connections; - return new ConnectionWrapper(connection, () -> { - finalConnections.remove(connection); - if (!isDaemon && finalConnections.isEmpty()) { - synchronized (jdbcUrlContainerCache) { - container.stop(); - jdbcUrlContainerCache.remove(connectionUrl.getUrl()); + return new ConnectionWrapper( + connection, + () -> { + finalConnections.remove(connection); + if (!isDaemon && finalConnections.isEmpty()) { + synchronized (jdbcUrlContainerCache) { + container.stop(); + jdbcUrlContainerCache.remove(connectionUrl.getUrl()); + } } } - }); + ); } /** @@ -177,7 +191,8 @@ private Connection wrapConnection(final Connection connection, final JdbcDatabas * @param databaseDelegate database delegate to apply init scripts to the database * @throws SQLException on script or DB error */ - private void runInitScriptIfRequired(final ConnectionUrl connectionUrl, DatabaseDelegate databaseDelegate) throws SQLException { + private void runInitScriptIfRequired(final ConnectionUrl connectionUrl, DatabaseDelegate databaseDelegate) + throws SQLException { if (connectionUrl.getInitScriptPath().isPresent()) { String initScriptPath = connectionUrl.getInitScriptPath().get(); try { @@ -191,7 +206,9 @@ private void runInitScriptIfRequired(final ConnectionUrl connectionUrl, Database } if (resource == null) { LOGGER.warn("Could not load classpath init script: {}", initScriptPath); - throw new SQLException("Could not load classpath init script: " + initScriptPath + ". Resource not found."); + throw new SQLException( + "Could not load classpath init script: " + initScriptPath + ". Resource not found." + ); } String sql = IOUtils.toString(resource, StandardCharsets.UTF_8); @@ -213,7 +230,8 @@ private void runInitScriptIfRequired(final ConnectionUrl connectionUrl, Database * @param connection JDBC connection to apply init functions to. * @throws SQLException on script or DB error */ - private void runInitFunctionIfRequired(final ConnectionUrl connectionUrl, Connection connection) throws SQLException { + private void runInitFunctionIfRequired(final ConnectionUrl connectionUrl, Connection connection) + throws SQLException { if (connectionUrl.getInitFunction().isPresent()) { String className = connectionUrl.getInitFunction().get().getClassName(); String methodName = connectionUrl.getInitFunction().get().getMethodName(); @@ -223,7 +241,9 @@ private void runInitFunctionIfRequired(final ConnectionUrl connectionUrl, Connec Method method = initFunctionClazz.getMethod(methodName, Connection.class); method.invoke(null, connection); - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + } catch ( + ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e + ) { LOGGER.error("Error while executing init function: {}::{}", className, methodName, e); throw new SQLException("Error while executing init function: " + className + "::" + methodName, e); } @@ -270,7 +290,6 @@ public static void killContainers() { containerConnections.clear(); initializedContainers.clear(); } - } /** diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java index 6173a8f6a37..7ed2f7ffde1 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java @@ -18,6 +18,7 @@ public class JdbcDatabaseDelegate extends AbstractDatabaseDelegate { private JdbcDatabaseContainer container; + private String queryString; public JdbcDatabaseDelegate(JdbcDatabaseContainer container, String queryString) { @@ -35,16 +36,27 @@ protected Statement createNewConnection() { } } - @Override - public void execute(String statement, String scriptPath, int lineNumber, boolean continueOnError, boolean ignoreFailedDrops) { + public void execute( + String statement, + String scriptPath, + int lineNumber, + boolean continueOnError, + boolean ignoreFailedDrops + ) { try { boolean rowsAffected = getConnection().execute(statement); log.debug("{} returned as updateCount for SQL: {}", rowsAffected, statement); } catch (SQLException ex) { boolean dropStatement = statement.trim().toLowerCase().startsWith("drop"); if (continueOnError || (dropStatement && ignoreFailedDrops)) { - log.debug("Failed to execute SQL script statement at line {} of resource {}: {}", lineNumber, scriptPath, statement, ex); + log.debug( + "Failed to execute SQL script statement at line {} of resource {}: {}", + lineNumber, + scriptPath, + statement, + ex + ); } else { throw new ScriptUtils.ScriptStatementFailedException(statement, lineNumber, scriptPath, ex); } diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ext/ScriptUtils.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ext/ScriptUtils.java index 76b7a044c9d..c6a3c0fa3ed 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ext/ScriptUtils.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ext/ScriptUtils.java @@ -18,10 +18,11 @@ import org.testcontainers.jdbc.ContainerLessJdbcDelegate; -import javax.script.ScriptException; import java.sql.Connection; import java.util.List; +import javax.script.ScriptException; + /** * Wrapper for database-agnostic ScriptUtils * @@ -68,9 +69,24 @@ private ScriptUtils() { * @see org.testcontainers.ext.ScriptUtils * @deprecated Needed only to keep binary compatibility for this internal API. Consider using database-agnostic ScriptUtils */ - public static void splitSqlScript(String resource, String script, String separator, String commentPrefix, - String blockCommentStartDelimiter, String blockCommentEndDelimiter, List statements) { - org.testcontainers.ext.ScriptUtils.splitSqlScript(resource, script, separator, commentPrefix, blockCommentStartDelimiter, blockCommentEndDelimiter, statements); + public static void splitSqlScript( + String resource, + String script, + String separator, + String commentPrefix, + String blockCommentStartDelimiter, + String blockCommentEndDelimiter, + List statements + ) { + org.testcontainers.ext.ScriptUtils.splitSqlScript( + resource, + script, + separator, + commentPrefix, + blockCommentStartDelimiter, + blockCommentEndDelimiter, + statements + ); } /** @@ -85,18 +101,40 @@ public static boolean containsSqlScriptDelimiters(String script, String delim) { * @see org.testcontainers.ext.ScriptUtils * @deprecated Needed only to keep binary compatibility for this internal API. Consider using database-agnostic ScriptUtils */ - public static void executeSqlScript(Connection connection, String scriptPath, String script) throws ScriptException { - org.testcontainers.ext.ScriptUtils.executeDatabaseScript(new ContainerLessJdbcDelegate(connection), scriptPath, script); + public static void executeSqlScript(Connection connection, String scriptPath, String script) + throws ScriptException { + org.testcontainers.ext.ScriptUtils.executeDatabaseScript( + new ContainerLessJdbcDelegate(connection), + scriptPath, + script + ); } /** * @see org.testcontainers.ext.ScriptUtils * @deprecated Needed only to keep binary compatibility for this internal API. Consider using database-agnostic ScriptUtils */ - public static void executeSqlScript(Connection connection, String scriptPath, String script, boolean continueOnError, - boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter, - String blockCommentEndDelimiter) throws ScriptException { - org.testcontainers.ext.ScriptUtils.executeDatabaseScript(new ContainerLessJdbcDelegate(connection), scriptPath, - script, continueOnError, ignoreFailedDrops, commentPrefix, separator, blockCommentStartDelimiter, blockCommentEndDelimiter); + public static void executeSqlScript( + Connection connection, + String scriptPath, + String script, + boolean continueOnError, + boolean ignoreFailedDrops, + String commentPrefix, + String separator, + String blockCommentStartDelimiter, + String blockCommentEndDelimiter + ) throws ScriptException { + org.testcontainers.ext.ScriptUtils.executeDatabaseScript( + new ContainerLessJdbcDelegate(connection), + scriptPath, + script, + continueOnError, + ignoreFailedDrops, + commentPrefix, + separator, + blockCommentStartDelimiter, + blockCommentEndDelimiter + ); } -} \ No newline at end of file +} diff --git a/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java b/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java index 9f0cf514558..1dc6646bd17 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java @@ -1,11 +1,12 @@ package org.testcontainers.containers; -import java.sql.Connection; -import java.sql.SQLException; import lombok.NonNull; import org.junit.Test; import org.slf4j.Logger; +import java.sql.Connection; +import java.sql.SQLException; + import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java index 12ca5c28c3d..9b88e6b503d 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java @@ -5,9 +5,9 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; +import java.util.Arrays; import java.util.Optional; -import static java.util.Arrays.asList; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; /** @@ -20,35 +20,106 @@ public class ConnectionUrlDriversTests { @Parameter public String jdbcUrl; + @Parameter(1) public String databaseType; + @Parameter(2) public Optional tag; + @Parameter(3) public String dbHostString; + @Parameter(4) public String databaseName; @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:mysql:5.7.34://hostname/test", "mysql", Optional.of("5.7.34"), "hostname/test", "test"}, - {"jdbc:tc:mysql://hostname/test", "mysql", Optional.empty(), "hostname/test", "test"}, - {"jdbc:tc:postgresql:1.2.3://hostname/test", "postgresql", Optional.of("1.2.3"), "hostname/test", "test"}, - {"jdbc:tc:postgresql://hostname/test", "postgresql", Optional.empty(), "hostname/test", "test"}, - {"jdbc:tc:sqlserver:1.2.3://localhost;instance=SQLEXPRESS:1433;databaseName=test", "sqlserver", Optional.of("1.2.3"), "localhost;instance=SQLEXPRESS:1433;databaseName=test", "test"}, - {"jdbc:tc:sqlserver://localhost;instance=SQLEXPRESS:1433;databaseName=test", "sqlserver", Optional.empty(), "localhost;instance=SQLEXPRESS:1433;databaseName=test", "test"}, - {"jdbc:tc:mariadb:1.2.3://localhost:3306/test", "mariadb", Optional.of("1.2.3"), "localhost:3306/test", "test"}, - {"jdbc:tc:mariadb://localhost:3306/test", "mariadb", Optional.empty(), "localhost:3306/test", "test"}, - {"jdbc:tc:oracle:1.2.3:thin://@localhost:1521/test", "oracle", Optional.of("1.2.3"), "localhost:1521/test", "test"}, - {"jdbc:tc:oracle:1.2.3:thin:@localhost:1521/test", "oracle", Optional.of("1.2.3"), "localhost:1521/test", "test"}, - {"jdbc:tc:oracle:thin:@localhost:1521/test", "oracle", Optional.empty(), "localhost:1521/test", "test"}, - {"jdbc:tc:oracle:1.2.3:thin:@localhost:1521:test", "oracle", Optional.of("1.2.3"), "localhost:1521:test", "test"}, - {"jdbc:tc:oracle:1.2.3:thin://@localhost:1521:test", "oracle", Optional.of("1.2.3"), "localhost:1521:test", "test"}, - {"jdbc:tc:oracle:1.2.3-anything:thin://@localhost:1521:test", "oracle", Optional.of("1.2.3-anything"), "localhost:1521:test", "test"}, - {"jdbc:tc:oracle:thin:@localhost:1521:test", "oracle", Optional.empty(), "localhost:1521:test", "test"} - }); + return Arrays.asList( + new Object[][] { + { "jdbc:tc:mysql:5.7.34://hostname/test", "mysql", Optional.of("5.7.34"), "hostname/test", "test" }, + { "jdbc:tc:mysql://hostname/test", "mysql", Optional.empty(), "hostname/test", "test" }, + { + "jdbc:tc:postgresql:1.2.3://hostname/test", + "postgresql", + Optional.of("1.2.3"), + "hostname/test", + "test", + }, + { "jdbc:tc:postgresql://hostname/test", "postgresql", Optional.empty(), "hostname/test", "test" }, + { + "jdbc:tc:sqlserver:1.2.3://localhost;instance=SQLEXPRESS:1433;databaseName=test", + "sqlserver", + Optional.of("1.2.3"), + "localhost;instance=SQLEXPRESS:1433;databaseName=test", + "test", + }, + { + "jdbc:tc:sqlserver://localhost;instance=SQLEXPRESS:1433;databaseName=test", + "sqlserver", + Optional.empty(), + "localhost;instance=SQLEXPRESS:1433;databaseName=test", + "test", + }, + { + "jdbc:tc:mariadb:1.2.3://localhost:3306/test", + "mariadb", + Optional.of("1.2.3"), + "localhost:3306/test", + "test", + }, + { "jdbc:tc:mariadb://localhost:3306/test", "mariadb", Optional.empty(), "localhost:3306/test", "test" }, + { + "jdbc:tc:oracle:1.2.3:thin://@localhost:1521/test", + "oracle", + Optional.of("1.2.3"), + "localhost:1521/test", + "test", + }, + { + "jdbc:tc:oracle:1.2.3:thin:@localhost:1521/test", + "oracle", + Optional.of("1.2.3"), + "localhost:1521/test", + "test", + }, + { + "jdbc:tc:oracle:thin:@localhost:1521/test", + "oracle", + Optional.empty(), + "localhost:1521/test", + "test", + }, + { + "jdbc:tc:oracle:1.2.3:thin:@localhost:1521:test", + "oracle", + Optional.of("1.2.3"), + "localhost:1521:test", + "test", + }, + { + "jdbc:tc:oracle:1.2.3:thin://@localhost:1521:test", + "oracle", + Optional.of("1.2.3"), + "localhost:1521:test", + "test", + }, + { + "jdbc:tc:oracle:1.2.3-anything:thin://@localhost:1521:test", + "oracle", + Optional.of("1.2.3-anything"), + "localhost:1521:test", + "test", + }, + { + "jdbc:tc:oracle:thin:@localhost:1521:test", + "oracle", + Optional.empty(), + "localhost:1521:test", + "test", + }, + } + ); } @Test diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java index 4fefd5d1e13..6888f881ec4 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java @@ -13,7 +13,6 @@ public class ConnectionUrlTest { @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void testConnectionUrl1() { String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d"; @@ -31,7 +30,6 @@ public void testConnectionUrl1() { assertEquals("Parameter c is captured", "d", url.getQueryParameters().get("c")); } - @Test public void testConnectionUrl2() { String urlString = "jdbc:tc:mysql://somehostname/databasename"; @@ -46,7 +44,6 @@ public void testConnectionUrl2() { assertEquals("Database Name value is as expected", "databasename", url.getDatabaseName().get()); assertTrue("Connection Parameters set is empty", url.getQueryParameters().isEmpty()); - } @Test @@ -62,40 +59,55 @@ public void testTmpfsOption() { assertTrue("Connection Parameters set is empty", url.getQueryParameters().isEmpty()); assertFalse("Container Parameters set is not empty", url.getContainerParameters().isEmpty()); - assertEquals("Container Parameter TC_TMPFS is true", "key:value,key1:value1", url.getContainerParameters().get("TC_TMPFS")); + assertEquals( + "Container Parameter TC_TMPFS is true", + "key:value,key1:value1", + url.getContainerParameters().get("TC_TMPFS") + ); assertTrue("tmpfs option key exists", url.getTmpfsOptions().containsKey("key")); - assertEquals("tmpfs option key has correct value", "value" , url.getTmpfsOptions().get("key")); + assertEquals("tmpfs option key has correct value", "value", url.getTmpfsOptions().get("key")); assertTrue("tmpfs option key1 exists", url.getTmpfsOptions().containsKey("key1")); - assertEquals("tmpfs option key1 has correct value", "value1" , url.getTmpfsOptions().get("key1")); + assertEquals("tmpfs option key1 has correct value", "value1", url.getTmpfsOptions().get("key1")); } - @Test public void testInitScriptPathCapture() { - String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITSCRIPT=somepath/init_mysql.sql"; + String urlString = + "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITSCRIPT=somepath/init_mysql.sql"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); assertEquals("Database Type value is as expected", "somepath/init_mysql.sql", url.getInitScriptPath().get()); assertEquals("Query String value is as expected", "?a=b&c=d", url.getQueryString().get()); - assertEquals("INIT SCRIPT Path exists in Container Parameters", "somepath/init_mysql.sql", url.getContainerParameters().get("TC_INITSCRIPT")); + assertEquals( + "INIT SCRIPT Path exists in Container Parameters", + "somepath/init_mysql.sql", + url.getContainerParameters().get("TC_INITSCRIPT") + ); //Parameter sets are unmodifiable thrown.expect(UnsupportedOperationException.class); url.getContainerParameters().remove("TC_INITSCRIPT"); url.getQueryParameters().remove("a"); - } @Test public void testInitFunctionCapture() { - String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction"; + String urlString = + "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); assertTrue("Init Function parameter exists", url.getInitFunction().isPresent()); - assertEquals("Init function class is as expected", "org.testcontainers.jdbc.JDBCDriverTest", url.getInitFunction().get().getClassName()); - assertEquals("Init function class is as expected", "sampleInitFunction", url.getInitFunction().get().getMethodName()); - + assertEquals( + "Init function class is as expected", + "org.testcontainers.jdbc.JDBCDriverTest", + url.getInitFunction().get().getClassName() + ); + assertEquals( + "Init function class is as expected", + "sampleInitFunction", + url.getInitFunction().get().getMethodName() + ); } @Test @@ -104,6 +116,5 @@ public void testDaemonCapture() { ConnectionUrl url = ConnectionUrl.newInstance(urlString); assertTrue("Daemon flag is set to true.", url.isInDaemonMode()); - } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java index d33e399db27..5b4d223cd36 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java @@ -13,23 +13,22 @@ public class ContainerDatabaseDriverTest { - private static final String PLAIN_POSTGRESQL_JDBC_URL = "jdbc:postgresql://localhost:5432/test"; - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Test - public void shouldNotTryToConnectToNonMatchingJdbcUrlDirectly() throws SQLException { - ContainerDatabaseDriver driver = new ContainerDatabaseDriver(); - Connection connection = driver.connect(PLAIN_POSTGRESQL_JDBC_URL, new Properties()); - Assert.assertNull(connection); - } - - @Test - public void shouldNotTryToConnectToNonMatchingJdbcUrlViaDriverManager() throws SQLException { - thrown.expect(SQLException.class); - thrown.expectMessage(CoreMatchers.startsWith("No suitable driver found for ")); - DriverManager.getConnection(PLAIN_POSTGRESQL_JDBC_URL); - } - + private static final String PLAIN_POSTGRESQL_JDBC_URL = "jdbc:postgresql://localhost:5432/test"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void shouldNotTryToConnectToNonMatchingJdbcUrlDirectly() throws SQLException { + ContainerDatabaseDriver driver = new ContainerDatabaseDriver(); + Connection connection = driver.connect(PLAIN_POSTGRESQL_JDBC_URL, new Properties()); + Assert.assertNull(connection); + } + + @Test + public void shouldNotTryToConnectToNonMatchingJdbcUrlViaDriverManager() throws SQLException { + thrown.expect(SQLException.class); + thrown.expectMessage(CoreMatchers.startsWith("No suitable driver found for ")); + DriverManager.getConnection(PLAIN_POSTGRESQL_JDBC_URL); + } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java index 46138d91347..68afe8692e8 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java @@ -17,7 +17,6 @@ public class MissingJdbcDriverTest { @Test public void shouldFailFastIfNoDriverFound() { - final MissingDriverContainer container = new MissingDriverContainer(); try { @@ -37,6 +36,7 @@ public void shouldFailFastIfNoDriverFound() { * Container class for the purposes of testing, with a known non-existent driver */ static class MissingDriverContainer extends JdbcDatabaseContainer { + private final AtomicInteger connectionAttempts = new AtomicInteger(); MissingDriverContainer() { diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java index ef8560b3f19..a8612fc1516 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java @@ -1,22 +1,22 @@ package org.testcontainers.junit.jupiter; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.platform.commons.util.StringUtils; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.platform.commons.util.StringUtils.isBlank; +import java.nio.charset.StandardCharsets; class FilesystemFriendlyNameGenerator { + private static final String UNKNOWN_NAME = "unknown"; static String filesystemFriendlyNameOf(ExtensionContext context) { String contextId = context.getUniqueId(); try { - return (isBlank(contextId)) + return (StringUtils.isBlank(contextId)) ? UNKNOWN_NAME - : URLEncoder.encode(contextId, UTF_8.toString()); + : URLEncoder.encode(contextId, StandardCharsets.UTF_8.toString()); } catch (UnsupportedEncodingException e) { return UNKNOWN_NAME; } diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java index db8273563a7..730339f0fd5 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Testcontainers.java @@ -59,7 +59,6 @@ @ExtendWith(TestcontainersExtension.class) @Inherited public @interface Testcontainers { - /** * Whether tests should be disabled (rather than failing) when Docker is not available. */ diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java index 990940be14d..47ed56d9ac5 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java @@ -29,33 +29,38 @@ import java.util.Optional; import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.util.stream.Collectors.toList; -import static org.testcontainers.junit.jupiter.FilesystemFriendlyNameGenerator.filesystemFriendlyNameOf; - -class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition { +class TestcontainersExtension + implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition { private static final Namespace NAMESPACE = Namespace.create(TestcontainersExtension.class); private static final String SHARED_LIFECYCLE_AWARE_CONTAINERS = "sharedLifecycleAwareContainers"; + private static final String LOCAL_LIFECYCLE_AWARE_CONTAINERS = "localLifecycleAwareContainers"; @Override public void beforeAll(ExtensionContext context) { - Class testClass = context.getTestClass() - .orElseThrow(() -> new ExtensionConfigurationException("TestcontainersExtension is only supported for classes.")); + Class testClass = context + .getTestClass() + .orElseThrow(() -> { + return new ExtensionConfigurationException("TestcontainersExtension is only supported for classes."); + }); Store store = context.getStore(NAMESPACE); List sharedContainersStoreAdapters = findSharedContainers(testClass); - sharedContainersStoreAdapters.forEach(adapter -> store.getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start())); + sharedContainersStoreAdapters.forEach(adapter -> { + store.getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start()); + }); List lifecycleAwareContainers = sharedContainersStoreAdapters .stream() .filter(this::isTestLifecycleAware) .map(lifecycleAwareAdapter -> (TestLifecycleAware) lifecycleAwareAdapter.container) - .collect(toList()); + .collect(Collectors.toList()); store.put(SHARED_LIFECYCLE_AWARE_CONTAINERS, lifecycleAwareContainers); signalBeforeTestToContainers(lifecycleAwareContainers, testDescriptionFrom(context)); @@ -70,12 +75,13 @@ public void afterAll(ExtensionContext context) { public void beforeEach(final ExtensionContext context) { Store store = context.getStore(NAMESPACE); - List lifecycleAwareContainers = collectParentTestInstances(context).parallelStream() + List lifecycleAwareContainers = collectParentTestInstances(context) + .parallelStream() .flatMap(this::findRestartContainers) .peek(adapter -> store.getOrComputeIfAbsent(adapter.getKey(), k -> adapter.start())) .filter(this::isTestLifecycleAware) .map(lifecycleAwareAdapter -> (TestLifecycleAware) lifecycleAwareAdapter.container) - .collect(toList()); + .collect(Collectors.toList()); store.put(LOCAL_LIFECYCLE_AWARE_CONTAINERS, lifecycleAwareContainers); signalBeforeTestToContainers(lifecycleAwareContainers, testDescriptionFrom(context)); @@ -86,13 +92,17 @@ public void afterEach(ExtensionContext context) { signalAfterTestToContainersFor(LOCAL_LIFECYCLE_AWARE_CONTAINERS, context); } - private void signalBeforeTestToContainers(List lifecycleAwareContainers, TestDescription testDescription) { + private void signalBeforeTestToContainers( + List lifecycleAwareContainers, + TestDescription testDescription + ) { lifecycleAwareContainers.forEach(container -> container.beforeTest(testDescription)); } private void signalAfterTestToContainersFor(String storeKey, ExtensionContext context) { - List lifecycleAwareContainers = - (List) context.getStore(NAMESPACE).get(storeKey); + List lifecycleAwareContainers = (List) context + .getStore(NAMESPACE) + .get(storeKey); if (lifecycleAwareContainers != null) { TestDescription description = testDescriptionFrom(context); Optional throwable = context.getExecutionException(); @@ -103,7 +113,7 @@ private void signalAfterTestToContainersFor(String storeKey, ExtensionContext co private TestDescription testDescriptionFrom(ExtensionContext context) { return new TestcontainersTestDescription( context.getUniqueId(), - filesystemFriendlyNameOf(context) + FilesystemFriendlyNameGenerator.filesystemFriendlyNameOf(context) ); } @@ -113,14 +123,18 @@ private boolean isTestLifecycleAware(StoreAdapter adapter) { @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { - return findTestcontainers(context).map(this::evaluate) + return findTestcontainers(context) + .map(this::evaluate) .orElseThrow(() -> new ExtensionConfigurationException("@Testcontainers not found")); } private Optional findTestcontainers(ExtensionContext context) { Optional current = Optional.of(context); while (current.isPresent()) { - Optional testcontainers = AnnotationUtils.findAnnotation(current.get().getRequiredTestClass(), Testcontainers.class); + Optional testcontainers = AnnotationUtils.findAnnotation( + current.get().getRequiredTestClass(), + Testcontainers.class + ); if (testcontainers.isPresent()) { return testcontainers; } @@ -155,13 +169,11 @@ private Set collectParentTestInstances(final ExtensionContext context) { } private List findSharedContainers(Class testClass) { - return ReflectionUtils.findFields( - testClass, - isSharedContainer(), - ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) + return ReflectionUtils + .findFields(testClass, isSharedContainer(), ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) .stream() .map(f -> getContainerInstance(null, f)) - .collect(toList()); + .collect(Collectors.toList()); } private Predicate isSharedContainer() { @@ -169,10 +181,8 @@ private Predicate isSharedContainer() { } private Stream findRestartContainers(Object testInstance) { - return ReflectionUtils.findFields( - testInstance.getClass(), - isRestartContainer(), - ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) + return ReflectionUtils + .findFields(testInstance.getClass(), isRestartContainer(), ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) .stream() .map(f -> getContainerInstance(testInstance, f)); } @@ -188,7 +198,9 @@ private static Predicate isContainer() { boolean isStartable = Startable.class.isAssignableFrom(field.getType()); if (!isStartable) { - throw new ExtensionConfigurationException(String.format("FieldName: %s does not implement Startable", field.getName())); + throw new ExtensionConfigurationException( + String.format("FieldName: %s does not implement Startable", field.getName()) + ); } return true; } @@ -199,7 +211,10 @@ private static Predicate isContainer() { private static StoreAdapter getContainerInstance(final Object testInstance, final Field field) { try { field.setAccessible(true); - Startable containerInstance = Preconditions.notNull((Startable) field.get(testInstance), "Container " + field.getName() + " needs to be initialized"); + Startable containerInstance = Preconditions.notNull( + (Startable) field.get(testInstance), + "Container " + field.getName() + " needs to be initialized" + ); return new StoreAdapter(field.getDeclaringClass(), field.getName(), containerInstance); } catch (IllegalAccessException e) { throw new ExtensionConfigurationException("Can not access container defined in field " + field.getName()); diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersTestDescription.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersTestDescription.java index 568d228e08c..3cf466a5708 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersTestDescription.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersTestDescription.java @@ -5,6 +5,8 @@ @Value class TestcontainersTestDescription implements TestDescription { + String testId; + String filesystemFriendlyName; } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java index 11b9027b392..f49aa8732f5 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java @@ -18,7 +18,8 @@ class ComposeContainerTests { @Container private DockerComposeContainer composeContainer = new DockerComposeContainer( - new File("src/test/resources/docker-compose.yml")) + new File("src/test/resources/docker-compose.yml") + ) .withExposedService("whoami_1", 80, Wait.forHttp("/")); private String host; diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java index 96617b0e063..9050df6f257 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGeneratorTest.java @@ -10,7 +10,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.testcontainers.junit.jupiter.FilesystemFriendlyNameGenerator.filesystemFriendlyNameOf; class FilesystemFriendlyNameGeneratorTest { @@ -18,10 +17,9 @@ class FilesystemFriendlyNameGeneratorTest { @MethodSource("provideDisplayNamesAndFilesystemFriendlyNames") void should_generate_filesystem_friendly_name(String displayName, String expectedName) { ExtensionContext context = mock(ExtensionContext.class); - doReturn(displayName) - .when(context).getUniqueId(); + doReturn(displayName).when(context).getUniqueId(); - String filesystemFriendlyName = filesystemFriendlyNameOf(context); + String filesystemFriendlyName = FilesystemFriendlyNameGenerator.filesystemFriendlyNameOf(context); assertThat(filesystemFriendlyName).isEqualTo(expectedName); } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java index 791c887cc19..6c44d978b69 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java @@ -1,19 +1,11 @@ package org.testcontainers.junit.jupiter; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.HttpClientBuilder; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.containers.wait.strategy.Wait; import static org.junit.jupiter.api.Assertions.assertTrue; - // testClass { @Testcontainers class MixedLifecycleTests { diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java index 4cbc331e64b..186d4095b0d 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java @@ -9,16 +9,17 @@ import java.sql.Statement; import static org.junit.Assert.assertEquals; -import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.POSTGRES_IMAGE; @Testcontainers class PostgresContainerTests { @Container - private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = new PostgreSQLContainer<>(POSTGRES_IMAGE) - .withDatabaseName("foo") - .withUsername("foo") - .withPassword("secret"); + private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = new PostgreSQLContainer<>( + JUnitJupiterTestImages.POSTGRES_IMAGE + ) + .withDatabaseName("foo") + .withUsername("foo") + .withPassword("secret"); @Test void waits_until_postgres_accepts_jdbc_connections() throws Exception { @@ -37,5 +38,4 @@ void waits_until_postgres_accepts_jdbc_connections() throws Exception { assertEquals(1, resultSetInt); } } - } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java index 38751c8789a..a8217d60840 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareContainerMock.java @@ -11,9 +11,11 @@ public class TestLifecycleAwareContainerMock implements Startable, TestLifecycleAware { static final String BEFORE_TEST = "beforeTest"; + static final String AFTER_TEST = "afterTest"; private final List lifecycleMethodCalls = new ArrayList<>(); + private final List lifecycleFilesystemFriendlyNames = new ArrayList<>(); private Throwable capturedThrowable; @@ -43,12 +45,8 @@ public List getLifecycleFilesystemFriendlyNames() { } @Override - public void start() { - - } + public void start() {} @Override - public void stop() { - - } + public void stop() {} } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java index 85d837a7880..09b816be56e 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java @@ -14,6 +14,7 @@ @Testcontainers @TestMethodOrder(OrderAnnotation.class) class TestLifecycleAwareExceptionCapturingTest { + @Container private final TestLifecycleAwareContainerMock testContainer = new TestLifecycleAwareContainerMock(); diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java index cecdff490ef..a77242e1d3a 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareMethodTest.java @@ -10,14 +10,13 @@ import org.junit.jupiter.api.extension.ExtensionContext; import static org.assertj.core.api.Assertions.assertThat; -import static org.testcontainers.junit.jupiter.TestLifecycleAwareContainerMock.AFTER_TEST; -import static org.testcontainers.junit.jupiter.TestLifecycleAwareContainerMock.BEFORE_TEST; // The order of @ExtendsWith and @Testcontainers is crucial for the tests -@ExtendWith({TestLifecycleAwareMethodTest.SharedContainerAfterAllTestExtension.class}) +@ExtendWith({ TestLifecycleAwareMethodTest.SharedContainerAfterAllTestExtension.class }) @Testcontainers @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class TestLifecycleAwareMethodTest { + @Container private final TestLifecycleAwareContainerMock testContainer = new TestLifecycleAwareContainerMock(); @@ -28,8 +27,8 @@ class TestLifecycleAwareMethodTest { @BeforeAll static void beforeAll() { - assertThat(SHARED_CONTAINER.getLifecycleMethodCalls()).containsExactly(BEFORE_TEST); - + assertThat(SHARED_CONTAINER.getLifecycleMethodCalls()) + .containsExactly(TestLifecycleAwareContainerMock.BEFORE_TEST); } @Test @@ -43,7 +42,7 @@ void should_prepare_before_and_after_test() { @Order(2) void should_call_beforeTest_first_afterTest_later_with_filesystem_friendly_name() { assertThat(startedTestContainer.getLifecycleMethodCalls()) - .containsExactly(BEFORE_TEST, AFTER_TEST); + .containsExactly(TestLifecycleAwareContainerMock.BEFORE_TEST, TestLifecycleAwareContainerMock.AFTER_TEST); } @Test @@ -63,11 +62,15 @@ void static_container_should_have_a_filesystem_friendly_name_after_container_has } static class SharedContainerAfterAllTestExtension implements AfterAllCallback { + // Unfortunately it's not possible to write a @Test that is run after all tests @Override public void afterAll(ExtensionContext context) { assertThat(SHARED_CONTAINER.getLifecycleMethodCalls()) - .containsExactly(BEFORE_TEST, AFTER_TEST); + .containsExactly( + TestLifecycleAwareContainerMock.BEFORE_TEST, + TestLifecycleAwareContainerMock.AFTER_TEST + ); } } } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java index f3aea9bb850..526038853c9 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java @@ -46,14 +46,10 @@ private ExtensionContext extensionContext(Class clazz) { } @Testcontainers(disabledWithoutDocker = true) - static final class DisabledWithoutDocker { - - } + static final class DisabledWithoutDocker {} @Testcontainers - static final class EnabledWithoutDocker { - - } + static final class EnabledWithoutDocker {} static final class TestTestcontainersExtension extends TestcontainersExtension { @@ -66,7 +62,5 @@ private TestTestcontainersExtension(boolean dockerAvailable) { boolean isDockerAvailable() { return dockerAvailable; } - } - } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java index 6e02e31b774..c41b184defa 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java @@ -6,15 +6,15 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; // testClass { @Testcontainers class TestcontainersNestedRestartedContainerTests { @Container - private final GenericContainer topLevelContainer = new GenericContainer<>(HTTPD_IMAGE) + private final GenericContainer topLevelContainer = new GenericContainer<>(JUnitJupiterTestImages.HTTPD_IMAGE) .withExposedPorts(80); + // }} private static String topLevelContainerId; @@ -25,16 +25,16 @@ class TestcontainersNestedRestartedContainerTests { @Test void top_level_container_should_be_running() { assertTrue(topLevelContainer.isRunning()); -// }} + // }} topLevelContainerId = topLevelContainer.getContainerId(); -// testClass {{ + // testClass {{ } @Nested class NestedTestCase { @Container - private final GenericContainer nestedContainer = new GenericContainer<>(HTTPD_IMAGE) + private final GenericContainer nestedContainer = new GenericContainer<>(JUnitJupiterTestImages.HTTPD_IMAGE) .withExposedPorts(80); @Test @@ -43,13 +43,13 @@ void both_containers_should_be_running() { assertTrue(topLevelContainer.isRunning()); // nested containers are only available inside their nested class assertTrue(nestedContainer.isRunning()); -// }}} + // }}} if (nestedContainerId == null) { nestedContainerId = nestedContainer.getContainerId(); } else { assertNotEquals(nestedContainerId, nestedContainer.getContainerId()); } -// testClass {{ + // testClass {{ } // } @@ -74,7 +74,7 @@ void ids_should_not_change() { assertNotEquals(nestedContainerId, nestedContainer.getContainerId()); } } -// testClass {{{ + // testClass {{{ } } // } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java index cf59e0338a2..c00e66c2d9d 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java @@ -6,13 +6,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; @Testcontainers class TestcontainersNestedSharedContainerTests { @Container - private static final GenericContainer TOP_LEVEL_CONTAINER = new GenericContainer<>(HTTPD_IMAGE) + private static final GenericContainer TOP_LEVEL_CONTAINER = new GenericContainer<>( + JUnitJupiterTestImages.HTTPD_IMAGE + ) .withExposedPorts(80); private static String topLevelContainerId; diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java index eeb63b72380..46c6045984f 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java @@ -4,14 +4,13 @@ import org.testcontainers.containers.GenericContainer; import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; @Testcontainers class TestcontainersRestartBetweenTests { @Container - private GenericContainer genericContainer = new GenericContainer<>(HTTPD_IMAGE) - .withExposedPorts(80); + private GenericContainer genericContainer = new GenericContainer<>(JUnitJupiterTestImages.HTTPD_IMAGE) + .withExposedPorts(80); private static String lastContainerId; @@ -19,7 +18,7 @@ class TestcontainersRestartBetweenTests { void first_test() { if (lastContainerId == null) { lastContainerId = genericContainer.getContainerId(); - } else { + } else { assertNotEquals(lastContainerId, genericContainer.getContainerId()); } } @@ -28,9 +27,8 @@ void first_test() { void second_test() { if (lastContainerId == null) { lastContainerId = genericContainer.getContainerId(); - } else { + } else { assertNotEquals(lastContainerId, genericContainer.getContainerId()); } } - } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java index 60094994f69..b23b2fe0e53 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java @@ -6,13 +6,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.testcontainers.junit.jupiter.JUnitJupiterTestImages.HTTPD_IMAGE; @Testcontainers class TestcontainersSharedContainerTests { @Container - private static final GenericContainer GENERIC_CONTAINER = new GenericContainer<>(HTTPD_IMAGE) + private static final GenericContainer GENERIC_CONTAINER = new GenericContainer<>( + JUnitJupiterTestImages.HTTPD_IMAGE + ) .withExposedPorts(80); private static String lastContainerId; @@ -39,5 +40,4 @@ void second_test() { assertEquals(lastContainerId, GENERIC_CONTAINER.getContainerId()); } } - } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/WrongAnnotationUsageTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/WrongAnnotationUsageTests.java index bec99894307..9fe9893d9ee 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/WrongAnnotationUsageTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/WrongAnnotationUsageTests.java @@ -1,10 +1,8 @@ package org.testcontainers.junit.jupiter; - import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; - @Disabled @Testcontainers class WrongAnnotationUsageTests { @@ -16,5 +14,4 @@ class WrongAnnotationUsageTests { void extension_throws_exception() { assert true; } - } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java index 3766c3f7a60..70614d3dbc7 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/AbstractTestBase.java @@ -11,5 +11,4 @@ abstract class AbstractTestBase { @Container RedisContainer redisPerTest = new RedisContainer(); - } diff --git a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java index 7f21ca7dbb8..c9dad93a06e 100644 --- a/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java +++ b/modules/k3s/src/main/java/org/testcontainers/k3s/K3sContainer.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.node.TextNode; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.github.dockerjava.api.command.InspectContainerResponse; -import com.github.dockerjava.api.model.DockerObjectAccessor; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; import org.testcontainers.containers.BindMode; @@ -42,17 +41,14 @@ public K3sContainer(DockerImageName dockerImageName) { tmpFsMapping.put("/var/run", ""); setTmpFsMapping(tmpFsMapping); - setCommand( - "server", - "--no-deploy=traefik", - "--tls-san=" + this.getHost() - ); + setCommand("server", "--no-deploy=traefik", "--tls-san=" + this.getHost()); setWaitStrategy(new LogMessageWaitStrategy().withRegEx(".*Node controller sync successful.*")); } @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { - String rawKubeConfig = copyFileFromContainer("/etc/rancher/k3s/k3s.yaml", + String rawKubeConfig = copyFileFromContainer( + "/etc/rancher/k3s/k3s.yaml", is -> IOUtils.toString(is, StandardCharsets.UTF_8) ); String serverUrl = "https://" + this.getHost() + ":" + this.getMappedPort(KUBE_SECURE_PORT); @@ -100,7 +96,6 @@ private String kubeConfigWithServerUrl(String kubeConfigYaml, String serverUrl) kubeConfigObjectNode.set("current-context", new TextNode("default")); - return objectMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(kubeConfigObjectNode); + return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(kubeConfigObjectNode); } } diff --git a/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java index 8b31c299634..6f9550eab2a 100644 --- a/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java +++ b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java @@ -10,19 +10,17 @@ import io.fabric8.kubernetes.api.model.ProbeBuilder; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.DefaultKubernetesClient; -import io.fabric8.kubernetes.client.dsl.PodResource; import io.fabric8.kubernetes.client.dsl.Readiable; import lombok.extern.slf4j.Slf4j; -import org.assertj.core.api.Assertions; -import org.assertj.core.api.Condition; import org.junit.Test; import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.utility.DockerImageName; import java.util.List; -import java.util.Map; import java.util.concurrent.TimeUnit; +import static org.assertj.core.api.Assertions.assertThat; + @Slf4j public class Fabric8K3sContainerTest { @@ -49,14 +47,14 @@ public void shouldStartAndHaveListableNode() { List nodes = client.nodes().list().getItems(); // } - Assertions.assertThat(nodes).hasSize(1); + assertThat(nodes).hasSize(1); // verify that we can start a pod Pod helloworld = dummyStartablePod(); client.pods().create(helloworld); client.pods().inNamespace("default").withName("helloworld").waitUntilReady(30, TimeUnit.SECONDS); - Assertions.assertThat(client.pods().inNamespace("default").withName("helloworld")) + assertThat(client.pods().inNamespace("default").withName("helloworld")) .extracting(Readiable::isReady) .isEqualTo(true); } diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 8b1128efef0..02342351b83 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -11,6 +11,7 @@ public class KafkaContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("confluentinc/cp-kafka"); + private static final String DEFAULT_TAG = "5.4.3"; public static final int KAFKA_PORT = 9093; @@ -39,7 +40,6 @@ public KafkaContainer(String confluentPlatformVersion) { public KafkaContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(KAFKA_PORT); @@ -77,12 +77,7 @@ public String getBootstrapServers() { protected void configure() { withEnv( "KAFKA_ADVERTISED_LISTENERS", - String.format( - "BROKER://%s:9092", - getNetwork() != null - ? getNetworkAliases().get(0) - : "localhost" - ) + String.format("BROKER://%s:9092", getNetwork() != null ? getNetworkAliases().get(0) : "localhost") ); String command = "#!/bin/bash\n"; @@ -111,9 +106,12 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { ExecResult result = execInContainer( "kafka-configs", "--alter", - "--bootstrap-server", brokerAdvertisedListener, - "--entity-type", "brokers", - "--entity-name", getEnvMap().get("KAFKA_BROKER_ID"), + "--bootstrap-server", + brokerAdvertisedListener, + "--entity-type", + "brokers", + "--entity-name", + getEnvMap().get("KAFKA_BROKER_ID"), "--add-config", "advertised.listeners=[" + String.join(",", getBootstrapServers(), brokerAdvertisedListener) + "]" ); diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index f0ef0db2067..380df00e9e9 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -20,17 +20,20 @@ import java.time.Duration; import java.util.Collection; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeUnit; -import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; public class KafkaContainerTest { private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:6.2.1"); - private static final DockerImageName ZOOKEEPER_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-zookeeper:4.0.0"); + + private static final DockerImageName ZOOKEEPER_TEST_IMAGE = DockerImageName.parse( + "confluentinc/cp-zookeeper:4.0.0" + ); @Test public void testUsage() throws Exception { @@ -40,7 +43,6 @@ public void testUsage() throws Exception { } } - @Test public void testUsageWithSpecificImage() throws Exception { try ( @@ -50,18 +52,16 @@ public void testUsageWithSpecificImage() throws Exception { ) { kafka.start(); testKafkaFunctionality( - // getBootstrapServers { - kafka.getBootstrapServers() - // } + // getBootstrapServers { + kafka.getBootstrapServers() + // } ); } } @Test public void testUsageWithVersion() throws Exception { - try ( - KafkaContainer kafka = new KafkaContainer("6.2.1") - ) { + try (KafkaContainer kafka = new KafkaContainer("6.2.1")) { kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); } @@ -71,7 +71,6 @@ public void testUsageWithVersion() throws Exception { public void testExternalZookeeperWithExternalNetwork() throws Exception { try ( Network network = Network.newNetwork(); - // withExternalZookeeper { KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE) .withNetwork(network) @@ -82,11 +81,10 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { .withNetwork(network) .withNetworkAliases("zookeeper") .withEnv("ZOOKEEPER_CLIENT_PORT", "2181"); - // withKafkaNetwork { GenericContainer application = new GenericContainer<>(DockerImageName.parse("alpine")) .withNetwork(network) - // } + // } .withNetworkAliases("dummy") .withCommand("sleep 10000") ) { @@ -100,9 +98,7 @@ public void testExternalZookeeperWithExternalNetwork() throws Exception { @Test public void testConfluentPlatformVersion5() throws Exception { - try ( - KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3")) - ) { + try (KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3"))) { kafka.start(); testKafkaFunctionality(kafka.getBootstrapServers()); } @@ -132,24 +128,27 @@ protected void testKafkaFunctionality(String bootstrapServers) throws Exception protected void testKafkaFunctionality(String bootstrapServers, int partitions, int rf) throws Exception { try ( - AdminClient adminClient = AdminClient.create(ImmutableMap.of( - AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers - )); - + AdminClient adminClient = AdminClient.create( + ImmutableMap.of(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers) + ); KafkaProducer producer = new KafkaProducer<>( ImmutableMap.of( - ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, - ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString() + ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ProducerConfig.CLIENT_ID_CONFIG, + UUID.randomUUID().toString() ), new StringSerializer(), new StringSerializer() ); - KafkaConsumer consumer = new KafkaConsumer<>( ImmutableMap.of( - ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, - ConsumerConfig.GROUP_ID_CONFIG, "tc-" + UUID.randomUUID(), - ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest" + ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ConsumerConfig.GROUP_ID_CONFIG, + "tc-" + UUID.randomUUID(), + ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, + "earliest" ), new StringDeserializer(), new StringDeserializer() @@ -157,30 +156,33 @@ protected void testKafkaFunctionality(String bootstrapServers, int partitions, i ) { String topicName = "messages-" + UUID.randomUUID(); - Collection topics = singletonList(new NewTopic(topicName, partitions, (short) rf)); + Collection topics = Collections.singletonList(new NewTopic(topicName, partitions, (short) rf)); adminClient.createTopics(topics).all().get(30, TimeUnit.SECONDS); - consumer.subscribe(singletonList(topicName)); + consumer.subscribe(Collections.singletonList(topicName)); producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); - Unreliables.retryUntilTrue(10, TimeUnit.SECONDS, () -> { - ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + Unreliables.retryUntilTrue( + 10, + TimeUnit.SECONDS, + () -> { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); - if (records.isEmpty()) { - return false; - } + if (records.isEmpty()) { + return false; + } - assertThat(records) - .hasSize(1) - .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) - .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + assertThat(records) + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); - return true; - }); + return true; + } + ); consumer.unsubscribe(); } } - } diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index dd03a4206e0..8bd6f14d3fd 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -36,10 +36,13 @@ public class LocalStackContainer extends GenericContainer { static final int PORT = 4566; + private static final String HOSTNAME_EXTERNAL_ENV_VAR = "HOSTNAME_EXTERNAL"; + private final List services = new ArrayList<>(); private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("localstack/localstack"); + private static final String DEFAULT_TAG = "0.11.2"; @Deprecated @@ -88,7 +91,6 @@ public LocalStackContainer(final DockerImageName dockerImageName) { */ public LocalStackContainer(final DockerImageName dockerImageName, boolean useLegacyMode) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); this.legacyMode = useLegacyMode; @@ -109,7 +111,9 @@ private static boolean shouldRunInLegacyMode(String version) { } log.warn("Version {} is not a semantic version, LocalStack will run in legacy mode.", version); - log.warn("Consider using \"LocalStackContainer(DockerImageName dockerImageName, boolean legacyMode)\" constructor if you want to disable legacy mode."); + log.warn( + "Consider using \"LocalStackContainer(DockerImageName dockerImageName, boolean legacyMode)\" constructor if you want to disable legacy mode." + ); return true; } @@ -126,22 +130,25 @@ protected void configure() { // do nothing hostnameExternalReason = "explicitly as environment variable"; } else if (getNetwork() != null && getNetworkAliases() != null && getNetworkAliases().size() >= 1) { - withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getNetworkAliases().get(getNetworkAliases().size() - 1)); // use the last network alias set + withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getNetworkAliases().get(getNetworkAliases().size() - 1)); // use the last network alias set hostnameExternalReason = "to match last network alias on container with non-default network"; } else { withEnv(HOSTNAME_EXTERNAL_ENV_VAR, getHost()); hostnameExternalReason = "to match host-routable address for container"; } - logger().info("{} environment variable set to {} ({})", HOSTNAME_EXTERNAL_ENV_VAR, getEnvMap().get(HOSTNAME_EXTERNAL_ENV_VAR), hostnameExternalReason); + logger() + .info( + "{} environment variable set to {} ({})", + HOSTNAME_EXTERNAL_ENV_VAR, + getEnvMap().get(HOSTNAME_EXTERNAL_ENV_VAR), + hostnameExternalReason + ); exposePorts(); } private void exposePorts() { - services.stream() - .map(this::getServicePort) - .distinct() - .forEach(this::addExposedPort); + services.stream().map(this::getServicePort).distinct().forEach(this::addExposedPort); } public LocalStackContainer withServices(Service... services) { @@ -218,10 +225,7 @@ public URI getEndpointOverride(EnabledService service) { String ipAddress = address; // resolve IP address and use that as the endpoint so that path-style access is automatically used for S3 ipAddress = InetAddress.getByName(address).getHostAddress(); - return new URI("http://" + - ipAddress + - ":" + - getMappedPort(getServicePort(service))); + return new URI("http://" + ipAddress + ":" + getMappedPort(getServicePort(service))); } catch (UnknownHostException | URISyntaxException e) { throw new IllegalStateException("Cannot obtain endpoint URL", e); } @@ -332,7 +336,7 @@ public enum Service implements EnabledService { DYNAMODB("dynamodb", 4569), DYNAMODB_STREAMS("dynamodbstreams", 4570), // TODO: Clarify usage for ELASTICSEARCH and ELASTICSEARCH_SERVICE -// ELASTICSEARCH("es", 4571), + // ELASTICSEARCH("es", 4571), S3("s3", 4572), FIREHOSE("firehose", 4573), LAMBDA("lambda", 4574), diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java index b34f43f79ed..a757c11e928 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java @@ -16,48 +16,51 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; -import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_10_IMAGE; -import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_11_IMAGE; -import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_12_IMAGE; -import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_0_7_IMAGE; -import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_IMAGE; @RunWith(Enclosed.class) public class LegacyModeTest { - private static DockerImageName LOCALSTACK_CUSTOM_TAG = LOCALSTACK_IMAGE.withTag("custom"); + + private static DockerImageName LOCALSTACK_CUSTOM_TAG = LocalstackTestImages.LOCALSTACK_IMAGE.withTag("custom"); @RunWith(Parameterized.class) @AllArgsConstructor public static class Off { + private final String description; + private final LocalStackContainer localstack; @Parameterized.Parameters(name = "{0}") public static Iterable constructors() { - return Arrays.asList(new Object[][]{ - {"0.12", new LocalStackContainer(LOCALSTACK_0_12_IMAGE)}, - {"0.11", new LocalStackContainer(LOCALSTACK_0_11_IMAGE)}, - {"0.7 with legacy = off", new LocalStackContainer(LOCALSTACK_0_7_IMAGE, false)} - }); + return Arrays.asList( + new Object[][] { + { "0.12", new LocalStackContainer(LocalstackTestImages.LOCALSTACK_0_12_IMAGE) }, + { "0.11", new LocalStackContainer(LocalstackTestImages.LOCALSTACK_0_11_IMAGE) }, + { + "0.7 with legacy = off", + new LocalStackContainer(LocalstackTestImages.LOCALSTACK_0_7_IMAGE, false), + }, + } + ); } @Test public void samePortIsExposedForAllServices() { - localstack.withServices(S3, SQS); + localstack.withServices(LocalStackContainer.Service.S3, LocalStackContainer.Service.SQS); localstack.start(); try { assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); assertEquals( "Endpoint overrides are different", - localstack.getEndpointOverride(S3).toString(), - localstack.getEndpointOverride(SQS).toString()); + localstack.getEndpointOverride(LocalStackContainer.Service.S3).toString(), + localstack.getEndpointOverride(LocalStackContainer.Service.SQS).toString() + ); assertEquals( "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + localstack.getEndpointConfiguration(LocalStackContainer.Service.S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(LocalStackContainer.Service.SQS).getServiceEndpoint() + ); } finally { localstack.stop(); } @@ -67,7 +70,9 @@ public void samePortIsExposedForAllServices() { @RunWith(Parameterized.class) @AllArgsConstructor public static class On { + private final String description; + private final LocalStackContainer localstack; @BeforeClass @@ -75,7 +80,7 @@ public static void createCustomTag() { DockerClient dockerClient = DockerClientFactory.instance().client(); dockerClient .tagImageCmd( - new RemoteDockerImage(LOCALSTACK_0_12_IMAGE).get(), + new RemoteDockerImage(LocalstackTestImages.LOCALSTACK_0_12_IMAGE).get(), LOCALSTACK_CUSTOM_TAG.getRepository(), LOCALSTACK_CUSTOM_TAG.getVersionPart() ) @@ -84,28 +89,35 @@ public static void createCustomTag() { @Parameterized.Parameters(name = "{0}") public static Iterable constructors() { - return Arrays.asList(new Object[][]{ - {"0.10", new LocalStackContainer(LOCALSTACK_0_10_IMAGE)}, - {"custom", new LocalStackContainer(LOCALSTACK_CUSTOM_TAG)}, - {"0.11 with legacy = on", new LocalStackContainer(LOCALSTACK_0_11_IMAGE, true)} - }); + return Arrays.asList( + new Object[][] { + { "0.10", new LocalStackContainer(LocalstackTestImages.LOCALSTACK_0_10_IMAGE) }, + { "custom", new LocalStackContainer(LOCALSTACK_CUSTOM_TAG) }, + { + "0.11 with legacy = on", + new LocalStackContainer(LocalstackTestImages.LOCALSTACK_0_11_IMAGE, true), + }, + } + ); } @Test public void differentPortsAreExposed() { - localstack.withServices(S3, SQS); + localstack.withServices(LocalStackContainer.Service.S3, LocalStackContainer.Service.SQS); localstack.start(); try { assertTrue("Multiple ports are exposed", localstack.getExposedPorts().size() > 1); assertNotEquals( "Endpoint overrides are different", - localstack.getEndpointOverride(S3).toString(), - localstack.getEndpointOverride(SQS).toString()); + localstack.getEndpointOverride(LocalStackContainer.Service.S3).toString(), + localstack.getEndpointOverride(LocalStackContainer.Service.SQS).toString() + ); assertNotEquals( "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + localstack.getEndpointConfiguration(LocalStackContainer.Service.S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(LocalStackContainer.Service.SQS).getServiceEndpoint() + ); } finally { localstack.stop(); } diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index 6b32ba2c102..cf4e1a813a4 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -1,17 +1,5 @@ package org.testcontainers.containers.localstack; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.containers.localstack.LocalStackContainer.PORT; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCHLOGS; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.KMS; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; -import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS; -import static org.testcontainers.containers.localstack.LocalstackTestImages.LOCALSTACK_IMAGE; - import com.amazonaws.services.kms.AWSKMS; import com.amazonaws.services.kms.AWSKMSClientBuilder; import com.amazonaws.services.kms.model.CreateKeyRequest; @@ -29,10 +17,6 @@ import com.amazonaws.services.sqs.AmazonSQS; import com.amazonaws.services.sqs.AmazonSQSClientBuilder; import com.amazonaws.services.sqs.model.CreateQueueResult; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.List; -import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.junit.Assert; @@ -44,12 +28,22 @@ import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.Network; -import org.testcontainers.utility.DockerImageName; +import org.testcontainers.containers.localstack.LocalStackContainer.Service; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.Matchers.containsString; +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; + /** * Tests for Localstack Container, used both in bridge network (exposed to host) and docker network modes. *

@@ -65,15 +59,22 @@ public static class WithoutNetwork { // without_network { @ClassRule - public static LocalStackContainer localstack = new LocalStackContainer(LOCALSTACK_IMAGE) - .withServices(S3, SQS, CLOUDWATCHLOGS, KMS, LocalStackContainer.EnabledService.named("events")); + public static LocalStackContainer localstack = new LocalStackContainer(LocalstackTestImages.LOCALSTACK_IMAGE) + .withServices( + Service.S3, + Service.SQS, + Service.CLOUDWATCHLOGS, + Service.KMS, + LocalStackContainer.EnabledService.named("events") + ); + // } @Test public void s3TestOverBridgeNetwork() throws IOException { AmazonS3 s3 = AmazonS3ClientBuilder .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) + .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.S3)) .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); @@ -82,7 +83,10 @@ public void s3TestOverBridgeNetwork() throws IOException { s3.putObject(bucketName, "bar", "baz"); final List buckets = s3.listBuckets(); - final Optional maybeBucket = buckets.stream().filter(b -> b.getName().equals(bucketName)).findFirst(); + final Optional maybeBucket = buckets + .stream() + .filter(b -> b.getName().equals(bucketName)) + .findFirst(); assertTrue("The created bucket is present", maybeBucket.isPresent()); final Bucket bucket = maybeBucket.get(); @@ -100,32 +104,49 @@ public void s3TestOverBridgeNetwork() throws IOException { public void s3TestUsingAwsSdkV2() { S3Client s3 = S3Client .builder() - .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3)) - .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create( - localstack.getAccessKey(), localstack.getSecretKey() - ))) + .endpointOverride(localstack.getEndpointOverride(Service.S3)) + .credentialsProvider( + StaticCredentialsProvider.create( + AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey()) + ) + ) .region(Region.of(localstack.getRegion())) .build(); final String bucketName = "foov2"; s3.createBucket(b -> b.bucket(bucketName)); - assertTrue("New bucket was created", s3.listBuckets().buckets().stream().anyMatch(b -> b.name().equals(bucketName))); + assertTrue( + "New bucket was created", + s3.listBuckets().buckets().stream().anyMatch(b -> b.name().equals(bucketName)) + ); } @Test public void sqsTestOverBridgeNetwork() { - AmazonSQS sqs = AmazonSQSClientBuilder.standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(SQS)) + AmazonSQS sqs = AmazonSQSClientBuilder + .standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.SQS)) .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); CreateQueueResult queueResult = sqs.createQueue("baz"); String fooQueueUrl = queueResult.getQueueUrl(); - assertThat("Created queue has external hostname URL", fooQueueUrl, - containsString("http://" + DockerClientFactory.instance().dockerHostIpAddress() + ":" + localstack.getMappedPort(PORT))); + assertThat( + "Created queue has external hostname URL", + fooQueueUrl, + containsString( + "http://" + + DockerClientFactory.instance().dockerHostIpAddress() + + ":" + + localstack.getMappedPort(LocalStackContainer.PORT) + ) + ); sqs.sendMessage(fooQueueUrl, "test"); - final long messageCount = sqs.receiveMessage(fooQueueUrl).getMessages().stream() + final long messageCount = sqs + .receiveMessage(fooQueueUrl) + .getMessages() + .stream() .filter(message -> message.getBody().equals("test")) .count(); assertEquals("the sent message can be received", 1L, messageCount); @@ -133,9 +154,11 @@ public void sqsTestOverBridgeNetwork() { @Test public void cloudWatchLogsTestOverBridgeNetwork() { - AWSLogs logs = AWSLogsClientBuilder.standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(CLOUDWATCHLOGS)) - .withCredentials(localstack.getDefaultCredentialsProvider()).build(); + AWSLogs logs = AWSLogsClientBuilder + .standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.CLOUDWATCHLOGS)) + .withCredentials(localstack.getDefaultCredentialsProvider()) + .build(); logs.createLogGroup(new CreateLogGroupRequest("foo")); @@ -146,8 +169,9 @@ public void cloudWatchLogsTestOverBridgeNetwork() { @Test public void kmsKeyCreationTest() { - AWSKMS awskms = AWSKMSClientBuilder.standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(KMS)) + AWSKMS awskms = AWSKMSClientBuilder + .standard() + .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.KMS)) .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); @@ -156,7 +180,11 @@ public void kmsKeyCreationTest() { CreateKeyRequest req = new CreateKeyRequest().withDescription(desc).withTags(createdByTag); CreateKeyResult key = awskms.createKey(req); - assertEquals("AWS KMS Customer Managed Key should be created ", key.getKeyMetadata().getDescription(), desc); + assertEquals( + "AWS KMS Customer Managed Key should be created ", + key.getKeyMetadata().getDescription(), + desc + ); } @Test @@ -164,35 +192,42 @@ public void samePortIsExposedForAllServices() { assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); assertEquals( "Endpoint overrides are different", - localstack.getEndpointOverride(S3).toString(), - localstack.getEndpointOverride(SQS).toString()); + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getEndpointOverride(Service.SQS).toString() + ); assertEquals( "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(SQS).getServiceEndpoint()); + localstack.getEndpointConfiguration(Service.S3).getServiceEndpoint(), + localstack.getEndpointConfiguration(Service.SQS).getServiceEndpoint() + ); } } public static class WithNetwork { + // with_network { private static Network network = Network.newNetwork(); @ClassRule - public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer(LOCALSTACK_IMAGE) + public static LocalStackContainer localstackInDockerNetwork = new LocalStackContainer( + LocalstackTestImages.LOCALSTACK_IMAGE + ) .withNetwork(network) - .withNetworkAliases("notthis", "localstack") // the last alias is used for HOSTNAME_EXTERNAL - .withServices(S3, SQS, CLOUDWATCHLOGS); + .withNetworkAliases("notthis", "localstack") // the last alias is used for HOSTNAME_EXTERNAL + .withServices(Service.S3, Service.SQS, Service.CLOUDWATCHLOGS); + // } @ClassRule - public static GenericContainer awsCliInDockerNetwork = new GenericContainer<>(LocalstackTestImages.AWS_CLI_IMAGE) + public static GenericContainer awsCliInDockerNetwork = new GenericContainer<>( + LocalstackTestImages.AWS_CLI_IMAGE + ) .withNetwork(network) .withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("top")) .withEnv("AWS_ACCESS_KEY_ID", "accesskey") .withEnv("AWS_SECRET_ACCESS_KEY", "secretkey") .withEnv("AWS_REGION", "eu-west-1"); - @Test public void s3TestOverDockerNetwork() throws Exception { runAwsCliAgainstDockerNetworkContainer("s3api create-bucket --bucket foo"); @@ -202,15 +237,30 @@ public void s3TestOverDockerNetwork() throws Exception { @Test public void sqsTestOverDockerNetwork() throws Exception { - final String queueCreationResponse = runAwsCliAgainstDockerNetworkContainer("sqs create-queue --queue-name baz"); + final String queueCreationResponse = runAwsCliAgainstDockerNetworkContainer( + "sqs create-queue --queue-name baz" + ); - assertThat("Created queue has external hostname URL", queueCreationResponse, - containsString("http://localstack:" + PORT)); + assertThat( + "Created queue has external hostname URL", + queueCreationResponse, + containsString("http://localstack:" + LocalStackContainer.PORT) + ); runAwsCliAgainstDockerNetworkContainer( - String.format("sqs send-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz --message-body test", PORT, PORT)); + String.format( + "sqs send-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz --message-body test", + LocalStackContainer.PORT, + LocalStackContainer.PORT + ) + ); final String message = runAwsCliAgainstDockerNetworkContainer( - String.format("sqs receive-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz", PORT, PORT)); + String.format( + "sqs receive-message --endpoint http://localstack:%d --queue-url http://localstack:%d/queue/baz", + LocalStackContainer.PORT, + LocalStackContainer.PORT + ) + ); assertTrue("the sent message can be received", message.contains("\"Body\": \"test\"")); } @@ -221,7 +271,13 @@ public void cloudWatchLogsTestOverDockerNetwork() throws Exception { } private String runAwsCliAgainstDockerNetworkContainer(String command) throws Exception { - final String[] commandParts = String.format("/usr/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", command, PORT).split(" "); + final String[] commandParts = String + .format( + "/usr/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", + command, + LocalStackContainer.PORT + ) + .split(" "); final Container.ExecResult execResult = awsCliInDockerNetwork.execInContainer(commandParts); Assert.assertEquals(0, execResult.getExitCode()); diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java index 2e28e5d0480..b0944a6d3c0 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainer.java @@ -27,10 +27,15 @@ public class MariaDBContainer> extends JdbcD static final String DEFAULT_PASSWORD = "test"; static final Integer MARIADB_PORT = 3306; + private String databaseName = "test"; + private String username = DEFAULT_USER; + private String password = DEFAULT_PASSWORD; + private static final String MARIADB_ROOT_USER = "root"; + private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF"; /** @@ -47,7 +52,6 @@ public MariaDBContainer(String dockerImageName) { public MariaDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPort(MARIADB_PORT); @@ -60,7 +64,11 @@ public Set getLivenessCheckPortNumbers() { @Override protected void configure() { - optionallyMapResourceParameterAsVolume(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, "/etc/mysql/conf.d", "mariadb-default-conf"); + optionallyMapResourceParameterAsVolume( + MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, + "/etc/mysql/conf.d", + "mariadb-default-conf" + ); addEnv("MYSQL_DATABASE", databaseName); addEnv("MYSQL_USER", username); @@ -83,13 +91,14 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { String additionalUrlParams = constructUrlParameters("?", "&"); - return "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + - "/" + databaseName + additionalUrlParams; + return ( + "jdbc:mariadb://" + getHost() + ":" + getMappedPort(MARIADB_PORT) + "/" + databaseName + additionalUrlParams + ); } @Override public String getDatabaseName() { - return databaseName; + return databaseName; } @Override diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java index 4330465a9c3..6697255ca79 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBContainerProvider.java @@ -29,7 +29,6 @@ public JdbcDatabaseContainer newInstance(String tag) { @Override public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { - return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); + return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); } - } diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java index e37e9b0b6bf..99041e83e28 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java @@ -13,7 +13,8 @@ public class MariaDBR2DBCDatabaseContainer implements R2DBCDatabaseContainer { private final MariaDBContainer container; public static ConnectionFactoryOptions getOptions(MariaDBContainer container) { - ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + ConnectionFactoryOptions options = ConnectionFactoryOptions + .builder() .option(ConnectionFactoryOptions.DRIVER, MariaDBR2DBCDatabaseContainerProvider.DRIVER) .build(); @@ -22,7 +23,8 @@ public static ConnectionFactoryOptions getOptions(MariaDBContainer container) @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { - return options.mutate() + return options + .mutate() .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MariaDBContainer.MARIADB_PORT)) .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) diff --git a/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java index b6fb4dd659e..f2339b0e5f9 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java @@ -20,5 +20,4 @@ protected String createR2DBCUrl() { protected MariaDBContainer createContainer() { return new MariaDBContainer<>(DockerImageName.parse("mariadb:10.3.6")); } - } diff --git a/modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java b/modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java index ef1dfef2703..ffb26f19734 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/jdbc/mariadb/MariaDBJDBCDriverTest.java @@ -4,26 +4,47 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class MariaDBJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mariadb.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", EnumSet.of(Options.CustomIniFile)}, - }); + return Arrays.asList( + new Object[][] { + { "jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class) }, + { + "jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { "jdbc:tc:mariadb:10.2.14://hostname/databasename", EnumSet.noneOf(Options.class) }, + { + "jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mariadb.sql&useUnicode=yes&characterEncoding=utf8", + EnumSet.of(Options.CharacterSet), + }, + { + "jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mariadb.sql", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", + EnumSet.of(Options.CustomIniFile), + }, + } + ); } } diff --git a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index 2dcdbafd9e3..21a48b6e73c 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -2,26 +2,24 @@ import org.apache.commons.lang3.SystemUtils; import org.junit.Test; +import org.testcontainers.MariaDBTestImages; import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; import java.sql.ResultSet; import java.sql.SQLException; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.testcontainers.MariaDBTestImages.MARIADB_IMAGE; - public class SimpleMariaDBTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (MariaDBContainer mariadb = new MariaDBContainer<>(MARIADB_IMAGE)) { - + try (MariaDBContainer mariadb = new MariaDBContainer<>(MariaDBTestImages.MARIADB_IMAGE)) { mariadb.start(); ResultSet resultSet = performQuery(mariadb, "SELECT 1"); @@ -33,14 +31,20 @@ public void testSimple() throws SQLException { @Test public void testSpecificVersion() throws SQLException { - try (MariaDBContainer mariadbOldVersion = new MariaDBContainer<>(MARIADB_IMAGE.withTag("5.5.51"))) { - + try ( + MariaDBContainer mariadbOldVersion = new MariaDBContainer<>( + MariaDBTestImages.MARIADB_IMAGE.withTag("5.5.51") + ) + ) { mariadbOldVersion.start(); ResultSet resultSet = performQuery(mariadbOldVersion, "SELECT VERSION()"); String resultSetString = resultSet.getString(1); - assertTrue("The database version can be set using a container rule parameter", resultSetString.startsWith("5.5.51")); + assertTrue( + "The database version can be set using a container rule parameter", + resultSetString.startsWith("5.5.51") + ); } } @@ -48,8 +52,12 @@ public void testSpecificVersion() throws SQLException { public void testMariaDBWithCustomIniFile() throws SQLException { assumeFalse(SystemUtils.IS_OS_WINDOWS); - try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>(MARIADB_IMAGE.withTag("10.1.16")) - .withConfigurationOverride("somepath/mariadb_conf_override")) { + try ( + MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>( + MariaDBTestImages.MARIADB_IMAGE.withTag("10.1.16") + ) + .withConfigurationOverride("somepath/mariadb_conf_override") + ) { mariadbCustomConfig.start(); ResultSet resultSet = performQuery(mariadbCustomConfig, "SELECT @@GLOBAL.innodb_file_format"); @@ -61,9 +69,10 @@ public void testMariaDBWithCustomIniFile() throws SQLException { @Test public void testMariaDBWithCommandOverride() throws SQLException { - - try (MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>(MARIADB_IMAGE) - .withCommand("mysqld --auto_increment_increment=10")) { + try ( + MariaDBContainer mariadbCustomConfig = new MariaDBContainer<>(MariaDBTestImages.MARIADB_IMAGE) + .withCommand("mysqld --auto_increment_increment=10") + ) { mariadbCustomConfig.start(); ResultSet resultSet = performQuery(mariadbCustomConfig, "show variables like 'auto_increment_increment'"); String result = resultSet.getString("Value"); @@ -74,7 +83,7 @@ public void testMariaDBWithCommandOverride() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - MariaDBContainer mariaDBContainer = new MariaDBContainer<>(MARIADB_IMAGE) + MariaDBContainer mariaDBContainer = new MariaDBContainer<>(MariaDBTestImages.MARIADB_IMAGE) .withUrlParam("connectTimeout", "40000") .withUrlParam("rewriteBatchedStatements", "true"); diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index 6ab1c541325..8b39d5d3763 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -8,6 +8,7 @@ public class MockServerContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("jamesdbloom/mockserver"); + private static final String DEFAULT_TAG = "mockserver-5.5.4"; @Deprecated @@ -33,7 +34,6 @@ public MockServerContainer(String version) { public MockServerContainer(DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, DockerImageName.parse("mockserver/mockserver")); waitingFor(Wait.forHttp("/mockserver/status").withMethod("PUT").forStatusCode(200)); diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java index d0c290ad46a..3f34d000603 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java @@ -5,22 +5,26 @@ import org.mockserver.client.MockServerClient; import org.testcontainers.utility.DockerImageName; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; public class MockServerContainerRuleTest { - public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse("jamesdbloom/mockserver:mockserver-5.5.4"); + public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse( + "jamesdbloom/mockserver:mockserver-5.5.4" + ); // creatingProxy { @Rule public MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE); + // } @Test public void shouldReturnExpectation() throws Exception { + // spotless:off // testSimpleExpectation { new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) .when(request() @@ -31,8 +35,10 @@ public void shouldReturnExpectation() throws Exception { // ...a GET request to '/person?name=peter' returns "Peter the person!" // } + // spotless:on - assertThat("Expectation returns expected response body", + assertThat( + "Expectation returns expected response body", SimpleHttpClient.responseFromMockserver(mockServer, "/person?name=peter"), containsString("Peter the person") ); diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index 61a5c33c630..d038b111824 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -4,7 +4,7 @@ import org.mockserver.client.MockServerClient; import org.testcontainers.utility.DockerImageName; -import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.Matchers.equalTo; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; @@ -12,12 +12,18 @@ public class MockServerContainerTest { - public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse("jamesdbloom/mockserver:mockserver-5.5.4"); + public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse( + "jamesdbloom/mockserver:mockserver-5.5.4" + ); @Test public void shouldCallActualMockserverVersion() throws Exception { String actualVersion = MockServerClient.class.getPackage().getImplementationVersion(); - try (MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE.withTag("mockserver-" + actualVersion))) { + try ( + MockServerContainer mockServer = new MockServerContainer( + MOCKSERVER_IMAGE.withTag("mockserver-" + actualVersion) + ) + ) { mockServer.start(); String expectedBody = "Hello World!"; @@ -26,11 +32,10 @@ public void shouldCallActualMockserverVersion() throws Exception { assertTrue("Mockserver running", client.isRunning()); - client - .when(request().withPath("/hello")) - .respond(response().withBody(expectedBody)); + client.when(request().withPath("/hello")).respond(response().withBody(expectedBody)); - assertThat("MockServer returns correct result", + assertThat( + "MockServer returns correct result", SimpleHttpClient.responseFromMockserver(mockServer, "/hello"), equalTo(expectedBody) ); diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java b/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java index cd5cb25cabb..da60ca9396a 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java @@ -9,9 +9,11 @@ import java.net.URLConnection; public class SimpleHttpClient { + public static String responseFromMockserver(MockServerContainer mockServer, String path) throws IOException { URLConnection urlConnection = new URL(mockServer.getEndpoint() + path).openConnection(); - @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + @Cleanup + BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); return reader.readLine(); } } diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 87db80846a8..81bb59fd69d 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -18,10 +18,15 @@ public class MongoDBContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mongo"); + private static final String DEFAULT_TAG = "4.0.10"; + private static final int CONTAINER_EXIT_CODE_OK = 0; + private static final int MONGODB_INTERNAL_PORT = 27017; + private static final int AWAIT_INIT_REPLICA_SET_ATTEMPTS = 60; + private static final String MONGODB_DATABASE_NAME_DEFAULT = "test"; /** @@ -38,14 +43,11 @@ public MongoDBContainer(@NonNull final String dockerImageName) { public MongoDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(MONGODB_INTERNAL_PORT); withCommand("--replSet", "docker-rs"); - waitingFor( - Wait.forLogMessage("(?i).*waiting for connections.*", 1) - ); + waitingFor(Wait.forLogMessage("(?i).*waiting for connections.*", 1)); } /** @@ -54,11 +56,7 @@ public MongoDBContainer(final DockerImageName dockerImageName) { * @return a connection url pointing to a mongodb instance */ public String getConnectionString() { - return String.format( - "mongodb://%s:%d", - getHost(), - getMappedPort(MONGODB_INTERNAL_PORT) - ); + return String.format("mongodb://%s:%d", getHost(), getMappedPort(MONGODB_INTERNAL_PORT)); } /** @@ -89,7 +87,7 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { } private String[] buildMongoEvalCommand(final String command) { - return new String[]{"mongo", "--eval", command}; + return new String[] { "mongo", "--eval", command }; } private void checkMongoNodeExitCode(final Container.ExecResult execResult) { @@ -103,21 +101,19 @@ private void checkMongoNodeExitCode(final Container.ExecResult execResult) { private String buildMongoWaitCommand() { return String.format( "var attempt = 0; " + - "while" + - "(%s) " + - "{ " + - "if (attempt > %d) {quit(1);} " + - "print('%s ' + attempt); sleep(100); attempt++; " + - " }", + "while" + + "(%s) " + + "{ " + + "if (attempt > %d) {quit(1);} " + + "print('%s ' + attempt); sleep(100); attempt++; " + + " }", "db.runCommand( { isMaster: 1 } ).ismaster==false", AWAIT_INIT_REPLICA_SET_ATTEMPTS, "An attempt to await for a single node replica set initialization:" ); } - private void checkMongoNodeExitCodeAfterWaiting( - final Container.ExecResult execResultWaitForMaster - ) { + private void checkMongoNodeExitCodeAfterWaiting(final Container.ExecResult execResultWaitForMaster) { if (execResultWaitForMaster.getExitCode() != CONTAINER_EXIT_CODE_OK) { final String errorMessage = String.format( "A single node replica set was not initialized in a set timeout: %d attempts", @@ -128,12 +124,10 @@ private void checkMongoNodeExitCodeAfterWaiting( } } - @SneakyThrows(value = {IOException.class, InterruptedException.class}) + @SneakyThrows(value = { IOException.class, InterruptedException.class }) private void initReplicaSet() { log.debug("Initializing a single node node replica set..."); - final ExecResult execResultInitRs = execInContainer( - buildMongoEvalCommand("rs.initiate();") - ); + final ExecResult execResultInitRs = execInContainer(buildMongoEvalCommand("rs.initiate();")); log.debug(execResultInitRs.getStdout()); checkMongoNodeExitCode(execResultInitRs); @@ -141,15 +135,14 @@ private void initReplicaSet() { "Awaiting for a single node replica set initialization up to {} attempts", AWAIT_INIT_REPLICA_SET_ATTEMPTS ); - final ExecResult execResultWaitForMaster = execInContainer( - buildMongoEvalCommand(buildMongoWaitCommand()) - ); + final ExecResult execResultWaitForMaster = execInContainer(buildMongoEvalCommand(buildMongoWaitCommand())); log.debug(execResultWaitForMaster.getStdout()); checkMongoNodeExitCodeAfterWaiting(execResultWaitForMaster); } public static class ReplicaSetInitializationException extends RuntimeException { + ReplicaSetInitializationException(final String errorMessage) { super(errorMessage); } diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index 532a86208c1..6c98978f20a 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -13,12 +13,11 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.Matchers.endsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; - public class MongoDBContainerTest { /** @@ -31,7 +30,6 @@ public void shouldExecuteTransactions() { final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")) // } ) { - // startingMongoDBContainer { mongoDBContainer.start(); // } @@ -41,15 +39,25 @@ public void shouldExecuteTransactions() { final String connectionString = mongoDBContainer.getConnectionString(); final MongoClient mongoSyncClientBase = MongoClients.create(connectionString); final MongoClient mongoSyncClient = MongoClients.create(mongoRsUrl); - mongoSyncClient.getDatabase("mydb1").getCollection("foo") - .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0)); - mongoSyncClient.getDatabase("mydb2").getCollection("bar") - .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0)); - mongoSyncClientBase.getDatabase("mydb3").getCollection("baz") - .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("def", 0)); + mongoSyncClient + .getDatabase("mydb1") + .getCollection("foo") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("abc", 0)); + mongoSyncClient + .getDatabase("mydb2") + .getCollection("bar") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("xyz", 0)); + mongoSyncClientBase + .getDatabase("mydb3") + .getCollection("baz") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("def", 0)); final ClientSession clientSession = mongoSyncClient.startSession(); - final TransactionOptions txnOptions = TransactionOptions.builder() + final TransactionOptions txnOptions = TransactionOptions + .builder() .readPreference(ReadPreference.primary()) .readConcern(ReadConcern.LOCAL) .writeConcern(WriteConcern.MAJORITY) @@ -58,10 +66,8 @@ public void shouldExecuteTransactions() { final String trxResult = "Inserted into collections in different databases"; TransactionBody txnBody = () -> { - final MongoCollection coll1 = - mongoSyncClient.getDatabase("mydb1").getCollection("foo"); - final MongoCollection coll2 = - mongoSyncClient.getDatabase("mydb2").getCollection("bar"); + final MongoCollection coll1 = mongoSyncClient.getDatabase("mydb1").getCollection("foo"); + final MongoCollection coll2 = mongoSyncClient.getDatabase("mydb2").getCollection("bar"); coll1.insertOne(clientSession, new Document("abc", 1)); coll2.insertOne(clientSession, new Document("xyz", 999)); @@ -82,18 +88,14 @@ public void shouldExecuteTransactions() { @Test public void supportsMongoDB_4_4() { - try ( - final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.4")) - ) { + try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.4"))) { mongoDBContainer.start(); } } @Test public void shouldTestDatabaseName() { - try ( - final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")) - ) { + try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))) { mongoDBContainer.start(); final String databaseName = "my-db"; assertThat(mongoDBContainer.getReplicaSetUrl(databaseName), endsWith(databaseName)); diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java index 59c3ed0de68..6a58b3488ff 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLR2DBCDatabaseContainer.java @@ -13,7 +13,8 @@ public class MSSQLR2DBCDatabaseContainer implements R2DBCDatabaseContainer { private final MSSQLServerContainer container; public static ConnectionFactoryOptions getOptions(MSSQLServerContainer container) { - ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + ConnectionFactoryOptions options = ConnectionFactoryOptions + .builder() .option(ConnectionFactoryOptions.DRIVER, MSSQLR2DBCDatabaseContainerProvider.DRIVER) .build(); @@ -22,7 +23,8 @@ public static ConnectionFactoryOptions getOptions(MSSQLServerContainer contai @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { - return options.mutate() + return options + .mutate() .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MSSQLServerContainer.MS_SQL_SERVER_PORT)) // TODO enable if/when MSSQLServerContainer adds support for customizing the DB name diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index fe6270d04c7..532316fb967 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -14,6 +14,7 @@ public class MSSQLServerContainer> extends JdbcDatabaseContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mcr.microsoft.com/mssql/server"); + @Deprecated public static final String DEFAULT_TAG = "2017-CU12"; @@ -30,13 +31,14 @@ public class MSSQLServerContainer> exten private String password = DEFAULT_PASSWORD; private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240; + private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 240; - private static final Pattern[] PASSWORD_CATEGORY_VALIDATION_PATTERNS = new Pattern[]{ + private static final Pattern[] PASSWORD_CATEGORY_VALIDATION_PATTERNS = new Pattern[] { Pattern.compile("[A-Z]+"), Pattern.compile("[a-z]+"), Pattern.compile("[0-9]+"), - Pattern.compile("[^a-zA-Z0-9]+", Pattern.CASE_INSENSITIVE) + Pattern.compile("[^a-zA-Z0-9]+", Pattern.CASE_INSENSITIVE), }; /** @@ -53,7 +55,6 @@ public MSSQLServerContainer(final String dockerImageName) { public MSSQLServerContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS); @@ -131,7 +132,6 @@ public SELF withPassword(final String password) { } private void checkPasswordStrength(String password) { - if (password == null) { throw new IllegalArgumentException("Null password is not allowed"); } @@ -144,18 +144,19 @@ private void checkPasswordStrength(String password) { throw new IllegalArgumentException("Password can be up to 128 characters long"); } - long satisfiedCategories = Stream.of(PASSWORD_CATEGORY_VALIDATION_PATTERNS) + long satisfiedCategories = Stream + .of(PASSWORD_CATEGORY_VALIDATION_PATTERNS) .filter(p -> p.matcher(password).find()) .count(); if (satisfiedCategories < 3) { throw new IllegalArgumentException( "Password must contain characters from three of the following four categories:\n" + - " - Latin uppercase letters (A through Z)\n" + - " - Latin lowercase letters (a through z)\n" + - " - Base 10 digits (0 through 9)\n" + - " - Non-alphanumeric characters such as: exclamation point (!), dollar sign ($), number sign (#), " + - "or percent (%)." + " - Latin uppercase letters (A through Z)\n" + + " - Latin lowercase letters (a through z)\n" + + " - Base 10 digits (0 through 9)\n" + + " - Non-alphanumeric characters such as: exclamation point (!), dollar sign ($), number sign (#), " + + "or percent (%)." ); } } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java index c3495c8a3a6..27e8ab75225 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainerProvider.java @@ -6,6 +6,7 @@ * Factory for MS SQL Server containers. */ public class MSSQLServerContainerProvider extends JdbcDatabaseContainerProvider { + @Override public boolean supports(String databaseType) { return databaseType.equals(MSSQLServerContainer.NAME); diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java index 00e22199b46..bdb623136fb 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/jdbc/mssqlserver/MSSQLServerJDBCDriverTest.java @@ -4,18 +4,21 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class MSSQLServerJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", EnumSet.noneOf(Options.class)}, - }); + return Arrays.asList( + new Object[][] { + { + "jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", + EnumSet.noneOf(Options.class), + }, + } + ); } } diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java index 6ebd3624577..49bae13d9e3 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java @@ -22,11 +22,15 @@ public class CustomPasswordMSSQLServerTest { private static String UPPER_CASE_LETTERS = "ABCDE"; + private static String LOWER_CASE_LETTERS = "abcde"; + private static String NUMBERS = "12345"; + private static String SPECIAL_CHARS = "_(!)_"; private String password; + private Boolean valid; public CustomPasswordMSSQLServerTest(String password, Boolean valid) { @@ -36,45 +40,41 @@ public CustomPasswordMSSQLServerTest(String password, Boolean valid) { @Parameterized.Parameters public static Collection data() { - return Arrays.asList(new Object[][]{ - new Object[]{null, false}, - // too short - {"abc123", false}, - - // too long - {RandomStringUtils.randomAlphabetic(129), false}, - - // only 2 categories - {UPPER_CASE_LETTERS + NUMBERS, false}, - {UPPER_CASE_LETTERS + SPECIAL_CHARS, false}, - {LOWER_CASE_LETTERS + NUMBERS, false}, - {LOWER_CASE_LETTERS + SPECIAL_CHARS, false}, - {NUMBERS + SPECIAL_CHARS, false}, - - // 3 categories - {UPPER_CASE_LETTERS + LOWER_CASE_LETTERS + NUMBERS, true}, - {UPPER_CASE_LETTERS + LOWER_CASE_LETTERS + SPECIAL_CHARS, true}, - {UPPER_CASE_LETTERS + NUMBERS + SPECIAL_CHARS, true}, - {LOWER_CASE_LETTERS + NUMBERS + SPECIAL_CHARS, true}, - - // 4 categories - {UPPER_CASE_LETTERS + LOWER_CASE_LETTERS + NUMBERS + SPECIAL_CHARS, true}, - - - }); + return Arrays.asList( + new Object[][] { + new Object[] { null, false }, + // too short + { "abc123", false }, + // too long + { RandomStringUtils.randomAlphabetic(129), false }, + // only 2 categories + { UPPER_CASE_LETTERS + NUMBERS, false }, + { UPPER_CASE_LETTERS + SPECIAL_CHARS, false }, + { LOWER_CASE_LETTERS + NUMBERS, false }, + { LOWER_CASE_LETTERS + SPECIAL_CHARS, false }, + { NUMBERS + SPECIAL_CHARS, false }, + // 3 categories + { UPPER_CASE_LETTERS + LOWER_CASE_LETTERS + NUMBERS, true }, + { UPPER_CASE_LETTERS + LOWER_CASE_LETTERS + SPECIAL_CHARS, true }, + { UPPER_CASE_LETTERS + NUMBERS + SPECIAL_CHARS, true }, + { LOWER_CASE_LETTERS + NUMBERS + SPECIAL_CHARS, true }, + // 4 categories + { UPPER_CASE_LETTERS + LOWER_CASE_LETTERS + NUMBERS + SPECIAL_CHARS, true }, + } + ); } @Test public void runPasswordTests() { try { new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE).withPassword(this.password); - if (!valid) + if (!valid) { fail("Password " + this.password + " is not valid. Expected exception"); + } } catch (IllegalArgumentException e) { - if (valid) + if (valid) { fail("Password " + this.password + " should have been validated"); + } } } - - } diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java index d3c387e7b4a..21ea5380801 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java @@ -16,9 +16,12 @@ public class CustomizableMSSQLServerTest extends AbstractContainerDatabaseTest { @Test public void testSqlServerConnection() throws SQLException { - try (MSSQLServerContainer mssqlServerContainer = new MSSQLServerContainer<>(DockerImageName.parse("mcr.microsoft.com/mssql/server:2017-CU12")) - .withPassword(STRONG_PASSWORD)) { - + try ( + MSSQLServerContainer mssqlServerContainer = new MSSQLServerContainer<>( + DockerImageName.parse("mcr.microsoft.com/mssql/server:2017-CU12") + ) + .withPassword(STRONG_PASSWORD) + ) { mssqlServerContainer.start(); ResultSet resultSet = performQuery(mssqlServerContainer, mssqlServerContainer.getTestQueryString()); diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index 1530760b673..36d215c8757 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -1,24 +1,27 @@ package org.testcontainers.junit.mssqlserver; import org.junit.Test; +import org.testcontainers.MSSQLServerTestImages; import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; -import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import static org.hamcrest.CoreMatchers.containsString; +import javax.sql.DataSource; + import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.MSSQLServerTestImages.MSSQL_SERVER_IMAGE; public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQL_SERVER_IMAGE)) { + try ( + MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE) + ) { mssqlServer.start(); ResultSet resultSet = performQuery(mssqlServer, "SELECT 1"); @@ -29,10 +32,11 @@ public void testSimple() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQL_SERVER_IMAGE) - .withUrlParam("integratedSecurity", "false") - .withUrlParam("applicationName", "MyApp")) { - + try ( + MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE) + .withUrlParam("integratedSecurity", "false") + .withUrlParam("applicationName", "MyApp") + ) { mssqlServer.start(); String jdbcUrl = mssqlServer.getJdbcUrl(); @@ -40,10 +44,11 @@ public void testWithAdditionalUrlParamInJdbcUrl() { } } - @Test public void testSetupDatabase() throws SQLException { - try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQL_SERVER_IMAGE)) { + try ( + MSSQLServerContainer mssqlServer = new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE) + ) { mssqlServer.start(); DataSource ds = getDataSource(mssqlServer); Statement statement = ds.getConnection().createStatement(); diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 20be08c2aec..14206018954 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -26,10 +26,15 @@ public class MySQLContainer> extends JdbcDatab static final String DEFAULT_PASSWORD = "test"; private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF"; + public static final Integer MYSQL_PORT = 3306; + private String databaseName = "test"; + private String username = DEFAULT_USER; + private String password = DEFAULT_PASSWORD; + private static final String MYSQL_ROOT_USER = "root"; /** @@ -46,13 +51,11 @@ public MySQLContainer(String dockerImageName) { public MySQLContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPort(MYSQL_PORT); } - @NotNull @Override protected Set getLivenessCheckPorts() { @@ -61,8 +64,11 @@ protected Set getLivenessCheckPorts() { @Override protected void configure() { - optionallyMapResourceParameterAsVolume(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, "/etc/mysql/conf.d", - "mysql-default-conf"); + optionallyMapResourceParameterAsVolume( + MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, + "/etc/mysql/conf.d", + "mysql-default-conf" + ); addEnv("MYSQL_DATABASE", databaseName); if (!MYSQL_ROOT_USER.equalsIgnoreCase(username)) { @@ -92,8 +98,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { String additionalUrlParams = constructUrlParameters("?", "&"); - return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + - "/" + databaseName + additionalUrlParams; + return "jdbc:mysql://" + getHost() + ":" + getMappedPort(MYSQL_PORT) + "/" + databaseName + additionalUrlParams; } @Override diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java index 18d126635b1..621001d7b57 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainerProvider.java @@ -35,5 +35,4 @@ public JdbcDatabaseContainer newInstance(String tag) { public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); } - } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java index 274224352a8..4bbb542fec8 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java @@ -13,7 +13,8 @@ public class MySQLR2DBCDatabaseContainer implements R2DBCDatabaseContainer { private final MySQLContainer container; public static ConnectionFactoryOptions getOptions(MySQLContainer container) { - ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + ConnectionFactoryOptions options = ConnectionFactoryOptions + .builder() .option(ConnectionFactoryOptions.DRIVER, MySQLR2DBCDatabaseContainerProvider.DRIVER) .build(); @@ -22,7 +23,8 @@ public static ConnectionFactoryOptions getOptions(MySQLContainer container) { @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { - return options.mutate() + return options + .mutate() .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(MySQLContainer.MYSQL_PORT)) .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) diff --git a/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java b/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java index 833dc1448cf..81de83be0b9 100644 --- a/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java +++ b/modules/mysql/src/test/java/org/testcontainers/MySQLTestImages.java @@ -3,7 +3,10 @@ import org.testcontainers.utility.DockerImageName; public class MySQLTestImages { + public static final DockerImageName MYSQL_56_IMAGE = DockerImageName.parse("mysql:5.6.51"); + public static final DockerImageName MYSQL_57_IMAGE = DockerImageName.parse("mysql:5.7.34"); + public static final DockerImageName MYSQL_80_IMAGE = DockerImageName.parse("mysql:8.0.24"); } diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java index 334fabb0a49..42a852ad1f1 100644 --- a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java @@ -20,5 +20,4 @@ protected String createR2DBCUrl() { protected MySQLContainer createContainer() { return new MySQLContainer<>(MySQLTestImages.MYSQL_80_IMAGE); } - } diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java index 86b13a0d1bf..0320eee9255 100644 --- a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLRootAccountTest.java @@ -18,13 +18,10 @@ public class MySQLRootAccountTest { @Parameterized.Parameters(name = "{0}") public static DockerImageName[] params() { - return new DockerImageName[]{ - MySQLTestImages.MYSQL_80_IMAGE, - MySQLTestImages.MYSQL_57_IMAGE - }; + return new DockerImageName[] { MySQLTestImages.MYSQL_80_IMAGE, MySQLTestImages.MYSQL_57_IMAGE }; } - @Parameterized.Parameter() + @Parameterized.Parameter public DockerImageName image; @Test diff --git a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java index 3b9f9842095..a30f3f59888 100644 --- a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java @@ -11,15 +11,16 @@ import org.testcontainers.jdbc.ContainerDatabaseDriver; import org.vibur.dbcp.ViburDBCPDataSource; -import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; +import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -import static java.util.Arrays.asList; +import javax.sql.DataSource; + import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; /** @@ -31,12 +32,14 @@ @RunWith(Parameterized.class) public class JDBCDriverWithPoolTest { - public static final String URL = "jdbc:tc:mysql:5.7.34://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.mysql.JDBCDriverWithPoolTest::sampleInitFunction"; + public static final String URL = + "jdbc:tc:mysql:5.7.34://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.mysql.JDBCDriverWithPoolTest::sampleInitFunction"; + private final DataSource dataSource; @Parameterized.Parameters public static Iterable> dataSourceSuppliers() { - return asList( + return Arrays.asList( JDBCDriverWithPoolTest::getTomcatDataSourceWithDriverClassName, JDBCDriverWithPoolTest::getTomcatDataSource, JDBCDriverWithPoolTest::getHikariDataSourceWithDriverClassName, @@ -54,13 +57,12 @@ public JDBCDriverWithPoolTest(Supplier dataSourceSupplier) { @Test public void testMySQLWithConnectionPoolUsingSameContainer() throws SQLException, InterruptedException { - // Populate the database with some data in multiple threads, so that multiple connections from the pool will be used for (int i = 0; i < 100; i++) { executorService.submit(() -> { try { - new QueryRunner(dataSource).insert("INSERT INTO my_counter (n) VALUES (5)", - (ResultSetHandler) rs -> true); + new QueryRunner(dataSource) + .insert("INSERT INTO my_counter (n) VALUES (5)", (ResultSetHandler) rs -> true); } catch (SQLException e) { e.printStackTrace(); } @@ -72,22 +74,28 @@ public void testMySQLWithConnectionPoolUsingSameContainer() throws SQLException, executorService.awaitTermination(5, TimeUnit.MINUTES); // compare to expected results - int count = new QueryRunner(dataSource).query("SELECT COUNT(1) FROM my_counter", rs -> { - rs.next(); - return rs.getInt(1); - }); + int count = new QueryRunner(dataSource) + .query( + "SELECT COUNT(1) FROM my_counter", + rs -> { + rs.next(); + return rs.getInt(1); + } + ); assertEquals("Reuse of a datasource points to the same DB container", 100, count); - - int sum = new QueryRunner(dataSource).query("SELECT SUM(n) FROM my_counter", rs -> { - rs.next(); - return rs.getInt(1); - }); + int sum = new QueryRunner(dataSource) + .query( + "SELECT SUM(n) FROM my_counter", + rs -> { + rs.next(); + return rs.getInt(1); + } + ); // 100 records * 5 = 500 expected assertEquals("Reuse of a datasource points to the same DB container", 500, sum); } - private static DataSource getTomcatDataSourceWithDriverClassName() { PoolProperties poolProperties = new PoolProperties(); poolProperties.setUrl(URL + ";TEST=TOMCAT_WITH_CLASSNAME"); // append a dummy URL element to ensure different DB per test @@ -134,7 +142,7 @@ private static DataSource getViburDataSourceWithDriverClassName() { ViburDBCPDataSource ds = new ViburDBCPDataSource(); ds.setJdbcUrl(URL + ";TEST=VIBUR_WITH_CLASSNAME"); - ds.setUsername("any"); // Recent versions of Vibur require a username, even though it will not be used + ds.setUsername("any"); // Recent versions of Vibur require a username, even though it will not be used ds.setPassword(""); ds.setPoolInitialSize(3); ds.setPoolMaxSize(10); @@ -149,7 +157,7 @@ private static DataSource getViburDataSourceWithDriverClassName() { private static DataSource getViburDataSource() { ViburDBCPDataSource ds = new ViburDBCPDataSource(); ds.setJdbcUrl(URL + ";TEST=VIBUR"); - ds.setUsername("any"); // Recent versions of Vibur require a username, even though it will not be used + ds.setUsername("any"); // Recent versions of Vibur require a username, even though it will not be used ds.setPassword(""); ds.setPoolInitialSize(3); ds.setPoolMaxSize(10); @@ -162,12 +170,8 @@ private static DataSource getViburDataSource() { @SuppressWarnings("SqlNoDataSourceInspection") public static void sampleInitFunction(Connection connection) throws SQLException { - connection.createStatement().execute("CREATE TABLE bar (\n" + - " foo VARCHAR(255)\n" + - ");"); + connection.createStatement().execute("CREATE TABLE bar (\n" + " foo VARCHAR(255)\n" + ");"); connection.createStatement().execute("INSERT INTO bar (foo) VALUES ('hello world');"); - connection.createStatement().execute("CREATE TABLE my_counter (\n" + - " n INT\n" + - ");"); + connection.createStatement().execute("CREATE TABLE my_counter (\n" + " n INT\n" + ");"); } } diff --git a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java index 302621879eb..752fbca8e07 100644 --- a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLJDBCDriverTest.java @@ -4,27 +4,48 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class MySQLJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:mysql://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)}, - {"jdbc:tc:mysql:5.7.34://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)}, - {"jdbc:tc:mysql:5.7.34://hostname/databasename", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mysql:5.7.34://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class)}, - {"jdbc:tc:mysql:5.6.51://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)}, - }); + return Arrays.asList( + new Object[][] { + { "jdbc:tc:mysql://hostname/databasename", EnumSet.noneOf(Options.class) }, + { + "jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mysql:5.7.34://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.AbstractJDBCDriverTest::sampleInitFunction", + EnumSet.of(Options.ScriptedSchema, Options.JDBCParams), + }, + { + "jdbc:tc:mysql:5.7.34://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", + EnumSet.of(Options.CharacterSet), + }, + { "jdbc:tc:mysql:5.7.34://hostname/databasename", EnumSet.noneOf(Options.class) }, + { "jdbc:tc:mysql:5.7.34://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class) }, + { + "jdbc:tc:mysql:5.6.51://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", + EnumSet.of(Options.CustomIniFile), + }, + } + ); } } diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java index 0b72ce083d2..20b49d19201 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java @@ -11,19 +11,23 @@ import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class CustomizableMysqlTest extends AbstractContainerDatabaseTest { + private static final String DB_NAME = "foo"; + private static final String USER = "bar"; + private static final String PWD = "baz"; @Test public void testSimple() throws SQLException { // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - try (MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) - .withDatabaseName(DB_NAME) - .withUsername(USER) - .withPassword(PWD) - .withEnv("MYSQL_ROOT_HOST", "%")) { - + try ( + MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) + .withDatabaseName(DB_NAME) + .withUsername(USER) + .withPassword(PWD) + .withEnv("MYSQL_ROOT_HOST", "%") + ) { mysql.start(); ResultSet resultSet = performQuery(mysql, "SELECT 1"); diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java index 32dee3cd056..735af251236 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java @@ -3,6 +3,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.testcontainers.MySQLTestImages; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; import org.testcontainers.utility.DockerImageName; @@ -11,23 +12,20 @@ import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.testcontainers.MySQLTestImages.MYSQL_56_IMAGE; -import static org.testcontainers.MySQLTestImages.MYSQL_57_IMAGE; -import static org.testcontainers.MySQLTestImages.MYSQL_80_IMAGE; @RunWith(Parameterized.class) public class MultiVersionMySQLTest extends AbstractContainerDatabaseTest { @Parameterized.Parameters(name = "{0}") public static DockerImageName[] params() { - return new DockerImageName[]{ - MYSQL_56_IMAGE, - MYSQL_57_IMAGE, - MYSQL_80_IMAGE + return new DockerImageName[] { + MySQLTestImages.MYSQL_56_IMAGE, + MySQLTestImages.MYSQL_57_IMAGE, + MySQLTestImages.MYSQL_80_IMAGE, }; } - @Parameterized.Parameter() + @Parameterized.Parameter public DockerImageName dockerImageName; @Test @@ -37,7 +35,11 @@ public void versionCheckTest() throws SQLException { final ResultSet resultSet = performQuery(mysql, "SELECT VERSION()"); final String resultSetString = resultSet.getString(1); - assertEquals("The database version can be set using a container rule parameter", dockerImageName.getVersionPart(), resultSetString); + assertEquals( + "The database version can be set using a container rule parameter", + dockerImageName.getVersionPart(), + resultSetString + ); } } } diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index 90973bc4b56..6441724c443 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testcontainers.MySQLTestImages; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.output.Slf4jLogConsumer; @@ -18,15 +19,12 @@ import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeFalse; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; import static org.rnorth.visibleassertions.VisibleAssertions.fail; -import static org.testcontainers.MySQLTestImages.MYSQL_56_IMAGE; -import static org.testcontainers.MySQLTestImages.MYSQL_57_IMAGE; - public class SimpleMySQLTest extends AbstractContainerDatabaseTest { @@ -51,10 +49,11 @@ public class SimpleMySQLTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) - .withConfigurationOverride("somepath/mysql_conf_override") - .withLogConsumer(new Slf4jLogConsumer(logger))) { - + try ( + MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) + .withConfigurationOverride("somepath/mysql_conf_override") + .withLogConsumer(new Slf4jLogConsumer(logger)) + ) { mysql.start(); ResultSet resultSet = performQuery(mysql, "SELECT 1"); @@ -66,16 +65,20 @@ public void testSimple() throws SQLException { @Test public void testSpecificVersion() throws SQLException { - try (MySQLContainer mysqlOldVersion = new MySQLContainer<>(MYSQL_56_IMAGE) - .withConfigurationOverride("somepath/mysql_conf_override") - .withLogConsumer(new Slf4jLogConsumer(logger))) { - + try ( + MySQLContainer mysqlOldVersion = new MySQLContainer<>(MySQLTestImages.MYSQL_56_IMAGE) + .withConfigurationOverride("somepath/mysql_conf_override") + .withLogConsumer(new Slf4jLogConsumer(logger)) + ) { mysqlOldVersion.start(); ResultSet resultSet = performQuery(mysqlOldVersion, "SELECT VERSION()"); String resultSetString = resultSet.getString(1); - assertTrue("The database version can be set using a container rule parameter", resultSetString.startsWith("5.6")); + assertTrue( + "The database version can be set using a container rule parameter", + resultSetString.startsWith("5.6") + ); } } @@ -83,9 +86,10 @@ public void testSpecificVersion() throws SQLException { public void testMySQLWithCustomIniFile() throws SQLException { assumeFalse(SystemUtils.IS_OS_WINDOWS); - try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MYSQL_56_IMAGE) - .withConfigurationOverride("somepath/mysql_conf_override")) { - + try ( + MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MySQLTestImages.MYSQL_56_IMAGE) + .withConfigurationOverride("somepath/mysql_conf_override") + ) { mysqlCustomConfig.start(); ResultSet resultSet = performQuery(mysqlCustomConfig, "SELECT @@GLOBAL.innodb_file_format"); @@ -97,9 +101,10 @@ public void testMySQLWithCustomIniFile() throws SQLException { @Test public void testCommandOverride() throws SQLException { - try (MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MYSQL_57_IMAGE) - .withCommand("mysqld --auto_increment_increment=42")) { - + try ( + MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) + .withCommand("mysqld --auto_increment_increment=42") + ) { mysqlCustomConfig.start(); ResultSet resultSet = performQuery(mysqlCustomConfig, "show variables like 'auto_increment_increment'"); @@ -111,9 +116,11 @@ public void testCommandOverride() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (MySQLContainer container = new MySQLContainer<>(MYSQL_57_IMAGE) - .withInitScript("somepath/init_mysql.sql") - .withLogConsumer(new Slf4jLogConsumer(logger))) { + try ( + MySQLContainer container = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) + .withInitScript("somepath/init_mysql.sql") + .withLogConsumer(new Slf4jLogConsumer(logger)) + ) { container.start(); ResultSet resultSet = performQuery(container, "SELECT foo FROM bar"); @@ -125,11 +132,13 @@ public void testExplicitInitScript() throws SQLException { @Test(expected = ContainerLaunchException.class) public void testEmptyPasswordWithNonRootUser() { - try (MySQLContainer container = new MySQLContainer<>(MYSQL_56_IMAGE) - .withDatabaseName("TEST") - .withUsername("test") - .withPassword("") - .withEnv("MYSQL_ROOT_HOST", "%")){ + try ( + MySQLContainer container = new MySQLContainer<>(MySQLTestImages.MYSQL_56_IMAGE) + .withDatabaseName("TEST") + .withUsername("test") + .withPassword("") + .withEnv("MYSQL_ROOT_HOST", "%") + ) { container.start(); fail("ContainerLaunchException expected to be thrown"); } @@ -138,12 +147,13 @@ public void testEmptyPasswordWithNonRootUser() { @Test public void testEmptyPasswordWithRootUser() throws SQLException { // Add MYSQL_ROOT_HOST environment so that we can root login from anywhere for testing purposes - try (MySQLContainer mysql = new MySQLContainer<>(MYSQL_56_IMAGE) - .withDatabaseName("foo") - .withUsername("root") - .withPassword("") - .withEnv("MYSQL_ROOT_HOST", "%")) { - + try ( + MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_56_IMAGE) + .withDatabaseName("foo") + .withUsername("root") + .withPassword("") + .withEnv("MYSQL_ROOT_HOST", "%") + ) { mysql.start(); ResultSet resultSet = performQuery(mysql, "SELECT 1"); @@ -155,13 +165,13 @@ public void testEmptyPasswordWithRootUser() throws SQLException { @Test public void testWithAdditionalUrlParamTimeZone() throws SQLException { - MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) + MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) .withUrlParam("serverTimezone", "Europe/Zurich") .withEnv("TZ", "Europe/Zurich") .withLogConsumer(new Slf4jLogConsumer(logger)); mysql.start(); - try(Connection connection = mysql.createConnection("")) { + try (Connection connection = mysql.createConnection("")) { Statement statement = connection.createStatement(); statement.execute("SELECT NOW();"); try (ResultSet resultSet = statement.getResultSet()) { @@ -169,13 +179,18 @@ public void testWithAdditionalUrlParamTimeZone() throws SQLException { // checking that the time_zone MySQL is Europe/Zurich LocalDateTime localDateTime = resultSet.getObject(1, LocalDateTime.class); - ZonedDateTime actualDateTime = localDateTime.atZone(ZoneId.of("Europe/Zurich")) + ZonedDateTime actualDateTime = localDateTime + .atZone(ZoneId.of("Europe/Zurich")) .truncatedTo(ChronoUnit.MINUTES); - ZonedDateTime expectedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Zurich")) + ZonedDateTime expectedDateTime = ZonedDateTime + .now(ZoneId.of("Europe/Zurich")) .truncatedTo(ChronoUnit.MINUTES); - String message = String.format("MySQL time zone is not Europe/Zurich. MySQL date:%s, current date:%s", - actualDateTime, expectedDateTime); + String message = String.format( + "MySQL time zone is not Europe/Zurich. MySQL date:%s, current date:%s", + actualDateTime, + expectedDateTime + ); assertTrue(message, actualDateTime.equals(expectedDateTime)); } } finally { @@ -185,19 +200,20 @@ public void testWithAdditionalUrlParamTimeZone() throws SQLException { @Test public void testWithAdditionalUrlParamMultiQueries() throws SQLException { - MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) + MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) .withUrlParam("allowMultiQueries", "true") .withLogConsumer(new Slf4jLogConsumer(logger)); mysql.start(); - try(Connection connection = mysql.createConnection("")) { + try (Connection connection = mysql.createConnection("")) { Statement statement = connection.createStatement(); - String multiQuery = "DROP TABLE IF EXISTS bar; " + + String multiQuery = + "DROP TABLE IF EXISTS bar; " + "CREATE TABLE bar (foo VARCHAR(20)); " + "INSERT INTO bar (foo) VALUES ('hello world');"; statement.execute(multiQuery); statement.execute("SELECT foo FROM bar;"); - try(ResultSet resultSet = statement.getResultSet()) { + try (ResultSet resultSet = statement.getResultSet()) { resultSet.next(); String firstColumnValue = resultSet.getString(1); assertEquals("Value from bar should equal real value", "hello world", firstColumnValue); @@ -209,7 +225,7 @@ public void testWithAdditionalUrlParamMultiQueries() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - MySQLContainer mysql = new MySQLContainer<>(MYSQL_57_IMAGE) + MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) .withUrlParam("allowMultiQueries", "true") .withUrlParam("rewriteBatchedStatements", "true") .withLogConsumer(new Slf4jLogConsumer(logger)); diff --git a/modules/neo4j/src/custom-neo4j-plugin/java/ac/simons/neo4j/demos/plugins/HelloWorld.java b/modules/neo4j/src/custom-neo4j-plugin/java/ac/simons/neo4j/demos/plugins/HelloWorld.java index cbfcdc03a55..8948c98d53c 100644 --- a/modules/neo4j/src/custom-neo4j-plugin/java/ac/simons/neo4j/demos/plugins/HelloWorld.java +++ b/modules/neo4j/src/custom-neo4j-plugin/java/ac/simons/neo4j/demos/plugins/HelloWorld.java @@ -9,7 +9,6 @@ public class HelloWorld { @UserFunction("ac.simons.helloWorld") @Description("Simple Hello World") public String helloWorld(@Name("name") String name) { - return "Hello, " + name; } } diff --git a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java index 6f0cf10ded7..94b4263fe8c 100644 --- a/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java +++ b/modules/neo4j/src/main/java/org/testcontainers/containers/Neo4jContainer.java @@ -1,15 +1,5 @@ package org.testcontainers.containers; -import static java.net.HttpURLConnection.HTTP_OK; -import static java.util.stream.Collectors.toSet; - -import java.time.Duration; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; @@ -19,6 +9,15 @@ import org.testcontainers.utility.LicenseAcceptance; import org.testcontainers.utility.MountableFile; +import java.net.HttpURLConnection; +import java.time.Duration; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * Testcontainer for Neo4j. * @@ -36,6 +35,7 @@ public class Neo4jContainer> extends GenericContaine * The default tag (version) to use. */ private static final String DEFAULT_TAG = "4.4"; + private static final String ENTERPRISE_TAG = DEFAULT_TAG + "-enterprise"; /** @@ -91,9 +91,7 @@ public Neo4jContainer(String dockerImageName) { */ public Neo4jContainer(final DockerImageName dockerImageName) { super(dockerImageName); - - this.standardImage = dockerImageName.getUnversionedPart() - .equals(DEFAULT_IMAGE_NAME.getUnversionedPart()); + this.standardImage = dockerImageName.getUnversionedPart().equals(DEFAULT_IMAGE_NAME.getUnversionedPart()); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); @@ -101,39 +99,37 @@ public Neo4jContainer(final DockerImageName dockerImageName) { .withRegEx(String.format(".*Bolt enabled on .*:%d\\.\n", DEFAULT_BOLT_PORT)); WaitStrategy waitForHttp = new HttpWaitStrategy() .forPort(DEFAULT_HTTP_PORT) - .forStatusCodeMatching(response -> response == HTTP_OK); + .forStatusCodeMatching(response -> response == HttpURLConnection.HTTP_OK); - this.waitStrategy = new WaitAllStrategy() - .withStrategy(waitForBolt) - .withStrategy(waitForHttp) - .withStartupTimeout(Duration.ofMinutes(2)); + this.waitStrategy = + new WaitAllStrategy() + .withStrategy(waitForBolt) + .withStrategy(waitForHttp) + .withStartupTimeout(Duration.ofMinutes(2)); addExposedPorts(DEFAULT_BOLT_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); } @Override public Set getLivenessCheckPortNumbers() { - - return Stream.of(DEFAULT_BOLT_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT) + return Stream + .of(DEFAULT_BOLT_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT) .map(this::getMappedPort) - .collect(toSet()); + .collect(Collectors.toSet()); } @Override protected void configure() { - boolean emptyAdminPassword = this.adminPassword == null || this.adminPassword.isEmpty(); String neo4jAuth = emptyAdminPassword ? "none" : String.format(AUTH_FORMAT, this.adminPassword); addEnv("NEO4J_AUTH", neo4jAuth); if (!this.labsPlugins.isEmpty()) { - String enabledPlugins = this.labsPlugins.stream() - .map(pluginName -> "\"" + pluginName + "\"") - .collect(Collectors.joining(",")); + String enabledPlugins = + this.labsPlugins.stream().map(pluginName -> "\"" + pluginName + "\"").collect(Collectors.joining(",")); addEnv("NEO4JLABS_PLUGINS", "[" + enabledPlugins + "]"); } - } /** @@ -169,8 +165,8 @@ public String getHttpsUrl() { public S withEnterpriseEdition() { if (!standardImage) { throw new IllegalStateException( - String.format("Cannot use enterprise version with alternative image %s.", - getDockerImageName())); + String.format("Cannot use enterprise version with alternative image %s.", getDockerImageName()) + ); } setDockerImageName(DEFAULT_IMAGE_NAME.withTag(ENTERPRISE_TAG).asCanonicalNameString()); @@ -189,7 +185,6 @@ public S withEnterpriseEdition() { * @return This container. */ public S withAdminPassword(final String adminPassword) { - this.adminPassword = adminPassword; return self(); } @@ -226,7 +221,8 @@ public S withoutAuthentication() { public S withDatabase(MountableFile graphDb) { if (!isNeo4jDatabaseVersionSupportingDbCopy()) { throw new IllegalArgumentException( - "Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); + "Copying database folder is not supported for Neo4j instances with version 4.0 or higher." + ); } return withCopyFileToContainer(graphDb, "/data/databases/graph.db"); } @@ -254,7 +250,6 @@ public S withPlugins(MountableFile plugins) { * @return This container. */ public S withNeo4jConfig(String key, String value) { - addEnv(formatConfigurationKey(key), value); return self(); } @@ -273,7 +268,8 @@ public String getAdminPassword() { * @return This container. */ public S withLabsPlugins(Neo4jLabsPlugin... neo4jLabsPlugins) { - List pluginNames = Arrays.stream(neo4jLabsPlugins) + List pluginNames = Arrays + .stream(neo4jLabsPlugins) .map(plugin -> plugin.pluginName) .collect(Collectors.toList()); @@ -295,9 +291,7 @@ public S withLabsPlugins(String... neo4jLabsPlugins) { private static String formatConfigurationKey(String plainConfigKey) { final String prefix = "NEO4J_"; - return String.format("%s%s", prefix, plainConfigKey - .replaceAll("_", "__") - .replaceAll("\\.", "_")); + return String.format("%s%s", prefix, plainConfigKey.replaceAll("_", "__").replaceAll("\\.", "_")); } private boolean isNeo4jDatabaseVersionSupportingDbCopy() { @@ -311,9 +305,12 @@ private boolean isNeo4jDatabaseVersionSupportingDbCopy() { return true; } if (!usedComparableVersion.isSemanticVersion()) { - logger().warn("Version {} is not a semantic version. The function \"withDatabase\" will fail.", usedImageVersion); + logger() + .warn( + "Version {} is not a semantic version. The function \"withDatabase\" will fail.", + usedImageVersion + ); logger().warn("Copying databases is only supported for Neo4j versions 3.5.x"); - } return false; diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java index 6832dfff0c7..3a2df1f7d0c 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerJUnitIntegrationTest.java @@ -24,12 +24,11 @@ public class Neo4jContainerJUnitIntegrationTest { @Test public void shouldStart() { - boolean actual = neo4jContainer.isRunning(); assertThat(actual).isTrue(); - try (Driver driver = GraphDatabase - .driver(neo4jContainer.getBoltUrl(), AuthTokens.basic("neo4j", "password")); + try ( + Driver driver = GraphDatabase.driver(neo4jContainer.getBoltUrl(), AuthTokens.basic("neo4j", "password")); Session session = driver.session() ) { long one = session.run("RETURN 1", Collections.emptyMap()).next().get(0).asLong(); diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java index 0d3f04ef570..20cd38dc70c 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java @@ -29,17 +29,16 @@ public class Neo4jContainerTest { @Test public void shouldDisableAuthentication() { - try ( + // spotless:off // withoutAuthentication { Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") .withoutAuthentication() // } + // spotless:on ) { neo4jContainer.start(); - try (Driver driver = getDriver(neo4jContainer); - Session session = driver.session() - ) { + try (Driver driver = getDriver(neo4jContainer); Session session = driver.session()) { long one = session.run("RETURN 1", Collections.emptyMap()).next().get(0).asLong(); assertThat(one).isEqualTo(1L); } @@ -55,10 +54,7 @@ public void shouldCopyDatabase() { // } ) { neo4jContainer.start(); - try ( - Driver driver = getDriver(neo4jContainer); - Session session = driver.session() - ) { + try (Driver driver = getDriver(neo4jContainer); Session session = driver.session()) { Result result = session.run("MATCH (t:Thing) RETURN t"); assertThat(result.list().stream().map(r -> r.get("t").get("name").asString())) .containsExactlyInAnyOrder("Thing", "Thing 2", "Thing 3", "A box"); @@ -68,25 +64,29 @@ public void shouldCopyDatabase() { @Test public void shouldFailOnCopyDatabaseForDefaultNeo4j4Image() { - Assertions.assertThatIllegalArgumentException() - .isThrownBy(() -> new Neo4jContainer<>() - .withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) + Assertions + .assertThatIllegalArgumentException() + .isThrownBy(() -> new Neo4jContainer<>().withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) .withMessage("Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); } @Test public void shouldFailOnCopyDatabaseForCustomNeo4j4Image() { - Assertions.assertThatIllegalArgumentException() - .isThrownBy(() -> new Neo4jContainer<>("neo4j:4.4.1") - .withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) + Assertions + .assertThatIllegalArgumentException() + .isThrownBy(() -> { + new Neo4jContainer<>("neo4j:4.4.1").withDatabase(MountableFile.forClasspathResource("/test-graph.db")); + }) .withMessage("Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); } @Test public void shouldFailOnCopyDatabaseForCustomNonSemverNeo4j4Image() { - Assertions.assertThatIllegalArgumentException() - .isThrownBy(() -> new Neo4jContainer<>("neo4j:latest") - .withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) + Assertions + .assertThatIllegalArgumentException() + .isThrownBy(() -> { + new Neo4jContainer<>("neo4j:latest").withDatabase(MountableFile.forClasspathResource("/test-graph.db")); + }) .withMessage("Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); } @@ -99,10 +99,7 @@ public void shouldCopyPlugins() { // } ) { neo4jContainer.start(); - try ( - Driver driver = getDriver(neo4jContainer); - Session session = driver.session() - ) { + try (Driver driver = getDriver(neo4jContainer); Session session = driver.session()) { assertThatCustomPluginWasCopied(session); } } @@ -117,10 +114,7 @@ public void shouldCopyPlugin() { // } ) { neo4jContainer.start(); - try ( - Driver driver = getDriver(neo4jContainer); - Session session = driver.session() - ) { + try (Driver driver = getDriver(neo4jContainer); Session session = driver.session()) { assertThatCustomPluginWasCopied(session); } } @@ -152,17 +146,16 @@ public void shouldRunEnterprise() { // enterpriseEdition { Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") .withEnterpriseEdition() - // } + // } .withAdminPassword("Picard123") ) { neo4jContainer.start(); - try ( - Driver driver = getDriver(neo4jContainer); - Session session = driver.session() - ) { + try (Driver driver = getDriver(neo4jContainer); Session session = driver.session()) { String edition = session .run("CALL dbms.components() YIELD edition RETURN edition", Collections.emptyMap()) - .next().get(0).asString(); + .next() + .get(0) + .asString(); assertThat(edition).isEqualTo("enterprise"); } } @@ -178,31 +171,28 @@ public void shouldAddConfigToEnvironment() { assertThat(neo4jContainer.getEnvMap()) .containsEntry("NEO4J_dbms_security_procedures_unrestricted", "apoc.*,algo.*"); - assertThat(neo4jContainer.getEnvMap()) - .containsEntry("NEO4J_dbms_tx__log_rotation_size", "42M"); + assertThat(neo4jContainer.getEnvMap()).containsEntry("NEO4J_dbms_tx__log_rotation_size", "42M"); } @Test public void shouldConfigureSingleLabsPlugin() { - try (Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") - .withLabsPlugins(Neo4jLabsPlugin.APOC)) { - - + try ( + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4").withLabsPlugins(Neo4jLabsPlugin.APOC) + ) { // needs to get called explicitly for setup neo4jContainer.configure(); - assertThat(neo4jContainer.getEnvMap()) - .containsEntry("NEO4JLABS_PLUGINS", "[\"apoc\"]"); + assertThat(neo4jContainer.getEnvMap()).containsEntry("NEO4JLABS_PLUGINS", "[\"apoc\"]"); } } @Test public void shouldConfigureMultipleLabsPlugins() { - try( - // configureLabsPlugins { - Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") - .withLabsPlugins(Neo4jLabsPlugin.APOC, Neo4jLabsPlugin.BLOOM); - // } + try ( + // configureLabsPlugins { + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") + .withLabsPlugins(Neo4jLabsPlugin.APOC, Neo4jLabsPlugin.BLOOM); + // } ) { // needs to get called explicitly for setup neo4jContainer.configure(); @@ -214,23 +204,19 @@ public void shouldConfigureMultipleLabsPlugins() { @Test public void shouldConfigureSingleLabsPluginWithString() { - try (Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") - .withLabsPlugins("myApoc")) { - + try (Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4").withLabsPlugins("myApoc")) { // needs to get called explicitly for setup neo4jContainer.configure(); - assertThat(neo4jContainer.getEnvMap()) - .containsEntry("NEO4JLABS_PLUGINS", "[\"myApoc\"]"); + assertThat(neo4jContainer.getEnvMap()).containsEntry("NEO4JLABS_PLUGINS", "[\"myApoc\"]"); } } @Test public void shouldConfigureMultipleLabsPluginsWithString() { - - try (Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4") - .withLabsPlugins("myApoc", "myBloom")) { - + try ( + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4").withLabsPlugins("myApoc", "myBloom") + ) { // needs to get called explicitly for setup neo4jContainer.configure(); @@ -240,7 +226,6 @@ public void shouldConfigureMultipleLabsPluginsWithString() { } private static Driver getDriver(Neo4jContainer container) { - AuthToken authToken = AuthTokens.none(); if (container.getAdminPassword() != null) { authToken = AuthTokens.basic("neo4j", container.getAdminPassword()); diff --git a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java index 296d82b7997..3e7a2062fd0 100644 --- a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java +++ b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java @@ -12,10 +12,14 @@ /** * @author richardnorth */ -public class NginxContainer> extends GenericContainer implements LinkableContainer { +public class NginxContainer> + extends GenericContainer + implements LinkableContainer { private static final int NGINX_DEFAULT_PORT = 80; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("nginx"); + private static final String DEFAULT_TAG = "1.9.4"; /** @@ -32,7 +36,6 @@ public NginxContainer(String dockerImageName) { public NginxContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPort(NGINX_DEFAULT_PORT); diff --git a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java index e322804bf75..c1ba3d30684 100644 --- a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java +++ b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java @@ -12,7 +12,7 @@ import java.net.URL; import java.net.URLConnection; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.rnorth.visibleassertions.VisibleAssertions.*; /** @@ -29,9 +29,10 @@ public class SimpleNginxTest { public NginxContainer nginx = new NginxContainer<>(NGINX_IMAGE) .withCustomContent(tmpDirectory) .waitingFor(new HttpWaitStrategy()); + // } - @SuppressWarnings({"Duplicates", "ResultOfMethodCallIgnored"}) + @SuppressWarnings({ "Duplicates", "ResultOfMethodCallIgnored" }) @BeforeClass public static void setupContent() throws Exception { // addCustomContent { @@ -43,7 +44,8 @@ public static void setupContent() throws Exception { // And "hello world" HTTP file File indexFile = new File(contentFolder, "index.html"); indexFile.deleteOnExit(); - @Cleanup PrintStream printStream = new PrintStream(new FileOutputStream(indexFile)); + @Cleanup + PrintStream printStream = new PrintStream(new FileOutputStream(indexFile)); printStream.println("Hello World!"); // } } @@ -53,7 +55,8 @@ public void testSimple() throws Exception { // getFromNginxServer { URL baseUrl = nginx.getBaseUrl("http", 80); - assertThat("An HTTP GET from the Nginx server returns the index.html from the custom content directory", + assertThat( + "An HTTP GET from the Nginx server returns the index.html from the custom content directory", responseFromNginx(baseUrl), containsString("Hello World!") ); @@ -62,7 +65,8 @@ public void testSimple() throws Exception { private static String responseFromNginx(URL baseUrl) throws IOException { URLConnection urlConnection = baseUrl.openConnection(); - @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + @Cleanup + BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); return reader.readLine(); } } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java index 689646f0006..bd5d9aeb7ca 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java @@ -1,50 +1,59 @@ package org.testcontainers.containers; -import com.google.common.collect.Sets; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.Future; -import static java.time.temporal.ChronoUnit.SECONDS; -import static java.util.Collections.singleton; - public class OracleContainer extends JdbcDatabaseContainer { public static final String NAME = "oracle"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe"); static final String DEFAULT_TAG = "18.4.0-slim"; + static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); private static final int ORACLE_PORT = 1521; + private static final int APEX_HTTP_PORT = 8080; private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240; + private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 120; // Container defaults static final String DEFAULT_DATABASE_NAME = "xepdb1"; + static final String DEFAULT_SID = "xe"; + static final String DEFAULT_SYSTEM_USER = "system"; + static final String DEFAULT_SYS_USER = "sys"; // Test container defaults static final String APP_USER = "test"; + static final String APP_USER_PASSWORD = "test"; // Restricted user and database names private static final List ORACLE_SYSTEM_USERS = Arrays.asList(DEFAULT_SYSTEM_USER, DEFAULT_SYS_USER); private String databaseName = DEFAULT_DATABASE_NAME; + private String username = APP_USER; + private String password = APP_USER_PASSWORD; + private boolean usingSid = false; /** @@ -71,10 +80,11 @@ public OracleContainer(Future dockerImageName) { } private void preconfigure() { - this.waitStrategy = new LogMessageWaitStrategy() - .withRegEx(".*DATABASE IS READY TO USE!.*\\s") - .withTimes(1) - .withStartupTimeout(Duration.of(DEFAULT_STARTUP_TIMEOUT_SECONDS, SECONDS)); + this.waitStrategy = + new LogMessageWaitStrategy() + .withRegEx(".*DATABASE IS READY TO USE!.*\\s") + .withTimes(1) + .withStartupTimeout(Duration.of(DEFAULT_STARTUP_TIMEOUT_SECONDS, ChronoUnit.SECONDS)); withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT); @@ -88,7 +98,7 @@ protected void waitUntilContainerStarted() { @NotNull @Override public Set getLivenessCheckPortNumbers() { - return singleton(getMappedPort(ORACLE_PORT)); + return Collections.singleton(getMappedPort(ORACLE_PORT)); } @Override @@ -98,9 +108,9 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return isUsingSid() ? - "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + ":" + getSid() : - "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + "/" + getDatabaseName(); + return isUsingSid() + ? "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + ":" + getSid() + : "jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + "/" + getDatabaseName(); } @Override @@ -192,7 +202,7 @@ protected void configure() { withEnv("ORACLE_PASSWORD", password); // Only set ORACLE_DATABASE if different than the default. - if(databaseName != DEFAULT_DATABASE_NAME) { + if (databaseName != DEFAULT_DATABASE_NAME) { withEnv("ORACLE_DATABASE", databaseName); } diff --git a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java index a298ae23359..f92f0ec40be 100644 --- a/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java +++ b/modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainerProvider.java @@ -6,6 +6,7 @@ * Factory for Oracle containers. */ public class OracleContainerProvider extends JdbcDatabaseContainerProvider { + @Override public boolean supports(String databaseType) { return databaseType.equals(OracleContainer.NAME); diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java index 79dc35deb64..003941f4dfc 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java @@ -4,7 +4,6 @@ import com.zaxxer.hikari.HikariDataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; -import org.junit.Ignore; import org.junit.Test; import java.sql.ResultSet; @@ -19,18 +18,21 @@ public void testOracleWithNoSpecifiedVersion() throws SQLException { performSimpleTest("jdbc:tc:oracle://hostname/databasename"); } - private void performSimpleTest(String jdbcUrl) throws SQLException { HikariDataSource dataSource = getDataSource(jdbcUrl, 1); - new QueryRunner(dataSource).query("SELECT 1 FROM dual", new ResultSetHandler() { - @Override - public Object handle(ResultSet rs) throws SQLException { - rs.next(); - int resultSetInt = rs.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); - return true; - } - }); + new QueryRunner(dataSource) + .query( + "SELECT 1 FROM dual", + new ResultSetHandler() { + @Override + public Object handle(ResultSet rs) throws SQLException { + rs.next(); + int resultSetInt = rs.getInt(1); + assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + return true; + } + } + ); dataSource.close(); } diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java index 2dd82c437a4..2c514062415 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java @@ -1,8 +1,5 @@ package org.testcontainers.junit.oracle; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - import org.junit.Test; import org.testcontainers.containers.OracleContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -11,16 +8,22 @@ import java.sql.ResultSet; import java.sql.SQLException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + public class SimpleOracleTest extends AbstractContainerDatabaseTest { - public static final DockerImageName ORACLE_DOCKER_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe:18.4.0-slim"); + public static final DockerImageName ORACLE_DOCKER_IMAGE_NAME = DockerImageName.parse( + "gvenzl/oracle-xe:18.4.0-slim" + ); - private void runTest(OracleContainer container, String databaseName, String username, String password) throws SQLException { + private void runTest(OracleContainer container, String databaseName, String username, String password) + throws SQLException { //Test config was honored assertEquals(databaseName, container.getDatabaseName()); assertEquals(username, container.getUsername()); assertEquals(password, container.getPassword()); - + //Test we can get a connection container.start(); ResultSet resultSet = performQuery(container, "SELECT 1 FROM dual"); @@ -30,9 +33,7 @@ private void runTest(OracleContainer container, String databaseName, String user @Test public void testDefaultSettings() throws SQLException { - try ( - OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME); - ) { + try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME);) { runTest(oracle, "xepdb1", "test", "test"); // Match against the last '/' @@ -43,10 +44,7 @@ public void testDefaultSettings() throws SQLException { @Test public void testPluggableDatabase() throws SQLException { - try ( - OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) - .withDatabaseName("testDB") - ) { + try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME).withDatabaseName("testDB")) { runTest(oracle, "testDB", "test", "test"); } } @@ -76,10 +74,7 @@ public void testCustomUser() throws SQLException { @Test public void testSID() throws SQLException { - try ( - OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) - .usingSid(); - ) { + try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME).usingSid();) { runTest(oracle, "xepdb1", "system", "test"); // Match against the last ':' diff --git a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java index a68f55b60ef..2f606475dc0 100644 --- a/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java +++ b/modules/orientdb/src/main/java/org/testcontainers/containers/OrientDBContainer.java @@ -21,25 +21,33 @@ * @author robfrank */ public class OrientDBContainer extends GenericContainer { + private static final Logger LOGGER = LoggerFactory.getLogger(OrientDBContainer.class); private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("orientdb"); + private static final String DEFAULT_TAG = "3.0.24-tp3"; private static final String DEFAULT_USERNAME = "admin"; + private static final String DEFAULT_PASSWORD = "admin"; + private static final String DEFAULT_SERVER_PASSWORD = "root"; private static final String DEFAULT_DATABASE_NAME = "testcontainers"; private static final int DEFAULT_BINARY_PORT = 2424; + private static final int DEFAULT_HTTP_PORT = 2480; private String databaseName; + private String serverPassword; + private Optional scriptPath = Optional.empty(); private OrientDB orientDB; + private ODatabaseSession session; /** @@ -56,13 +64,12 @@ public OrientDBContainer(@NonNull String dockerImageName) { public OrientDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); serverPassword = DEFAULT_SERVER_PASSWORD; databaseName = DEFAULT_DATABASE_NAME; - waitStrategy = new LogMessageWaitStrategy().withRegEx(".*Gremlin started correctly.*"); + waitStrategy = new LogMessageWaitStrategy().withRegEx(".*Gremlin started correctly.*"); addExposedPorts(DEFAULT_BINARY_PORT, DEFAULT_HTTP_PORT); } @@ -133,7 +140,9 @@ private void loadScript(String path, ODatabaseSession session) { if (resource == null) { LOGGER.warn("Could not load classpath init script: {}", scriptPath); - throw new RuntimeException("Could not load classpath init script: " + scriptPath + ". Resource not found."); + throw new RuntimeException( + "Could not load classpath init script: " + scriptPath + ". Resource not found." + ); } String script = IOUtils.toString(resource, StandardCharsets.UTF_8); @@ -147,5 +156,4 @@ private void loadScript(String path, ODatabaseSession session) { throw new RuntimeException("Error while executing init script: " + scriptPath, e); } } - } diff --git a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java index 60d7b172436..675218637ce 100644 --- a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java +++ b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java @@ -42,7 +42,6 @@ public void shouldInitializeWithCommands() { @Test public void shouldQueryWithGremlin() { - try (OrientDBContainer container = new OrientDBContainer(ORIENTDB_IMAGE)) { container.start(); @@ -52,17 +51,17 @@ public void shouldQueryWithGremlin() { session.command("INSERT INTO Person set name='john'"); session.command("INSERT INTO Person set name='jane'"); - assertThat(session.execute("gremlin", - "g.V().hasLabel('Person')").stream()).hasSize(2); + assertThat(session.execute("gremlin", "g.V().hasLabel('Person')").stream()).hasSize(2); } } @Test public void shouldInitializeDatabaseFromScript() { - try (OrientDBContainer container = new OrientDBContainer(ORIENTDB_IMAGE) - .withScriptPath("initscript.osql") - .withDatabaseName("persons")) { - + try ( + OrientDBContainer container = new OrientDBContainer(ORIENTDB_IMAGE) + .withScriptPath("initscript.osql") + .withDatabaseName("persons") + ) { container.start(); assertThat(container.getDbUrl()) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java index e41a349365c..0c30ebbb246 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgisContainerProvider.java @@ -9,11 +9,16 @@ public class PostgisContainerProvider extends JdbcDatabaseContainerProvider { private static final String NAME = "postgis"; - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("postgis/postgis").asCompatibleSubstituteFor("postgres"); + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName + .parse("postgis/postgis") + .asCompatibleSubstituteFor("postgres"); + private static final String DEFAULT_TAG = "12-3.0"; + public static final String USER_PARAM = "user"; - public static final String PASSWORD_PARAM = "password"; + public static final String PASSWORD_PARAM = "password"; @Override public boolean supports(String databaseType) { diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 741a8c4139a..3b36b61ea77 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -5,19 +5,21 @@ import org.testcontainers.utility.DockerImageName; import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Collections; import java.util.Set; -import static java.time.temporal.ChronoUnit.SECONDS; -import static java.util.Collections.singleton; - /** * @author richardnorth */ public class PostgreSQLContainer> extends JdbcDatabaseContainer { + public static final String NAME = "postgresql"; + public static final String IMAGE = "postgres"; public static final String DEFAULT_TAG = "9.6.12"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("postgres"); public static final Integer POSTGRESQL_PORT = 5432; @@ -27,7 +29,9 @@ public class PostgreSQLContainer> extends static final String DEFAULT_PASSWORD = "test"; private String databaseName = "test"; + private String username = "test"; + private String password = "test"; private static final String FSYNC_OFF_OPTION = "fsync=off"; @@ -46,13 +50,13 @@ public PostgreSQLContainer(final String dockerImageName) { public PostgreSQLContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); - this.waitStrategy = new LogMessageWaitStrategy() + this.waitStrategy = + new LogMessageWaitStrategy() .withRegEx(".*database system is ready to accept connections.*\\s") .withTimes(2) - .withStartupTimeout(Duration.of(60, SECONDS)); + .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS)); this.setCommand("postgres", "-c", FSYNC_OFF_OPTION); addExposedPort(POSTGRESQL_PORT); @@ -61,7 +65,7 @@ public PostgreSQLContainer(final DockerImageName dockerImageName) { @NotNull @Override protected Set getLivenessCheckPorts() { - return singleton(getMappedPort(POSTGRESQL_PORT)); + return Collections.singleton(getMappedPort(POSTGRESQL_PORT)); } @Override @@ -81,8 +85,15 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { String additionalUrlParams = constructUrlParameters("?", "&"); - return "jdbc:postgresql://" + getHost() + ":" + getMappedPort(POSTGRESQL_PORT) - + "/" + databaseName + additionalUrlParams; + return ( + "jdbc:postgresql://" + + getHost() + + ":" + + getMappedPort(POSTGRESQL_PORT) + + "/" + + databaseName + + additionalUrlParams + ); } @Override diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java index 5e7580c75eb..de98885510c 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainerProvider.java @@ -9,6 +9,7 @@ public class PostgreSQLContainerProvider extends JdbcDatabaseContainerProvider { public static final String USER_PARAM = "user"; + public static final String PASSWORD_PARAM = "password"; @Override @@ -30,5 +31,4 @@ public JdbcDatabaseContainer newInstance(String tag) { public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); } - } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java index 88b5497f5d3..d2b933694c7 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java @@ -13,7 +13,8 @@ public final class PostgreSQLR2DBCDatabaseContainer implements R2DBCDatabaseCont private final PostgreSQLContainer container; public static ConnectionFactoryOptions getOptions(PostgreSQLContainer container) { - ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + ConnectionFactoryOptions options = ConnectionFactoryOptions + .builder() .option(ConnectionFactoryOptions.DRIVER, PostgreSQLR2DBCDatabaseContainerProvider.DRIVER) .build(); @@ -22,7 +23,8 @@ public static ConnectionFactoryOptions getOptions(PostgreSQLContainer contain @Override public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) { - return options.mutate() + return options + .mutate() .option(ConnectionFactoryOptions.HOST, container.getHost()) .option(ConnectionFactoryOptions.PORT, container.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT)) .option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName()) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java b/modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java index c9b81fccfe4..86fcca2c039 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/TimescaleDBContainerProvider.java @@ -11,11 +11,16 @@ public class TimescaleDBContainerProvider extends JdbcDatabaseContainerProvider { private static final String NAME = "timescaledb"; + private static final String DEFAULT_TAG = "2.1.0-pg11"; - private static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("timescale/timescaledb").asCompatibleSubstituteFor("postgres"); + + private static final DockerImageName DEFAULT_IMAGE = DockerImageName + .parse("timescale/timescaledb") + .asCompatibleSubstituteFor("postgres"); + public static final String USER_PARAM = "user"; - public static final String PASSWORD_PARAM = "password"; + public static final String PASSWORD_PARAM = "password"; @Override public boolean supports(String databaseType) { diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index c18f19a109e..3be7685ea27 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -16,7 +16,10 @@ public void shouldCorrectlyAppendQueryString() { String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); - assertTrue("Query String contains expected params", queryString.contains("?stringtype=unspecified&stringtype=unspecified")); + assertTrue( + "Query String contains expected params", + queryString.contains("?stringtype=unspecified&stringtype=unspecified") + ); assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); } @@ -27,7 +30,10 @@ public void shouldCorrectlyAppendQueryStringWhenNoBaseParams() { String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); - assertTrue("Query String contains expected params", queryString.contains("?stringtype=unspecified&stringtype=unspecified")); + assertTrue( + "Query String contains expected params", + queryString.contains("?stringtype=unspecified&stringtype=unspecified") + ); assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); } @@ -42,11 +48,15 @@ public void shouldReturnOriginalURLWhenEmptyQueryString() { @Test public void shouldRejectInvalidQueryString() { - assertThrows("Fails when invalid query string provided", IllegalArgumentException.class, - () -> new NoParamsUrlPostgreSQLContainer().constructUrlForConnection("stringtype=unspecified")); + assertThrows( + "Fails when invalid query string provided", + IllegalArgumentException.class, + () -> new NoParamsUrlPostgreSQLContainer().constructUrlForConnection("stringtype=unspecified") + ); } static class FixedJdbcUrlPostgreSQLContainer extends PostgreSQLContainer { + public FixedJdbcUrlPostgreSQLContainer() { super(PostgreSQLTestImages.POSTGRES_TEST_IMAGE); } @@ -63,6 +73,7 @@ public Integer getMappedPort(int originalPort) { } static class NoParamsUrlPostgreSQLContainer extends PostgreSQLContainer { + public NoParamsUrlPostgreSQLContainer() { super(PostgreSQLTestImages.POSTGRES_TEST_IMAGE); } diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java index 46e439aaf66..fb503bfd659 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java @@ -13,11 +13,13 @@ protected PostgreSQLContainer createContainer() { @Override protected ConnectionFactoryOptions getOptions(PostgreSQLContainer container) { + // spotless:off // get_options { ConnectionFactoryOptions options = PostgreSQLR2DBCDatabaseContainer.getOptions( container ); // } + // spotless:on return options; } diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java index f3c73a4111b..74d60b2d32d 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java @@ -24,10 +24,17 @@ public void testSimple() throws SQLException { @Test public void testCommandOverride() throws SQLException { - try (GenericContainer postgres = new TimescaleDBContainerProvider().newInstance().withCommand("postgres -c max_connections=42")) { + try ( + GenericContainer postgres = new TimescaleDBContainerProvider() + .newInstance() + .withCommand("postgres -c max_connections=42") + ) { postgres.start(); - ResultSet resultSet = performQuery((JdbcDatabaseContainer) postgres, "SELECT current_setting('max_connections')"); + ResultSet resultSet = performQuery( + (JdbcDatabaseContainer) postgres, + "SELECT current_setting('max_connections')" + ); String result = resultSet.getString(1); assertEquals("max_connections should be overriden", "42", result); } @@ -35,10 +42,18 @@ public void testCommandOverride() throws SQLException { @Test public void testUnsetCommand() throws SQLException { - try (GenericContainer postgres = new TimescaleDBContainerProvider().newInstance().withCommand("postgres -c max_connections=42").withCommand()) { + try ( + GenericContainer postgres = new TimescaleDBContainerProvider() + .newInstance() + .withCommand("postgres -c max_connections=42") + .withCommand() + ) { postgres.start(); - ResultSet resultSet = performQuery((JdbcDatabaseContainer) postgres, "SELECT current_setting('max_connections')"); + ResultSet resultSet = performQuery( + (JdbcDatabaseContainer) postgres, + "SELECT current_setting('max_connections')" + ); String result = resultSet.getString(1); assertNotEquals("max_connections should not be overriden", "42", result); } @@ -46,7 +61,11 @@ public void testUnsetCommand() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (JdbcDatabaseContainer postgres = new TimescaleDBContainerProvider().newInstance().withInitScript("somepath/init_timescaledb.sql")) { + try ( + JdbcDatabaseContainer postgres = new TimescaleDBContainerProvider() + .newInstance() + .withInitScript("somepath/init_timescaledb.sql") + ) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java index 9e3e0b03413..5acbd875c23 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java @@ -19,6 +19,7 @@ * TODO: Move to the jdbc module and either (a) implement a barebones {@link org.testcontainers.containers.JdbcDatabaseContainerProvider} for testing, or (b) refactor into a unit test. */ public class DatabaseDriverShutdownTest { + @AfterClass public static void testCleanup() { ContainerDatabaseDriver.killContainers(); diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java index a2b1fd5da8b..4c8d6afeef0 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -22,7 +22,6 @@ public class DatabaseDriverTmpfsTest { public void testDatabaseHasTmpFsViaConnectionString() throws Exception { final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_TMPFS=/testtmpfs:rw"; try (Connection ignored = DriverManager.getConnection(jdbcUrl)) { - JdbcDatabaseContainer container = ContainerDatabaseDriver.getContainer(jdbcUrl); // check file doesn't exist String path = "/testtmpfs/test.file"; diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java index b1d01441016..abc0a3b76bc 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgis/PostgisJDBCDriverTest.java @@ -4,19 +4,25 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class PostgisJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - {"jdbc:tc:postgis:9.6-2.5://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - }); + return Arrays.asList( + new Object[][] { + { + "jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", + EnumSet.of(Options.JDBCParams), + }, + { + "jdbc:tc:postgis:9.6-2.5://hostname/databasename?user=someuser&password=somepwd", + EnumSet.of(Options.JDBCParams), + }, + } + ); } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java index c63eb9ffb9d..d42f17f3ec2 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/postgresql/PostgreSQLJDBCDriverTest.java @@ -4,18 +4,21 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class PostgreSQLJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - }); + return Arrays.asList( + new Object[][] { + { + "jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", + EnumSet.of(Options.JDBCParams), + }, + } + ); } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java index 8a6eaa3d04b..2a50b46c901 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/timescaledb/TimescaleDBJDBCDriverTest.java @@ -4,19 +4,25 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class TimescaleDBJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:timescaledb://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - {"jdbc:tc:timescaledb:2.1.0-pg13://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)}, - }); + return Arrays.asList( + new Object[][] { + { + "jdbc:tc:timescaledb://hostname/databasename?user=someuser&password=somepwd", + EnumSet.of(Options.JDBCParams), + }, + { + "jdbc:tc:timescaledb:2.1.0-pg13://hostname/databasename?user=someuser&password=somepwd", + EnumSet.of(Options.JDBCParams), + }, + } + ); } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java index 8fd523434dd..1b256c0fd6b 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java @@ -14,17 +14,21 @@ * @author richardnorth */ public class CustomizablePostgreSQLTest extends AbstractContainerDatabaseTest { + private static final String DB_NAME = "foo"; + private static final String USER = "bar"; + private static final String PWD = "baz"; @Test public void testSimple() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) + try ( + PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) .withDatabaseName(DB_NAME) .withUsername(USER) - .withPassword(PWD)) { - + .withPassword(PWD) + ) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT 1"); diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 95e1fdf10fd..2a0dd351ad6 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -1,6 +1,7 @@ package org.testcontainers.junit.postgresql; import org.junit.Test; +import org.testcontainers.PostgreSQLTestImages; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -9,14 +10,12 @@ import java.util.logging.Level; import java.util.logging.LogManager; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; -import static org.testcontainers.PostgreSQLTestImages.POSTGRES_TEST_IMAGE; public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { - static { // Postgres JDBC driver uses JUL; disable it to avoid annoying, irrelevant, stderr logs during connection testing LogManager.getLogManager().getLogger("").setLevel(Level.OFF); @@ -24,7 +23,7 @@ public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { @Test public void testSimple() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE)) { + try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT 1"); @@ -35,7 +34,10 @@ public void testSimple() throws SQLException { @Test public void testCommandOverride() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE).withCommand("postgres -c max_connections=42")) { + try ( + PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) + .withCommand("postgres -c max_connections=42") + ) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); @@ -46,7 +48,11 @@ public void testCommandOverride() throws SQLException { @Test public void testUnsetCommand() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE).withCommand("postgres -c max_connections=42").withCommand()) { + try ( + PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) + .withCommand("postgres -c max_connections=42") + .withCommand() + ) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); @@ -57,7 +63,10 @@ public void testUnsetCommand() throws SQLException { @Test public void testExplicitInitScript() throws SQLException { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE).withInitScript("somepath/init_postgresql.sql")) { + try ( + PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) + .withInitScript("somepath/init_postgresql.sql") + ) { postgres.start(); ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); @@ -69,9 +78,10 @@ public void testExplicitInitScript() throws SQLException { @Test public void testWithAdditionalUrlParamInJdbcUrl() { - try (PostgreSQLContainer postgres = new PostgreSQLContainer<>(POSTGRES_TEST_IMAGE) - .withUrlParam("charSet", "UNICODE")) { - + try ( + PostgreSQLContainer postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) + .withUrlParam("charSet", "UNICODE") + ) { postgres.start(); String jdbcUrl = postgres.getJdbcUrl(); assertThat(jdbcUrl, containsString("?")); diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index 30d77c1a469..e73f6cc0f6b 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -1,5 +1,6 @@ package org.testcontainers.containers; +import com.google.common.base.Strings; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; @@ -7,26 +8,28 @@ import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.Set; -import static com.google.common.base.Strings.nullToEmpty; -import static java.lang.String.format; -import static java.time.temporal.ChronoUnit.SECONDS; - /** * @deprecated Use {@code TrinoContainer} instead. */ @Deprecated public class PrestoContainer> extends JdbcDatabaseContainer { + public static final String NAME = "presto"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("ghcr.io/trinodb/presto"); + public static final String IMAGE = "ghcr.io/trinodb/presto"; + public static final String DEFAULT_TAG = "344"; public static final Integer PRESTO_PORT = 8080; private String username = "test"; + private String catalog = null; /** @@ -43,12 +46,12 @@ public PrestoContainer(final String dockerImageName) { public PrestoContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); - this.waitStrategy = new LogMessageWaitStrategy() - .withRegEx(".*======== SERVER STARTED ========.*") - .withStartupTimeout(Duration.of(60, SECONDS)); + this.waitStrategy = + new LogMessageWaitStrategy() + .withRegEx(".*======== SERVER STARTED ========.*") + .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS)); addExposedPort(PRESTO_PORT); } @@ -66,7 +69,12 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return format("jdbc:presto://%s:%s/%s", getHost(), getMappedPort(PRESTO_PORT), nullToEmpty(catalog)); + return String.format( + "jdbc:presto://%s:%s/%s", + getHost(), + getMappedPort(PRESTO_PORT), + Strings.nullToEmpty(catalog) + ); } @Override diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java index 8408aab4517..f37efb9438e 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainerProvider.java @@ -9,6 +9,7 @@ public class PrestoContainerProvider extends JdbcDatabaseContainerProvider { public static final String USER_PARAM = "user"; + public static final String PASSWORD_PARAM = "password"; @Override @@ -30,5 +31,4 @@ public JdbcDatabaseContainer newInstance(String tag) { public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) { return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM); } - } diff --git a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java index d5a4d9587a6..a54108ea1a2 100644 --- a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java +++ b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java @@ -3,7 +3,6 @@ import org.junit.Assert; import org.junit.Test; import org.testcontainers.PrestoTestImages; -import org.testcontainers.utility.DockerImageName; import java.sql.Connection; import java.sql.DriverManager; @@ -14,8 +13,6 @@ import java.util.Arrays; import java.util.List; -import static java.lang.Integer.parseInt; -import static java.lang.String.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -29,9 +26,11 @@ public class PrestoContainerTest { public void testSimple() throws Exception { try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_TEST_IMAGE)) { prestoSql.start(); - try (Connection connection = prestoSql.createConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + try ( + Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") + ) { assertTrue("No result", resultSet.next()); assertEquals("Presto version", PrestoContainer.DEFAULT_TAG, resultSet.getString("node_version")); } @@ -40,13 +39,21 @@ public void testSimple() throws Exception { @Test public void testSpecificVersion() throws Exception { - try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE)) { + try ( + PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE) + ) { prestoSql.start(); - try (Connection connection = prestoSql.createConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + try ( + Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") + ) { assertTrue("No result", resultSet.next()); - assertEquals("Presto version", PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), resultSet.getString("node_version")); + assertEquals( + "Presto version", + PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), + resultSet.getString("node_version") + ); } } } @@ -55,18 +62,26 @@ public void testSpecificVersion() throws Exception { public void testQueryMemoryAndTpch() throws SQLException { try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_TEST_IMAGE)) { prestoSql.start(); - try (Connection connection = prestoSql.createConnection(); - Statement statement = connection.createStatement()) { + try ( + Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement() + ) { // Prepare data - statement.execute("CREATE TABLE memory.default.table_with_array AS SELECT 1 id, ARRAY[1, 42, 2, 42, 4, 42] my_array"); + statement.execute( + "CREATE TABLE memory.default.table_with_array AS SELECT 1 id, ARRAY[1, 42, 2, 42, 4, 42] my_array" + ); // Query Presto using newly created table and a builtin connector - try (ResultSet resultSet = statement.executeQuery("" + - "SELECT nationkey, element " + - "FROM tpch.tiny.nation " + - "JOIN memory.default.table_with_array twa ON nationkey = twa.id " + - "LEFT JOIN UNNEST(my_array) a(element) ON true " + - "ORDER BY element OFFSET 1 FETCH NEXT 3 ROWS WITH TIES ")) { + try ( + ResultSet resultSet = statement.executeQuery( + "" + + "SELECT nationkey, element " + + "FROM tpch.tiny.nation " + + "JOIN memory.default.table_with_array twa ON nationkey = twa.id " + + "LEFT JOIN UNNEST(my_array) a(element) ON true " + + "ORDER BY element OFFSET 1 FETCH NEXT 3 ROWS WITH TIES " + ) + ) { List actualElements = new ArrayList<>(); while (resultSet.next()) { actualElements.add(resultSet.getInt("element")); @@ -82,9 +97,11 @@ public void testInitScript() throws Exception { try (PrestoContainer prestoSql = new PrestoContainer<>(PrestoTestImages.PRESTO_TEST_IMAGE)) { prestoSql.withInitScript("initial.sql"); prestoSql.start(); - try (Connection connection = prestoSql.createConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table")) { + try ( + Connection connection = prestoSql.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table") + ) { assertTrue("No result", resultSet.next()); assertEquals("Value", 12345678909324L, resultSet.getObject("a")); assertFalse("Too many result", resultSet.next()); @@ -94,19 +111,38 @@ public void testInitScript() throws Exception { @Test public void testTcJdbcUri() throws Exception { - try (Connection connection = DriverManager.getConnection(format("jdbc:tc:presto:%s://hostname/", PrestoContainer.DEFAULT_TAG))) { + try ( + Connection connection = DriverManager.getConnection( + String.format("jdbc:tc:presto:%s://hostname/", PrestoContainer.DEFAULT_TAG) + ) + ) { // Verify metadata with tc: JDBC connection URI - assertEquals(connection.getMetaData().getDatabaseMajorVersion(), parseInt(PrestoContainer.DEFAULT_TAG)); + assertEquals( + connection.getMetaData().getDatabaseMajorVersion(), + Integer.parseInt(PrestoContainer.DEFAULT_TAG) + ); // Verify transactions with tc: JDBC connection URI assertTrue("Is autocommit", connection.getAutoCommit()); connection.setAutoCommit(false); assertFalse("Is autocommit", connection.getAutoCommit()); - assertEquals("Transaction isolation", Connection.TRANSACTION_READ_UNCOMMITTED, connection.getTransactionIsolation()); + assertEquals( + "Transaction isolation", + Connection.TRANSACTION_READ_UNCOMMITTED, + connection.getTransactionIsolation() + ); try (Statement statement = connection.createStatement()) { - assertEquals("Update result", 0, statement.executeUpdate("CREATE TABLE memory.default.test_tc(a bigint)")); - try (ResultSet resultSet = statement.executeQuery("SELECT sum(cast(node_version AS bigint)) AS v FROM system.runtime.nodes")) { + assertEquals( + "Update result", + 0, + statement.executeUpdate("CREATE TABLE memory.default.test_tc(a bigint)") + ); + try ( + ResultSet resultSet = statement.executeQuery( + "SELECT sum(cast(node_version AS bigint)) AS v FROM system.runtime.nodes" + ) + ) { assertTrue(resultSet.next()); assertEquals(PrestoContainer.DEFAULT_TAG, resultSet.getString("v")); assertFalse(resultSet.next()); @@ -117,7 +153,11 @@ public void testTcJdbcUri() throws Exception { } connection.setAutoCommit(true); assertTrue("Is autocommit", connection.getAutoCommit()); - assertEquals("Transaction isolation should be retained", Connection.TRANSACTION_READ_UNCOMMITTED, connection.getTransactionIsolation()); + assertEquals( + "Transaction isolation should be retained", + Connection.TRANSACTION_READ_UNCOMMITTED, + connection.getTransactionIsolation() + ); } } } diff --git a/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java b/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java index d1a64c92aaa..9c5dd712104 100644 --- a/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java +++ b/modules/presto/src/test/java/org/testcontainers/jdbc/presto/PrestoJDBCDriverTest.java @@ -4,18 +4,18 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class PrestoJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:presto:344://hostname/", EnumSet.of(Options.PmdKnownBroken)}, - }); + return Arrays.asList( + new Object[][] { // + { "jdbc:tc:presto:344://hostname/", EnumSet.of(Options.PmdKnownBroken) }, + } + ); } } diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index b3c836b56a5..9b14e90d736 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -10,10 +10,13 @@ public class PulsarContainer extends GenericContainer { public static final int BROKER_PORT = 6650; + public static final int BROKER_HTTP_PORT = 8080; + public static final String METRICS_ENDPOINT = "/metrics"; private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("apachepulsar/pulsar"); + @Deprecated private static final String DEFAULT_TAG = "2.2.0"; @@ -37,7 +40,6 @@ public PulsarContainer(String pulsarVersion) { public PulsarContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DockerImageName.parse("apachepulsar/pulsar")); withExposedPorts(BROKER_PORT, BROKER_HTTP_PORT); diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index f2354d98ef7..6d739dfbf98 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -18,6 +18,7 @@ public class PulsarContainerTest { public static final String TEST_TOPIC = "test_topic"; + private static final DockerImageName PULSAR_IMAGE = DockerImageName.parse("apachepulsar/pulsar:2.2.0"); @Test @@ -33,9 +34,7 @@ public void shouldNotEnableFunctionsWorkerByDefault() throws Exception { try (PulsarContainer pulsar = new PulsarContainer("2.5.1")) { pulsar.start(); - PulsarAdmin pulsarAdmin = PulsarAdmin.builder() - .serviceHttpUrl(pulsar.getHttpServiceUrl()) - .build(); + PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build(); assertThatThrownBy(() -> pulsarAdmin.functions().getFunctions("public", "default")) .isInstanceOf(PulsarAdminException.class); @@ -47,36 +46,23 @@ public void shouldWaitForFunctionsWorkerStarted() throws Exception { try (PulsarContainer pulsar = new PulsarContainer("2.5.1").withFunctionsWorker()) { pulsar.start(); - PulsarAdmin pulsarAdmin = PulsarAdmin.builder() - .serviceHttpUrl(pulsar.getHttpServiceUrl()) - .build(); + PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build(); assertThat(pulsarAdmin.functions().getFunctions("public", "default")).hasSize(0); } } protected void testPulsarFunctionality(String pulsarBrokerUrl) throws Exception { - try ( - PulsarClient client = PulsarClient.builder() - .serviceUrl(pulsarBrokerUrl) - .build(); - Consumer consumer = client.newConsumer() - .topic(TEST_TOPIC) - .subscriptionName("test-subs") - .subscribe(); - Producer producer = client.newProducer() - .topic(TEST_TOPIC) - .create() + PulsarClient client = PulsarClient.builder().serviceUrl(pulsarBrokerUrl).build(); + Consumer consumer = client.newConsumer().topic(TEST_TOPIC).subscriptionName("test-subs").subscribe(); + Producer producer = client.newProducer().topic(TEST_TOPIC).create() ) { - producer.send("test containers".getBytes()); CompletableFuture future = consumer.receiveAsync(); Message message = future.get(5, TimeUnit.SECONDS); - assertThat(new String(message.getData())) - .isEqualTo("test containers"); + assertThat(new String(message.getData())).isEqualTo("test containers"); } } - } diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java index e64d19a9f49..3f4fd7e4b1e 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/CancellableSubscription.java @@ -9,8 +9,7 @@ class CancellableSubscription implements Subscription { private final AtomicBoolean cancelled = new AtomicBoolean(); @Override - public void request(long n) { - } + public void request(long n) {} @Override public void cancel() { diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java index 489d545429d..d1b1c0e43f3 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/ConnectionPublisher.java @@ -56,8 +56,8 @@ synchronized void transitionTo(SubscriptionState newState) { } abstract class SubscriptionState implements Subscription { - void enter() { - } + + void enter() {} } class WaitRequestSubscriptionState extends SubscriptionState { @@ -68,8 +68,7 @@ public void request(long n) { } @Override - public void cancel() { - } + public void cancel() {} } class WaitFutureCompletionSubscriptionState extends SubscriptionState { @@ -93,8 +92,7 @@ void enter() { } @Override - public void request(long n) { - } + public void request(long n) {} @Override public void cancel() { diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java index 7828d121c6f..5cd2ffbd894 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/EmptySubscription.java @@ -6,12 +6,8 @@ enum EmptySubscription implements Subscription { INSTANCE; @Override - public void request(long n) { - - } + public void request(long n) {} @Override - public void cancel() { - - } + public void cancel() {} } diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java index f642a60d67c..1eecb22a2c7 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/Hidden.java @@ -52,7 +52,8 @@ private ConnectionFactoryOptions removeProxying(ConnectionFactoryOptions options // when protocol does NOT contain COLON, the length becomes 1 String protocolDelegate = protocols.length == 2 ? protocols[1] : ""; - return ConnectionFactoryOptions.builder() + return ConnectionFactoryOptions + .builder() .from(options) .option(ConnectionFactoryOptions.DRIVER, driverDelegate) .option(ConnectionFactoryOptions.PROTOCOL, protocolDelegate) @@ -68,6 +69,5 @@ public boolean supports(ConnectionFactoryOptions options) { public String getDriver() { return DRIVER; } - } } diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java index a303cbafff8..8bf0401fe69 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainer.java @@ -4,6 +4,5 @@ import org.testcontainers.lifecycle.Startable; public interface R2DBCDatabaseContainer extends Startable { - ConnectionFactoryOptions configure(ConnectionFactoryOptions options); } diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java index 287407dc15e..9d3efc17ac7 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/R2DBCDatabaseContainerProvider.java @@ -9,7 +9,6 @@ import javax.annotation.Nullable; public interface R2DBCDatabaseContainerProvider { - Option REUSABLE_OPTION = Option.valueOf("TC_REUSABLE"); Option IMAGE_TAG_OPTION = Option.valueOf("TC_IMAGE_TAG"); diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java index 691775a94f8..bada076eec9 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java @@ -36,34 +36,36 @@ class TestcontainersR2DBCConnectionFactory implements ConnectionFactory, Closeab TestcontainersR2DBCConnectionFactory(ConnectionFactoryOptions options) { this.options = options; - containerProvider = StreamSupport.stream(ServiceLoader.load(R2DBCDatabaseContainerProvider.class).spliterator(), false) - .filter(it -> it.supports(options)) - .findAny() - .orElseThrow(() -> new IllegalArgumentException("Missing provider for " + options)); + containerProvider = + StreamSupport + .stream(ServiceLoader.load(R2DBCDatabaseContainerProvider.class).spliterator(), false) + .filter(it -> it.supports(options)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Missing provider for " + options)); } @Override public Publisher create() { - return new ConnectionPublisher( - () -> { - if (future == null) { - synchronized (this) { - if (future == null) { - future = CompletableFuture.supplyAsync(() -> { - R2DBCDatabaseContainer container = containerProvider.createContainer(options); - container.start(); - return container; - }, EXECUTOR); - } + return new ConnectionPublisher(() -> { + if (future == null) { + synchronized (this) { + if (future == null) { + future = + CompletableFuture.supplyAsync( + () -> { + R2DBCDatabaseContainer container = containerProvider.createContainer(options); + container.start(); + return container; + }, + EXECUTOR + ); } } - return future.thenApply(it -> { - return ConnectionFactories.find( - it.configure(options) - ); - }); } - ); + return future.thenApply(it -> { + return ConnectionFactories.find(it.configure(options)); + }); + }); } @Override @@ -99,5 +101,4 @@ public Publisher close() { } }; } - } diff --git a/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java b/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java index 6fad93f0e2a..3772e6d49a6 100644 --- a/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java +++ b/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java @@ -48,16 +48,15 @@ public void reusesUntilConnectionFactoryIsClosed() { assertThat(updated).isEqualTo(1); - Flux select = Flux - .usingWhen( - Flux.defer(connectionFactory::create), - connection -> { - return Flux - .from(connection.createStatement("SELECT COUNT(*) FROM test").execute()) - .flatMap(it -> it.map((row, meta) -> (Long) row.get(0))); - }, - Connection::close - ); + Flux select = Flux.usingWhen( + Flux.defer(connectionFactory::create), + connection -> { + return Flux + .from(connection.createStatement("SELECT COUNT(*) FROM test").execute()) + .flatMap(it -> it.map((row, meta) -> (Long) row.get(0))); + }, + Connection::close + ); Long rows = select.blockFirst(); diff --git a/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java b/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java index c21c7078410..63603379e40 100644 --- a/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java +++ b/modules/r2dbc/src/testFixtures/java/org/testcontainers/r2dbc/AbstractR2DBCDatabaseContainerTest.java @@ -60,9 +60,7 @@ protected void runTestQuery(ConnectionFactory connectionFactory) { .flatMap(it -> it.map((row, meta) -> (Number) row.get(0))) .blockFirst(); - assertThat(result) - .isNotNull() - .returns(expected, Number::intValue); + assertThat(result).isNotNull().returns(expected, Number::intValue); } finally { if (connectionFactory instanceof Closeable) { Mono.from(((Closeable) connectionFactory).close()).block(); diff --git a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java index f5c63a267a9..c13dfdf1a24 100644 --- a/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java +++ b/modules/rabbitmq/src/main/java/org/testcontainers/containers/RabbitMQContainer.java @@ -11,13 +11,11 @@ import java.io.IOException; import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; -import static java.lang.String.join; -import static java.util.Arrays.asList; - /** * Testcontainer for RabbitMQ. * @@ -29,15 +27,21 @@ public class RabbitMQContainer extends GenericContainer { * The image defaults to the official RabbitmQ image: RabbitMQ. */ private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("rabbitmq"); + private static final String DEFAULT_TAG = "3.7.25-management-alpine"; private static final int DEFAULT_AMQP_PORT = 5672; + private static final int DEFAULT_AMQPS_PORT = 5671; + private static final int DEFAULT_HTTPS_PORT = 15671; + private static final int DEFAULT_HTTP_PORT = 15672; private String adminPassword = "guest"; + private String adminUsername = "guest"; + private final List> values = new ArrayList<>(); /** @@ -60,14 +64,12 @@ public RabbitMQContainer(String dockerImageName) { public RabbitMQContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPorts(DEFAULT_AMQP_PORT, DEFAULT_AMQPS_PORT, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); - this.waitStrategy = Wait. - forLogMessage(".*Server startup complete.*", 1) - .withStartupTimeout(Duration.ofSeconds(60)); + this.waitStrategy = + Wait.forLogMessage(".*Server startup complete.*", 1).withStartupTimeout(Duration.ofSeconds(60)); } @Override @@ -79,7 +81,6 @@ protected void configure() { @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { - values.forEach(command -> { try { ExecResult execResult = execInContainer(command.toArray(new String[0])); @@ -159,257 +160,394 @@ public RabbitMQContainer withAdminPassword(final String adminPassword) { } public enum SslVerification { - VERIFY_NONE("verify_none"), VERIFY_PEER("verify_peer"); + VERIFY_NONE("verify_none"), + VERIFY_PEER("verify_peer"); SslVerification(String value) { this.value = value; } - private final String value; + private final String value; } public RabbitMQContainer withSSL( - final MountableFile keyFile, - final MountableFile certFile, - final MountableFile caFile, - final SslVerification verify, - boolean failIfNoCert, - int verificationDepth) { - + final MountableFile keyFile, + final MountableFile certFile, + final MountableFile caFile, + final SslVerification verify, + boolean failIfNoCert, + int verificationDepth + ) { return withSSL(keyFile, certFile, caFile, verify, failIfNoCert) - .withEnv("RABBITMQ_SSL_DEPTH", String.valueOf(verificationDepth)); + .withEnv("RABBITMQ_SSL_DEPTH", String.valueOf(verificationDepth)); } public RabbitMQContainer withSSL( - final MountableFile keyFile, - final MountableFile certFile, - final MountableFile caFile, - final SslVerification verify, - boolean failIfNoCert) { - + final MountableFile keyFile, + final MountableFile certFile, + final MountableFile caFile, + final SslVerification verify, + boolean failIfNoCert + ) { return withSSL(keyFile, certFile, caFile, verify) - .withEnv("RABBITMQ_SSL_FAIL_IF_NO_PEER_CERT", String.valueOf(failIfNoCert)); + .withEnv("RABBITMQ_SSL_FAIL_IF_NO_PEER_CERT", String.valueOf(failIfNoCert)); } public RabbitMQContainer withSSL( - final MountableFile keyFile, - final MountableFile certFile, - final MountableFile caFile, - final SslVerification verify) { - + final MountableFile keyFile, + final MountableFile certFile, + final MountableFile caFile, + final SslVerification verify + ) { return withEnv("RABBITMQ_SSL_CACERTFILE", "/etc/rabbitmq/ca_cert.pem") - .withEnv("RABBITMQ_SSL_CERTFILE", "/etc/rabbitmq/rabbitmq_cert.pem") - .withEnv("RABBITMQ_SSL_KEYFILE", "/etc/rabbitmq/rabbitmq_key.pem") - .withEnv("RABBITMQ_SSL_VERIFY", verify.value) - .withCopyFileToContainer(certFile, "/etc/rabbitmq/rabbitmq_cert.pem") - .withCopyFileToContainer(caFile, "/etc/rabbitmq/ca_cert.pem") - .withCopyFileToContainer(keyFile, "/etc/rabbitmq/rabbitmq_key.pem"); + .withEnv("RABBITMQ_SSL_CERTFILE", "/etc/rabbitmq/rabbitmq_cert.pem") + .withEnv("RABBITMQ_SSL_KEYFILE", "/etc/rabbitmq/rabbitmq_key.pem") + .withEnv("RABBITMQ_SSL_VERIFY", verify.value) + .withCopyFileToContainer(certFile, "/etc/rabbitmq/rabbitmq_cert.pem") + .withCopyFileToContainer(caFile, "/etc/rabbitmq/ca_cert.pem") + .withCopyFileToContainer(keyFile, "/etc/rabbitmq/rabbitmq_key.pem"); } public RabbitMQContainer withPluginsEnabled(String... pluginNames) { - List command = new ArrayList<>(asList("rabbitmq-plugins", "enable")); - command.addAll(asList(pluginNames)); + List command = new ArrayList<>(Arrays.asList("rabbitmq-plugins", "enable")); + command.addAll(Arrays.asList(pluginNames)); values.add(command); return self(); } public RabbitMQContainer withBinding(String source, String destination) { - values.add(asList("rabbitmqadmin", "declare", "binding", - "source=" + source, - "destination=" + destination)); + values.add( + Arrays.asList("rabbitmqadmin", "declare", "binding", "source=" + source, "destination=" + destination) + ); return self(); } public RabbitMQContainer withBinding(String vhost, String source, String destination) { - values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "binding", - "source=" + source, - "destination=" + destination)); + values.add( + Arrays.asList( + "rabbitmqadmin", + "--vhost=" + vhost, + "declare", + "binding", + "source=" + source, + "destination=" + destination + ) + ); return self(); } - public RabbitMQContainer withBinding(String source, String destination, Map arguments, String routingKey, String destinationType) { - values.add(asList("rabbitmqadmin", "declare", "binding", - "source=" + source, - "destination=" + destination, - "routing_key=" + routingKey, - "destination_type=" + destinationType, - "arguments=" + toJson(arguments))); + public RabbitMQContainer withBinding( + String source, + String destination, + Map arguments, + String routingKey, + String destinationType + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "binding", + "source=" + source, + "destination=" + destination, + "routing_key=" + routingKey, + "destination_type=" + destinationType, + "arguments=" + toJson(arguments) + ) + ); return self(); } - public RabbitMQContainer withBinding(String vhost, String source, String destination, Map arguments, String routingKey, String destinationType) { - values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "binding", + public RabbitMQContainer withBinding( + String vhost, + String source, + String destination, + Map arguments, + String routingKey, + String destinationType + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "--vhost=" + vhost, + "declare", + "binding", "source=" + source, "destination=" + destination, "routing_key=" + routingKey, "destination_type=" + destinationType, - "arguments=" + toJson(arguments))); + "arguments=" + toJson(arguments) + ) + ); return self(); } public RabbitMQContainer withParameter(String component, String name, String value) { - values.add(asList("rabbitmqadmin", "declare", "parameter", + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "parameter", "component=" + component, "name=" + name, - "value=" + value)); + "value=" + value + ) + ); return self(); } public RabbitMQContainer withPermission(String vhost, String user, String configure, String write, String read) { - values.add(asList("rabbitmqadmin", "declare", "permission", + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "permission", "vhost=" + vhost, "user=" + user, "configure=" + configure, "write=" + write, - "read=" + read)); + "read=" + read + ) + ); return self(); } public RabbitMQContainer withUser(String name, String password) { - values.add(asList("rabbitmqadmin", "declare", "user", - "name=" + name, - "password=" + password, - "tags=")); + values.add(Arrays.asList("rabbitmqadmin", "declare", "user", "name=" + name, "password=" + password, "tags=")); return self(); } public RabbitMQContainer withUser(String name, String password, Set tags) { - values.add(asList("rabbitmqadmin", "declare", "user", + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "user", "name=" + name, "password=" + password, - "tags=" + join(",", tags))); + "tags=" + String.join(",", tags) + ) + ); return self(); } public RabbitMQContainer withPolicy(String name, String pattern, Map definition) { - values.add(asList("rabbitmqadmin", "declare", "policy", + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "policy", "name=" + name, "pattern=" + pattern, - "definition=" + toJson(definition))); + "definition=" + toJson(definition) + ) + ); return self(); } public RabbitMQContainer withPolicy(String vhost, String name, String pattern, Map definition) { - values.add(asList("rabbitmqadmin", "declare", "policy", + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "policy", "--vhost=" + vhost, "name=" + name, "pattern=" + pattern, - "definition=" + toJson(definition))); + "definition=" + toJson(definition) + ) + ); return self(); } - public RabbitMQContainer withPolicy(String name, String pattern, Map definition, int priority, String applyTo) { - values.add(asList("rabbitmqadmin", "declare", "policy", + public RabbitMQContainer withPolicy( + String name, + String pattern, + Map definition, + int priority, + String applyTo + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "policy", "name=" + name, "pattern=" + pattern, "priority=" + priority, "apply-to=" + applyTo, - "definition=" + toJson(definition))); + "definition=" + toJson(definition) + ) + ); return self(); } public RabbitMQContainer withOperatorPolicy(String name, String pattern, Map definition) { - values.add(new ArrayList<>(asList("rabbitmqadmin", "declare", "operator_policy", - "name=" + name, - "pattern=" + pattern, - "definition=" + toJson(definition)))); + values.add( + new ArrayList<>( + Arrays.asList( + "rabbitmqadmin", + "declare", + "operator_policy", + "name=" + name, + "pattern=" + pattern, + "definition=" + toJson(definition) + ) + ) + ); return self(); } - public RabbitMQContainer withOperatorPolicy(String name, String pattern, Map definition, int priority, String applyTo) { - values.add(asList("rabbitmqadmin", "declare", "operator_policy", + public RabbitMQContainer withOperatorPolicy( + String name, + String pattern, + Map definition, + int priority, + String applyTo + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "operator_policy", "name=" + name, "pattern=" + pattern, "priority=" + priority, "apply-to=" + applyTo, - "definition=" + toJson(definition))); + "definition=" + toJson(definition) + ) + ); return self(); } public RabbitMQContainer withVhost(String name) { - values.add(asList("rabbitmqadmin", "declare", "vhost", - "name=" + name)); + values.add(Arrays.asList("rabbitmqadmin", "declare", "vhost", "name=" + name)); return self(); } public RabbitMQContainer withVhost(String name, boolean tracing) { - values.add(asList("rabbitmqadmin", "declare", "vhost", - "name=" + name, - "tracing=" + tracing)); + values.add(Arrays.asList("rabbitmqadmin", "declare", "vhost", "name=" + name, "tracing=" + tracing)); return self(); } public RabbitMQContainer withVhostLimit(String vhost, String name, int value) { - values.add(asList("rabbitmqadmin", "declare", "vhost_limit", - "vhost=" + vhost, - "name=" + name, - "value=" + value)); + values.add( + Arrays.asList("rabbitmqadmin", "declare", "vhost_limit", "vhost=" + vhost, "name=" + name, "value=" + value) + ); return self(); } public RabbitMQContainer withQueue(String name) { - values.add(asList("rabbitmqadmin", "declare", "queue", - "name=" + name)); + values.add(Arrays.asList("rabbitmqadmin", "declare", "queue", "name=" + name)); return self(); } public RabbitMQContainer withQueue(String vhost, String name) { - values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "queue", - "name=" + name)); + values.add(Arrays.asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "queue", "name=" + name)); return self(); } - public RabbitMQContainer withQueue(String name, boolean autoDelete, boolean durable, Map arguments) { - values.add(asList("rabbitmqadmin", "declare", "queue", + public RabbitMQContainer withQueue( + String name, + boolean autoDelete, + boolean durable, + Map arguments + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "queue", "name=" + name, "auto_delete=" + autoDelete, "durable=" + durable, - "arguments=" + toJson(arguments))); + "arguments=" + toJson(arguments) + ) + ); return self(); } - public RabbitMQContainer withQueue(String vhost, String name, boolean autoDelete, boolean durable, Map arguments) { - values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "queue", - "name=" + name, - "auto_delete=" + autoDelete, - "durable=" + durable, - "arguments=" + toJson(arguments))); + public RabbitMQContainer withQueue( + String vhost, + String name, + boolean autoDelete, + boolean durable, + Map arguments + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "--vhost=" + vhost, + "declare", + "queue", + "name=" + name, + "auto_delete=" + autoDelete, + "durable=" + durable, + "arguments=" + toJson(arguments) + ) + ); return self(); } public RabbitMQContainer withExchange(String name, String type) { - values.add(asList("rabbitmqadmin", "declare", "exchange", - "name=" + name, - "type=" + type)); + values.add(Arrays.asList("rabbitmqadmin", "declare", "exchange", "name=" + name, "type=" + type)); return self(); } public RabbitMQContainer withExchange(String vhost, String name, String type) { - values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "exchange", - "name=" + name, - "type=" + type)); + values.add( + Arrays.asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "exchange", "name=" + name, "type=" + type) + ); return self(); } - public RabbitMQContainer withExchange(String name, String type, boolean autoDelete, boolean internal, boolean durable, Map arguments) { - values.add(asList("rabbitmqadmin", "declare", "exchange", - "name=" + name, - "type=" + type, - "auto_delete=" + autoDelete, - "internal=" + internal, - "durable=" + durable, - "arguments=" + toJson(arguments))); + public RabbitMQContainer withExchange( + String name, + String type, + boolean autoDelete, + boolean internal, + boolean durable, + Map arguments + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "declare", + "exchange", + "name=" + name, + "type=" + type, + "auto_delete=" + autoDelete, + "internal=" + internal, + "durable=" + durable, + "arguments=" + toJson(arguments) + ) + ); return self(); } - public RabbitMQContainer withExchange(String vhost, String name, String type, boolean autoDelete, boolean internal, boolean durable, Map arguments) { - values.add(asList("rabbitmqadmin", "--vhost=" + vhost, "declare", "exchange", + public RabbitMQContainer withExchange( + String vhost, + String name, + String type, + boolean autoDelete, + boolean internal, + boolean durable, + Map arguments + ) { + values.add( + Arrays.asList( + "rabbitmqadmin", + "--vhost=" + vhost, + "declare", + "exchange", "name=" + name, "type=" + type, "auto_delete=" + autoDelete, "internal=" + internal, "durable=" + durable, - "arguments=" + toJson(arguments))); + "arguments=" + toJson(arguments) + ) + ); return self(); } @@ -420,7 +558,6 @@ public RabbitMQContainer withExchange(String vhost, String name, String type, bo * @return This container. */ public RabbitMQContainer withRabbitMQConfig(MountableFile rabbitMQConf) { - return withRabbitMQConfigSysctl(rabbitMQConf); } diff --git a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java index d82051a94db..6bc935b4e6c 100644 --- a/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java +++ b/modules/rabbitmq/src/test/java/org/testcontainers/containers/RabbitMQContainerTest.java @@ -6,11 +6,9 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import org.junit.Test; +import org.testcontainers.containers.RabbitMQContainer.SslVerification; import org.testcontainers.utility.MountableFile; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -22,10 +20,12 @@ import java.security.cert.CertificateException; import java.util.Collections; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; -import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER; -import static org.testcontainers.utility.MountableFile.forClasspathResource; /** * @author Martin Greber @@ -33,46 +33,55 @@ public class RabbitMQContainerTest { public static final int DEFAULT_AMQPS_PORT = 5671; + public static final int DEFAULT_AMQP_PORT = 5672; + public static final int DEFAULT_HTTPS_PORT = 15671; + public static final int DEFAULT_HTTP_PORT = 15672; @Test - public void shouldCreateRabbitMQContainer() - { + public void shouldCreateRabbitMQContainer() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { - assertThat(container.getAdminPassword()).isEqualTo("guest"); assertThat(container.getAdminUsername()).isEqualTo("guest"); container.start(); - assertThat(container.getAmqpsUrl()).isEqualTo( - String.format("amqps://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_AMQPS_PORT))); - assertThat(container.getAmqpUrl()).isEqualTo( - String.format("amqp://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_AMQP_PORT))); - assertThat(container.getHttpsUrl()).isEqualTo( - String.format("https://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_HTTPS_PORT))); - assertThat(container.getHttpUrl()).isEqualTo( - String.format("http://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_HTTP_PORT))); + assertThat(container.getAmqpsUrl()) + .isEqualTo( + String.format("amqps://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_AMQPS_PORT)) + ); + assertThat(container.getAmqpUrl()) + .isEqualTo( + String.format("amqp://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_AMQP_PORT)) + ); + assertThat(container.getHttpsUrl()) + .isEqualTo( + String.format("https://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_HTTPS_PORT)) + ); + assertThat(container.getHttpUrl()) + .isEqualTo( + String.format("http://%s:%d", container.getHost(), container.getMappedPort(DEFAULT_HTTP_PORT)) + ); assertThat(container.getHttpsPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTPS_PORT)); assertThat(container.getHttpPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTP_PORT)); assertThat(container.getAmqpsPort()).isEqualTo(container.getMappedPort(DEFAULT_AMQPS_PORT)); assertThat(container.getAmqpPort()).isEqualTo(container.getMappedPort(DEFAULT_AMQP_PORT)); - assertThat(container.getLivenessCheckPortNumbers()).containsExactlyInAnyOrder( - container.getMappedPort(DEFAULT_AMQP_PORT), - container.getMappedPort(DEFAULT_AMQPS_PORT), - container.getMappedPort(DEFAULT_HTTP_PORT), - container.getMappedPort(DEFAULT_HTTPS_PORT) - ); + assertThat(container.getLivenessCheckPortNumbers()) + .containsExactlyInAnyOrder( + container.getMappedPort(DEFAULT_AMQP_PORT), + container.getMappedPort(DEFAULT_AMQPS_PORT), + container.getMappedPort(DEFAULT_HTTP_PORT), + container.getMappedPort(DEFAULT_HTTPS_PORT) + ); } } @Test - public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException - { + public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withExchange("test-exchange", "direct"); @@ -84,11 +93,18 @@ public void shouldCreateRabbitMQContainerWithExchange() throws IOException, Inte } @Test - public void shouldCreateRabbitMQContainerWithExchangeInVhost() throws IOException, InterruptedException - { + public void shouldCreateRabbitMQContainerWithExchangeInVhost() throws IOException, InterruptedException { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withVhost("test-vhost"); - container.withExchange("test-vhost", "test-exchange", "direct", false, false, false, Collections.emptyMap()); + container.withExchange( + "test-vhost", + "test-exchange", + "direct", + false, + false, + false, + Collections.emptyMap() + ); container.start(); @@ -98,11 +114,10 @@ public void shouldCreateRabbitMQContainerWithExchangeInVhost() throws IOExceptio } @Test - public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException - { + public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { - - container.withQueue("queue-one") + container + .withQueue("queue-one") .withQueue("queue-two", false, true, ImmutableMap.of("x-message-ttl", 1000)); container.start(); @@ -124,7 +139,6 @@ public void shouldMountConfigurationFile() { } } - @Test public void shouldMountConfigurationFileErlang() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { @@ -135,7 +149,6 @@ public void shouldMountConfigurationFileErlang() { } } - @Test public void shouldMountConfigurationFileSysctl() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { @@ -147,132 +160,143 @@ public void shouldMountConfigurationFileSysctl() { } @Test - public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException - { + public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container - .withVhost("vhost1") - .withVhostLimit("vhost1", "max-connections", 1) - .withVhost("vhost2", true) - .withExchange("direct-exchange", "direct") - .withExchange("topic-exchange", "topic") - .withExchange("vhost1", "topic-exchange-2", "topic", false, false, true, Collections.emptyMap()) - .withExchange("vhost2", "topic-exchange-3", "topic") - .withExchange("topic-exchange-4", "topic", false, false, true, Collections.emptyMap()) - .withQueue("queue1") - .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) - .withQueue("vhost1", "queue3", true, false, ImmutableMap.of("x-message-ttl", 1000)) - .withQueue("vhost2", "queue4") - .withBinding("direct-exchange", "queue1") - .withBinding("vhost1", "topic-exchange-2", "queue3") - .withBinding("vhost2", "topic-exchange-3", "queue4", Collections.emptyMap(), "ss7", "queue") - .withUser("user1", "password1") - .withUser("user2", "password2", ImmutableSet.of("administrator")) - .withPermission("vhost1", "user1", ".*", ".*", ".*") - .withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues") - .withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct")) - .withPolicy("vhost2", "ha-all", ".*", ImmutableMap.of("ha-mode", "all", "ha-sync-mode", "automatic")) - .withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues") - .withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange"); + .withVhost("vhost1") + .withVhostLimit("vhost1", "max-connections", 1) + .withVhost("vhost2", true) + .withExchange("direct-exchange", "direct") + .withExchange("topic-exchange", "topic") + .withExchange("vhost1", "topic-exchange-2", "topic", false, false, true, Collections.emptyMap()) + .withExchange("vhost2", "topic-exchange-3", "topic") + .withExchange("topic-exchange-4", "topic", false, false, true, Collections.emptyMap()) + .withQueue("queue1") + .withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000)) + .withQueue("vhost1", "queue3", true, false, ImmutableMap.of("x-message-ttl", 1000)) + .withQueue("vhost2", "queue4") + .withBinding("direct-exchange", "queue1") + .withBinding("vhost1", "topic-exchange-2", "queue3") + .withBinding("vhost2", "topic-exchange-3", "queue4", Collections.emptyMap(), "ss7", "queue") + .withUser("user1", "password1") + .withUser("user2", "password2", ImmutableSet.of("administrator")) + .withPermission("vhost1", "user1", ".*", ".*", ".*") + .withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues") + .withPolicy( + "alternate exchange policy", + "^direct-exchange", + ImmutableMap.of("alternate-exchange", "amq.direct") + ) + .withPolicy("vhost2", "ha-all", ".*", ImmutableMap.of("ha-mode", "all", "ha-sync-mode", "automatic")) + .withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues") + .withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange"); container.start(); - assertThat(container.execInContainer("rabbitmqadmin", "list", "queues") - .getStdout()) + assertThat(container.execInContainer("rabbitmqadmin", "list", "queues").getStdout()) .contains("queue1", "queue2", "queue3", "queue4"); - assertThat(container.execInContainer("rabbitmqadmin", "list", "exchanges") - .getStdout()) - .contains("direct-exchange", "topic-exchange", "topic-exchange-2", "topic-exchange-3", "topic-exchange-4"); + assertThat(container.execInContainer("rabbitmqadmin", "list", "exchanges").getStdout()) + .contains( + "direct-exchange", + "topic-exchange", + "topic-exchange-2", + "topic-exchange-3", + "topic-exchange-4" + ); - assertThat(container.execInContainer("rabbitmqadmin", "list", "bindings") - .getStdout()) + assertThat(container.execInContainer("rabbitmqadmin", "list", "bindings").getStdout()) .contains("direct-exchange", "topic-exchange-2", "topic-exchange-3"); - assertThat(container.execInContainer("rabbitmqadmin", "list", "users") - .getStdout()) + assertThat(container.execInContainer("rabbitmqadmin", "list", "users").getStdout()) .contains("user1", "user2"); - assertThat(container.execInContainer("rabbitmqadmin", "list", "policies") - .getStdout()) + assertThat(container.execInContainer("rabbitmqadmin", "list", "policies").getStdout()) .contains("max length policy", "alternate exchange policy"); - assertThat(container.execInContainer("rabbitmqadmin", "list", "policies", "--vhost=vhost2") - .getStdout()) - .contains("ha-all", "ha-sync-mode"); + assertThat(container.execInContainer("rabbitmqadmin", "list", "policies", "--vhost=vhost2").getStdout()) + .contains("ha-all", "ha-sync-mode"); - assertThat(container.execInContainer("rabbitmqadmin", "list", "operator_policies") - .getStdout()) + assertThat(container.execInContainer("rabbitmqadmin", "list", "operator_policies").getStdout()) .contains("operator policy 1"); - assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_shovel", "--quiet") - .getStdout()) + assertThat( + container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_shovel", "--quiet").getStdout() + ) .contains("rabbitmq_shovel is enabled"); - assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_random_exchange", "--quiet") - .getStdout()) + assertThat( + container + .execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_random_exchange", "--quiet") + .getStdout() + ) .contains("rabbitmq_random_exchange is enabled"); } } @Test - public void shouldThrowExceptionForDodgyJson() - { + public void shouldThrowExceptionForDodgyJson() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { - - assertThatCode(() -> - container.withQueue( - "queue2", - true, - false, - ImmutableMap.of("x-message-ttl", container)) - ).hasMessageStartingWith("Failed to convert arguments into json"); - + assertThatCode(() -> container.withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", container)) + ) + .hasMessageStartingWith("Failed to convert arguments into json"); } } @Test - public void shouldWorkWithSSL() - { + public void shouldWorkWithSSL() { try (RabbitMQContainer container = new RabbitMQContainer(RabbitMQTestImages.RABBITMQ_IMAGE)) { container.withSSL( - forClasspathResource("/certs/server_key.pem", 0644), - forClasspathResource("/certs/server_certificate.pem", 0644), - forClasspathResource("/certs/ca_certificate.pem", 0644), - VERIFY_PEER, + MountableFile.forClasspathResource("/certs/server_key.pem", 0644), + MountableFile.forClasspathResource("/certs/server_certificate.pem", 0644), + MountableFile.forClasspathResource("/certs/ca_certificate.pem", 0644), + SslVerification.VERIFY_PEER, true ); container.start(); assertThatCode(() -> { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useSslProtocol(createSslContext( - "certs/client_key.p12", "password", - "certs/truststore.jks", "password")); - connectionFactory.enableHostnameVerification(); - connectionFactory.setUri(container.getAmqpsUrl()); - connectionFactory.setPassword(container.getAdminPassword()); - Connection connection = connectionFactory.newConnection(); - Channel channel = connection.openChannel().orElseThrow(() -> new RuntimeException("Failed to Open channel")); - channel.close(); - connection.close(); - }).doesNotThrowAnyException(); + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.useSslProtocol( + createSslContext("certs/client_key.p12", "password", "certs/truststore.jks", "password") + ); + connectionFactory.enableHostnameVerification(); + connectionFactory.setUri(container.getAmqpsUrl()); + connectionFactory.setPassword(container.getAdminPassword()); + Connection connection = connectionFactory.newConnection(); + Channel channel = connection + .openChannel() + .orElseThrow(() -> new RuntimeException("Failed to Open channel")); + channel.close(); + connection.close(); + }) + .doesNotThrowAnyException(); } } - private SSLContext createSslContext(String keystoreFile, String keystorePassword, String truststoreFile, String truststorePassword) - throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException - { + private SSLContext createSslContext( + String keystoreFile, + String keystorePassword, + String truststoreFile, + String truststorePassword + ) + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { ClassLoader classLoader = getClass().getClassLoader(); KeyStore ks = KeyStore.getInstance("PKCS12"); - ks.load(new FileInputStream(new File(classLoader.getResource(keystoreFile).getFile())), keystorePassword.toCharArray()); + ks.load( + new FileInputStream(new File(classLoader.getResource(keystoreFile).getFile())), + keystorePassword.toCharArray() + ); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, "password".toCharArray()); KeyStore trustStore = KeyStore.getInstance("PKCS12"); - trustStore.load(new FileInputStream(new File(classLoader.getResource(truststoreFile).getFile())), truststorePassword.toCharArray()); + trustStore.load( + new FileInputStream(new File(classLoader.getResource(truststoreFile).getFile())), + truststorePassword.toCharArray() + ); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(trustStore); diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index fc3778385cd..08d7ab053c6 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -1,22 +1,10 @@ package org.testcontainers.containers; -import static java.time.temporal.ChronoUnit.SECONDS; - import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.AccessMode; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Volume; import com.google.common.collect.ImmutableSet; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.file.Files; -import java.time.Duration; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; - import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; @@ -41,40 +29,67 @@ import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.TimeUnit; + /** * A chrome/firefox/custom container based on SeleniumHQ's standalone container sets. *

* The container should expose Selenium remote control protocol and VNC. */ -public class BrowserWebDriverContainer> extends GenericContainer implements LinkableContainer, TestLifecycleAware { +public class BrowserWebDriverContainer> + extends GenericContainer + implements LinkableContainer, TestLifecycleAware { private static final DockerImageName CHROME_IMAGE = DockerImageName.parse("selenium/standalone-chrome"); + private static final DockerImageName FIREFOX_IMAGE = DockerImageName.parse("selenium/standalone-firefox"); + private static final DockerImageName CHROME_DEBUG_IMAGE = DockerImageName.parse("selenium/standalone-chrome-debug"); - private static final DockerImageName FIREFOX_DEBUG_IMAGE = DockerImageName.parse("selenium/standalone-firefox-debug"); + + private static final DockerImageName FIREFOX_DEBUG_IMAGE = DockerImageName.parse( + "selenium/standalone-firefox-debug" + ); + private static final DockerImageName[] COMPATIBLE_IMAGES = new DockerImageName[] { CHROME_IMAGE, FIREFOX_IMAGE, CHROME_DEBUG_IMAGE, - FIREFOX_DEBUG_IMAGE + FIREFOX_DEBUG_IMAGE, }; private static final String DEFAULT_PASSWORD = "secret"; + private static final int SELENIUM_PORT = 4444; + private static final int VNC_PORT = 5900; private static final String NO_PROXY_KEY = "no_proxy"; + private static final String TC_TEMP_DIR_PREFIX = "tc"; @Nullable private Capabilities capabilities; + private DockerImageName customImageName = null; @Nullable private RemoteWebDriver driver; + private VncRecordingMode recordingMode = VncRecordingMode.RECORD_FAILING; + private VncRecordingFormat recordingFormat; + private RecordingFileFactory recordingFileFactory; + private File vncRecordingDirectory; private VncRecordingContainer vncRecordingContainer = null; @@ -84,13 +99,16 @@ public class BrowserWebDriverContainer getLivenessCheckPorts() { @Override protected void configure() { - String seleniumVersion = SeleniumUtils.determineClasspathSeleniumVersion(); if (recordingMode != VncRecordingMode.SKIP) { - if (vncRecordingDirectory == null) { try { vncRecordingDirectory = Files.createTempDirectory(TC_TEMP_DIR_PREFIX).toFile(); @@ -178,7 +196,8 @@ protected void configure() { withNetwork(Network.SHARED); } - vncRecordingContainer = new VncRecordingContainer(this) + vncRecordingContainer = + new VncRecordingContainer(this) .withVncPassword(DEFAULT_PASSWORD) .withVncPort(VNC_PORT) .withVideoFormat(recordingFormat); @@ -188,7 +207,10 @@ protected void configure() { customImageName.assertCompatibleWith(COMPATIBLE_IMAGES); super.setDockerImageName(customImageName.asCanonicalNameString()); } else { - DockerImageName standardImageForCapabilities = getStandardImageForCapabilities(capabilities, seleniumVersion); + DockerImageName standardImageForCapabilities = getStandardImageForCapabilities( + capabilities, + seleniumVersion + ); super.setDockerImageName(standardImageForCapabilities.asCanonicalNameString()); } @@ -246,7 +268,9 @@ private static DockerImageName getStandardImageForCapabilities(Capabilities capa case BrowserType.FIREFOX: return (supportsVncWithoutDebugImage ? FIREFOX_IMAGE : FIREFOX_DEBUG_IMAGE).withTag(seleniumVersion); default: - throw new UnsupportedOperationException("Browser name must be 'chrome' or 'firefox'; provided '" + browserName + "' is not supported"); + throw new UnsupportedOperationException( + "Browser name must be 'chrome' or 'firefox'; provided '" + browserName + "' is not supported" + ); } } @@ -254,7 +278,7 @@ public URL getSeleniumAddress() { try { return new URL("http", getHost(), getMappedPort(SELENIUM_PORT), "/wd/hub"); } catch (MalformedURLException e) { - e.printStackTrace();// TODO + e.printStackTrace(); // TODO return null; } } @@ -292,15 +316,27 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { public synchronized RemoteWebDriver getWebDriver() { if (driver == null) { if (capabilities == null) { - logger().warn("No capabilities provided - this will cause an exception in future versions. Falling back to ChromeOptions"); + logger() + .warn( + "No capabilities provided - this will cause an exception in future versions. Falling back to ChromeOptions" + ); capabilities = new ChromeOptions(); } - driver = Unreliables.retryUntilSuccess(30, TimeUnit.SECONDS, () -> { - return Timeouts.getWithTimeout(10, TimeUnit.SECONDS, () -> { - return new RemoteWebDriver(getSeleniumAddress(), capabilities); - }); - }); + driver = + Unreliables.retryUntilSuccess( + 30, + TimeUnit.SECONDS, + () -> { + return Timeouts.getWithTimeout( + 10, + TimeUnit.SECONDS, + () -> { + return new RemoteWebDriver(getSeleniumAddress(), capabilities); + } + ); + } + ); } return driver; } @@ -348,7 +384,12 @@ private void retainRecordingIfNeeded(String prefix, boolean succeeded) { } if (shouldRecord) { - File recordingFile = recordingFileFactory.recordingFileForTest(vncRecordingDirectory, prefix, succeeded, vncRecordingContainer.getVideoFormat()); + File recordingFile = recordingFileFactory.recordingFileForTest( + vncRecordingDirectory, + prefix, + succeeded, + vncRecordingContainer.getVideoFormat() + ); LOGGER.info("Screen recordings for test {} will be stored at: {}", prefix, recordingFile); vncRecordingContainer.saveRecordingToFile(recordingFile); @@ -375,7 +416,11 @@ public SELF withRecordingMode(VncRecordingMode recordingMode, File vncRecordingD return withRecordingMode(recordingMode, vncRecordingDirectory, null); } - public SELF withRecordingMode(VncRecordingMode recordingMode, File vncRecordingDirectory, VncRecordingFormat recordingFormat) { + public SELF withRecordingMode( + VncRecordingMode recordingMode, + File vncRecordingDirectory, + VncRecordingFormat recordingFormat + ) { this.recordingMode = recordingMode; this.vncRecordingDirectory = vncRecordingDirectory; this.recordingFormat = recordingFormat; @@ -388,6 +433,8 @@ public SELF withRecordingFileFactory(RecordingFileFactory recordingFileFactory) } public enum VncRecordingMode { - SKIP, RECORD_ALL, RECORD_FAILING + SKIP, + RECORD_ALL, + RECORD_FAILING, } } diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java b/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java index 62a1abd38db..3815f5de3e1 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java @@ -4,25 +4,36 @@ import java.text.SimpleDateFormat; import java.util.Date; -import static org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat; - public class DefaultRecordingFileFactory implements RecordingFileFactory { private static final SimpleDateFormat filenameDateFormat = new SimpleDateFormat("YYYYMMdd-HHmmss"); + private static final String PASSED = "PASSED"; + private static final String FAILED = "FAILED"; - private static final String FILENAME_FORMAT = "%s-%s-%s.%s"; + private static final String FILENAME_FORMAT = "%s-%s-%s.%s"; @Override public File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded) { - return recordingFileForTest(vncRecordingDirectory, prefix, succeeded, VncRecordingContainer.DEFAULT_RECORDING_FORMAT); + return recordingFileForTest( + vncRecordingDirectory, + prefix, + succeeded, + VncRecordingContainer.DEFAULT_RECORDING_FORMAT + ); } @Override - public File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded, VncRecordingFormat recordingFormat) { + public File recordingFileForTest( + File vncRecordingDirectory, + String prefix, + boolean succeeded, + VncRecordingContainer.VncRecordingFormat recordingFormat + ) { final String resultMarker = succeeded ? PASSED : FAILED; - final String fileName = String.format(FILENAME_FORMAT, + final String fileName = String.format( + FILENAME_FORMAT, resultMarker, prefix, filenameDateFormat.format(new Date()), diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java b/modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java index aff607cf23d..31946dac59e 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java @@ -6,16 +6,23 @@ import java.io.File; public interface RecordingFileFactory { - @Deprecated default File recordingFileForTest(File vncRecordingDirectory, Description description, boolean succeeded) { - return recordingFileForTest(vncRecordingDirectory, description.getTestClass().getSimpleName() + "-" + description.getMethodName(), succeeded); + return recordingFileForTest( + vncRecordingDirectory, + description.getTestClass().getSimpleName() + "-" + description.getMethodName(), + succeeded + ); } - default File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded, VncRecordingFormat recordingFormat) { + default File recordingFileForTest( + File vncRecordingDirectory, + String prefix, + boolean succeeded, + VncRecordingFormat recordingFormat + ) { return recordingFileForTest(vncRecordingDirectory, prefix, succeeded); } File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded); - } diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/SeleniumUtils.java b/modules/selenium/src/main/java/org/testcontainers/containers/SeleniumUtils.java index 131f5a953ea..4fc0765cc86 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/SeleniumUtils.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/SeleniumUtils.java @@ -45,19 +45,24 @@ public static String determineClasspathSeleniumVersion() { } } } - } catch (Exception e) { LOGGER.debug("Failed to determine Selenium-Version from selenium-api JAR Manifest", e); } if (seleniumVersions.size() == 0) { - LOGGER.warn("Failed to determine Selenium version from classpath - will use default version of {}", DEFAULT_SELENIUM_VERSION); + LOGGER.warn( + "Failed to determine Selenium version from classpath - will use default version of {}", + DEFAULT_SELENIUM_VERSION + ); return DEFAULT_SELENIUM_VERSION; } String foundVersion = seleniumVersions.iterator().next(); if (seleniumVersions.size() > 1) { - LOGGER.warn("Multiple versions of Selenium API found on classpath - will select {}, but this may not be reliable", foundVersion); + LOGGER.warn( + "Multiple versions of Selenium API found on classpath - will select {}, but this may not be reliable", + foundVersion + ); } return foundVersion; @@ -76,7 +81,7 @@ public static String getSeleniumVersionFromManifest(Manifest manifest) { } // Compatibility Selenium > 3.X - if(seleniumVersion == null) { + if (seleniumVersion == null) { Attributes seleniumInfo = manifest.getAttributes("Selenium"); if (seleniumInfo != null) { seleniumVersion = seleniumInfo.getValue("Selenium-Version"); diff --git a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java index 9abea56c5f2..0d8daaad219 100644 --- a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java @@ -8,19 +8,15 @@ import java.io.File; import java.nio.file.Files; +import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; -import static java.lang.Boolean.FALSE; -import static java.lang.Boolean.TRUE; -import static java.lang.String.format; -import static java.time.LocalDateTime.now; -import static org.hamcrest.core.IsCollectionContaining.hasItem; +import static org.hamcrest.Matchers.hasItem; import static org.junit.Assert.assertThat; -import static org.junit.runner.Description.createTestDescription; @RunWith(Parameterized.class) @Value @@ -29,30 +25,47 @@ public class DefaultRecordingFileFactoryTest { private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("YYYYMMdd-HHmmss"); private final DefaultRecordingFileFactory factory = new DefaultRecordingFileFactory(); + private final String methodName; + private final String prefix; + private final boolean success; @Parameterized.Parameters public static Collection data() { Collection args = new ArrayList<>(); - args.add(new Object[]{"testMethod1", "FAILED", FALSE}); - args.add(new Object[]{"testMethod2", "PASSED", TRUE}); + args.add(new Object[] { "testMethod1", "FAILED", Boolean.FALSE }); + args.add(new Object[] { "testMethod2", "PASSED", Boolean.TRUE }); return args; } @Test public void recordingFileThatShouldDescribeTheTestResultAtThePresentTime() throws Exception { File vncRecordingDirectory = Files.createTempDirectory("recording").toFile(); - Description description = createTestDescription(getClass().getCanonicalName(), methodName, Test.class); + Description description = Description.createTestDescription( + getClass().getCanonicalName(), + methodName, + Test.class + ); File recordingFile = factory.recordingFileForTest(vncRecordingDirectory, description, success); - String expectedFilePrefix = format("%s-%s-%s", prefix, getClass().getSimpleName(), methodName); + String expectedFilePrefix = String.format("%s-%s-%s", prefix, getClass().getSimpleName(), methodName); List expectedPossibleFileNames = Arrays.asList( - new File(vncRecordingDirectory, format("%s-%s.flv", expectedFilePrefix, now().format(DATETIME_FORMATTER))), - new File(vncRecordingDirectory, format("%s-%s.flv", expectedFilePrefix, now().minusSeconds(1L).format(DATETIME_FORMATTER))) + new File( + vncRecordingDirectory, + String.format("%s-%s.flv", expectedFilePrefix, LocalDateTime.now().format(DATETIME_FORMATTER)) + ), + new File( + vncRecordingDirectory, + String.format( + "%s-%s.flv", + expectedFilePrefix, + LocalDateTime.now().minusSeconds(1L).format(DATETIME_FORMATTER) + ) + ) ); assertThat(expectedPossibleFileNames, hasItem(recordingFile)); diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java index db369824442..d0865a06b09 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java @@ -1,10 +1,5 @@ package org.testcontainers.junit; -import static java.lang.String.format; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; - -import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; import org.junit.ClassRule; import org.openqa.selenium.By; @@ -16,6 +11,11 @@ import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.DockerImageName; +import java.util.concurrent.TimeUnit; + +import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; + /** * */ @@ -25,7 +25,9 @@ public class BaseWebDriverContainerTest { public static Network NETWORK = Network.newNetwork(); @ClassRule - public static GenericContainer HELLO_WORLD = new GenericContainer<>(DockerImageName.parse("testcontainers/helloworld:1.1.0")) + public static GenericContainer HELLO_WORLD = new GenericContainer<>( + DockerImageName.parse("testcontainers/helloworld:1.1.0") + ) .withNetwork(NETWORK) .withNetworkAliases("helloworld") .withExposedPorts(8080, 8081) @@ -39,17 +41,13 @@ protected static void doSimpleExplore(BrowserWebDriverContainer rule) { driver.get("http://helloworld:8080"); WebElement title = driver.findElement(By.tagName("h1")); - assertEquals("the index page contains the title 'Hello world'", - "Hello world", - title.getText().trim() - ); + assertEquals("the index page contains the title 'Hello world'", "Hello world", title.getText().trim()); } protected void assertBrowserNameIs(BrowserWebDriverContainer rule, String expectedName) { RemoteWebDriver driver = setupDriverFromRule(rule); String actual = driver.getCapabilities().getBrowserName(); - assertTrue(format("actual browser name is %s", actual), - actual.equals(expectedName)); + assertTrue(String.format("actual browser name is %s", actual), actual.equals(expectedName)); } @NotNull diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java index a53fa532f99..60d113dc290 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java @@ -9,10 +9,10 @@ import org.openqa.selenium.firefox.FirefoxOptions; import org.testcontainers.containers.BrowserWebDriverContainer; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; -import static java.util.Collections.emptyList; -import static java.util.stream.Collectors.toList; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class BrowserWebDriverContainerTest { @@ -40,7 +40,6 @@ public void provideDefaultNoProxyEnvironmentIfNotSet() { try ( BrowserWebDriverContainer chromeWithoutNoProxySet = new BrowserWebDriverContainer() .withCapabilities(new ChromeOptions()) - ) { chromeWithoutNoProxySet.start(); @@ -49,7 +48,6 @@ public void provideDefaultNoProxyEnvironmentIfNotSet() { } } - @Test public void createContainerWithShmVolume() { Assume.assumeFalse("SHM isn't mounted on Windows", SystemUtils.IS_OS_WINDOWS); @@ -76,19 +74,19 @@ public void createContainerWithoutShmVolume() { ) { webDriverContainer.start(); - assertEquals("Shared memory size is configured", - 512 * FileUtils.ONE_MB, - webDriverContainer.getShmSize()); + assertEquals("Shared memory size is configured", 512 * FileUtils.ONE_MB, webDriverContainer.getShmSize()); - assertEquals("No shm mounts present", emptyList(), shmVolumes(webDriverContainer)); + assertEquals("No shm mounts present", Collections.emptyList(), shmVolumes(webDriverContainer)); } } private List shmVolumes(final BrowserWebDriverContainer container) { - return container.getContainerInfo().getMounts() + return container + .getContainerInfo() + .getMounts() .stream() // destination path is always /dev/shm .filter(m -> m.getDestination().getPath().equals("/dev/shm")) - .collect(toList()); + .collect(Collectors.toList()); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java index fdf56aa0134..b2b7d8d6b1c 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java @@ -1,6 +1,5 @@ package org.testcontainers.junit; - import com.google.common.io.PatternFilenameFilter; import org.junit.Rule; import org.junit.Test; @@ -9,6 +8,7 @@ import org.junit.runner.RunWith; import org.openqa.selenium.chrome.ChromeOptions; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode; import org.testcontainers.containers.DefaultRecordingFileFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.VncRecordingContainer; @@ -21,14 +21,12 @@ import java.io.File; import java.io.IOException; import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.Optional; import java.util.concurrent.TimeUnit; -import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; -import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_FAILING; @RunWith(Enclosed.class) public class ChromeRecordingWebDriverContainerTest extends BaseWebDriverContainerTest { @@ -52,7 +50,7 @@ public void recordingTestThatShouldBeRecordedAndRetainedInFlvFormatAsDefault() t // To do this, simply add extra parameters to the rule constructor, so video will default to FLV format: BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, target) + .withRecordingMode(VncRecordingMode.RECORD_ALL, target) // } .withRecordingFileFactory(new DefaultRecordingFileFactory()) .withNetwork(NETWORK) @@ -62,22 +60,26 @@ public void recordingTestThatShouldBeRecordedAndRetainedInFlvFormatAsDefault() t } } - private File[] runSimpleExploreInContainer(BrowserWebDriverContainer container, String fileNamePattern) throws InterruptedException { + private File[] runSimpleExploreInContainer(BrowserWebDriverContainer container, String fileNamePattern) + throws InterruptedException { container.start(); TimeUnit.MILLISECONDS.sleep(MINIMUM_VIDEO_DURATION_MILLISECONDS); doSimpleExplore(container); - container.afterTest(new TestDescription() { - @Override - public String getTestId() { - return getFilesystemFriendlyName(); - } - - @Override - public String getFilesystemFriendlyName() { - return "ChromeThatRecordsAllTests-recordingTestThatShouldBeRecordedAndRetained"; - } - }, Optional.empty()); + container.afterTest( + new TestDescription() { + @Override + public String getTestId() { + return getFilesystemFriendlyName(); + } + + @Override + public String getFilesystemFriendlyName() { + return "ChromeThatRecordsAllTests-recordingTestThatShouldBeRecordedAndRetained"; + } + }, + Optional.empty() + ); return vncRecordingDirectory.getRoot().listFiles(new PatternFilenameFilter(fileNamePattern)); } @@ -90,7 +92,7 @@ public void recordingTestShouldHaveFlvExtension() throws InterruptedException { // Set (explicitly) FLV format for recorded video: BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, target, VncRecordingFormat.FLV) + .withRecordingMode(VncRecordingMode.RECORD_ALL, target, VncRecordingFormat.FLV) // } .withRecordingFileFactory(new DefaultRecordingFileFactory()) .withNetwork(NETWORK) @@ -108,7 +110,7 @@ public void recordingTestShouldHaveMp4Extension() throws InterruptedException { // Set MP4 format for recorded video: BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, target, VncRecordingFormat.MP4) + .withRecordingMode(VncRecordingMode.RECORD_ALL, target, VncRecordingFormat.MP4) // } .withRecordingFileFactory(new DefaultRecordingFileFactory()) .withNetwork(NETWORK) @@ -124,7 +126,7 @@ public void recordingTestThatShouldHaveCorrectDuration() throws IOException, Int try ( BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, vncRecordingDirectory.getRoot()) + .withRecordingMode(VncRecordingMode.RECORD_ALL, vncRecordingDirectory.getRoot()) .withRecordingFileFactory(new DefaultRecordingFileFactory()) .withNetwork(NETWORK) ) { @@ -132,19 +134,28 @@ public void recordingTestThatShouldHaveCorrectDuration() throws IOException, Int mountableFile = MountableFile.forHostPath(recordedFiles[0].getCanonicalPath()); } - try (GenericContainer container = new GenericContainer<>(DockerImageName.parse("testcontainers/vnc-recorder:1.2.0"))) { + try ( + GenericContainer container = new GenericContainer<>( + DockerImageName.parse("testcontainers/vnc-recorder:1.2.0") + ) + ) { String recordFileContainerPath = "/tmp/chromeTestRecord.flv"; - container.withCopyFileToContainer(mountableFile, recordFileContainerPath) - .withCreateContainerCmdModifier(createContainerCmd -> createContainerCmd.withEntrypoint("ffmpeg")) - .withCommand("-i", recordFileContainerPath, "-f", "null", "-") - .waitingFor(new LogMessageWaitStrategy() - .withRegEx(".*Duration.*") - .withStartupTimeout(Duration.of(60, SECONDS))) - .start(); + container + .withCopyFileToContainer(mountableFile, recordFileContainerPath) + .withCreateContainerCmdModifier(createContainerCmd -> createContainerCmd.withEntrypoint("ffmpeg")) + .withCommand("-i", recordFileContainerPath, "-f", "null", "-") + .waitingFor( + new LogMessageWaitStrategy() + .withRegEx(".*Duration.*") + .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS)) + ) + .start(); String ffmpegOutput = container.getLogs(); - assertTrue("Duration is incorrect in:\n " + ffmpegOutput, - ffmpegOutput.contains("Duration: 00:") && !(ffmpegOutput.contains("Duration: 00:00:00.00"))); + assertTrue( + "Duration is incorrect in:\n " + ffmpegOutput, + ffmpegOutput.contains("Duration: 00:") && !(ffmpegOutput.contains("Duration: 00:00:00.00")) + ); } } } @@ -180,7 +191,7 @@ public void recordingTestThatShouldBeRecordedAndRetained() throws InterruptedExc // or if you only want videos for test failures: BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_FAILING, target) + .withRecordingMode(VncRecordingMode.RECORD_FAILING, target) // } .withRecordingFileFactory(new DefaultRecordingFileFactory()) .withNetwork(NETWORK) @@ -189,25 +200,26 @@ public void recordingTestThatShouldBeRecordedAndRetained() throws InterruptedExc TimeUnit.MILLISECONDS.sleep(MINIMUM_VIDEO_DURATION_MILLISECONDS); doSimpleExplore(chrome); - chrome.afterTest(new TestDescription() { - @Override - public String getTestId() { - return getFilesystemFriendlyName(); - } - - @Override - public String getFilesystemFriendlyName() { - return "ChromeThatRecordsFailingTests-recordingTestThatShouldBeRecordedAndRetained"; - } - }, Optional.of(new RuntimeException("Force writing of video file."))); + chrome.afterTest( + new TestDescription() { + @Override + public String getTestId() { + return getFilesystemFriendlyName(); + } + + @Override + public String getFilesystemFriendlyName() { + return "ChromeThatRecordsFailingTests-recordingTestThatShouldBeRecordedAndRetained"; + } + }, + Optional.of(new RuntimeException("Force writing of video file.")) + ); String[] files = vncRecordingDirectory.getRoot().list(new PatternFilenameFilter("FAILED-.*\\.flv")); assertEquals("Recorded file not found", 1, files.length); } - } - private static class CustomRecordingFileFactory extends DefaultRecordingFileFactory { - } + private static class CustomRecordingFileFactory extends DefaultRecordingFileFactory {} } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java index bea1909a145..eb9872b06e9 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java @@ -15,7 +15,7 @@ public class ChromeWebDriverContainerTest extends BaseWebDriverContainerTest { @Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) - // } + // } .withNetwork(NETWORK); @Before diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java index b1214d18b60..d20f8c3aad8 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ContainerWithoutCapabilitiesTest.java @@ -4,11 +4,10 @@ import org.junit.Test; import org.testcontainers.containers.BrowserWebDriverContainer; -public class ContainerWithoutCapabilitiesTest extends BaseWebDriverContainerTest{ +public class ContainerWithoutCapabilitiesTest extends BaseWebDriverContainerTest { @Rule - public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() - .withNetwork(NETWORK); + public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>().withNetwork(NETWORK); @Test public void chromeIsStartedIfNoCapabilitiesProvided() { @@ -16,7 +15,7 @@ public void chromeIsStartedIfNoCapabilitiesProvided() { } @Test - public void simpleExploreTestWhenNoCapabilitiesProvided(){ + public void simpleExploreTestWhenNoCapabilitiesProvided() { doSimpleExplore(chrome); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java index 8448dc40d53..362be6550e4 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/CustomWaitTimeoutWebDriverContainerTest.java @@ -6,8 +6,7 @@ import org.testcontainers.containers.BrowserWebDriverContainer; import java.time.Duration; - -import static java.time.temporal.ChronoUnit.SECONDS; +import java.time.temporal.ChronoUnit; /** * @@ -17,7 +16,7 @@ public class CustomWaitTimeoutWebDriverContainerTest extends BaseWebDriverContai @Rule public BrowserWebDriverContainer chromeWithCustomTimeout = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) - .withStartupTimeout(Duration.of(30, SECONDS)) + .withStartupTimeout(Duration.of(30, ChronoUnit.SECONDS)) .withNetwork(NETWORK); @Test diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java index 1cffec16bc6..e56b33a1704 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/FirefoxWebDriverContainerTest.java @@ -14,8 +14,8 @@ public class FirefoxWebDriverContainerTest extends BaseWebDriverContainerTest { // junitRule { @Rule public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer<>() - .withCapabilities(new FirefoxOptions()) - // } + .withCapabilities(new FirefoxOptions()) + // } .withNetwork(NETWORK); @Before diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java index 3c071984dfb..2d2feb6aaff 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java @@ -22,11 +22,11 @@ public class LocalServerWebDriverContainerTest { public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>() .withAccessToHost(true) .withCapabilities(new ChromeOptions()); + private int localPort; @Before public void setupLocalServer() throws Exception { - // Set up a local Jetty HTTP server Server server = new Server(); server.addConnector(new SocketConnector()); @@ -53,6 +53,10 @@ public void testConnection() { String headingText = driver.findElement(By.cssSelector("h1")).getText().trim(); - assertEquals("The hardcoded success message was found on a page fetched from a local server", "It worked", headingText); + assertEquals( + "The hardcoded success message was found on a page fetched from a local server", + "It worked", + headingText + ); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumStartTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumStartTest.java index a236a9696c1..04a31662099 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumStartTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumStartTest.java @@ -15,19 +15,19 @@ public class SeleniumStartTest { @Parameterized.Parameters(name = "tag: {0}") public static String[] data() { - return new String[]{"4.0.0", "3.4.0", "2.53.0", "2.45.0"}; + return new String[] { "4.0.0", "3.4.0", "2.53.0", "2.45.0" }; } - @Parameterized.Parameter() + @Parameterized.Parameter public String tag; @Test public void testAdditionalStartupString() { - final DockerImageName imageName = DockerImageName - .parse("selenium/standalone-chrome") - .withTag(tag); - try (BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>(imageName) - .withCapabilities(new ChromeOptions())) { + final DockerImageName imageName = DockerImageName.parse("selenium/standalone-chrome").withTag(tag); + try ( + BrowserWebDriverContainer chrome = new BrowserWebDriverContainer<>(imageName) + .withCapabilities(new ChromeOptions()) + ) { chrome.start(); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java index d706d0fc390..4cbfca77d21 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java @@ -8,7 +8,6 @@ import static org.rnorth.visibleassertions.VisibleAssertions.*; - /** * Created by Julien LAMY */ @@ -35,5 +34,4 @@ private void checkSeleniumVersionDetected(String urlManifest, String expectedVer String seleniumVersion = SeleniumUtils.getSeleniumVersionFromManifest(manifest); assertEquals("Check if Selenium Version detected is the correct one.", expectedVersion, seleniumVersion); } - } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java index 9a15c6b466d..e3db8ad5887 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/SpecificImageNameWebDriverContainerTest.java @@ -8,8 +8,9 @@ public class SpecificImageNameWebDriverContainerTest extends BaseWebDriverContainerTest { - private static final DockerImageName FIREFOX_IMAGE = DockerImageName - .parse("selenium/standalone-firefox:2.53.1-beryllium"); + private static final DockerImageName FIREFOX_IMAGE = DockerImageName.parse( + "selenium/standalone-firefox:2.53.1-beryllium" + ); @Rule public BrowserWebDriverContainer firefox = new BrowserWebDriverContainer<>(FIREFOX_IMAGE) diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java index 4492ca0befe..f831cdd82e9 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java @@ -1,5 +1,13 @@ package org.testcontainers.containers; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.apache.commons.io.IOUtils; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URISyntaxException; @@ -11,15 +19,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.apache.commons.io.IOUtils; - -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - /** * Utils class which can create collections and configurations. * @@ -38,7 +37,13 @@ public class SolrClientUtils { * @param solrConfig the url under which the solrconfig.xml can be found * @param solrSchema the url under which the schema.xml can be found or null if the default schema should be used */ - public static void uploadConfiguration(String hostname, int port, String configurationName, URL solrConfig, URL solrSchema) throws URISyntaxException, IOException { + public static void uploadConfiguration( + String hostname, + int port, + String configurationName, + URL solrConfig, + URL solrSchema + ) throws URISyntaxException, IOException { Map parameters = new HashMap<>(); parameters.put("action", "UPLOAD"); parameters.put("name", configurationName); @@ -46,7 +51,6 @@ public static void uploadConfiguration(String hostname, int port, String configu byte[] configurationZipFile = generateConfigZipFile(solrConfig, solrSchema); executePost(url, configurationZipFile); - } /** @@ -58,7 +62,8 @@ public static void uploadConfiguration(String hostname, int port, String configu * @param configurationName the name of the configuration which should used to create the collection * or null if the default configuration should be used */ - public static void createCollection(String hostname, int port, String collectionName, String configurationName) throws URISyntaxException, IOException { + public static void createCollection(String hostname, int port, String collectionName, String configurationName) + throws URISyntaxException, IOException { Map parameters = new HashMap<>(); parameters.put("action", "CREATE"); parameters.put("name", collectionName); @@ -73,16 +78,11 @@ public static void createCollection(String hostname, int port, String collection } private static void executePost(HttpUrl url, byte[] data) throws IOException { + RequestBody requestBody = data == null + ? RequestBody.create(MediaType.parse("text/plain"), "") + : RequestBody.create(MediaType.parse("application/octet-stream"), data); + Request request = new Request.Builder().url(url).post(requestBody).build(); - RequestBody requestBody = data == null ? - RequestBody.create(MediaType.parse("text/plain"), "") : - RequestBody.create(MediaType.parse("application/octet-stream"), data); - ; - - Request request = new Request.Builder() - .url(url) - .post(requestBody) - .build(); Response response = httpClient.newCall(request).execute(); if (!response.isSuccessful()) { String responseBody = ""; @@ -97,7 +97,12 @@ private static void executePost(HttpUrl url, byte[] data) throws IOException { } } - private static HttpUrl generateSolrURL(String hostname, int port, List pathSegments, Map parameters) throws URISyntaxException { + private static HttpUrl generateSolrURL( + String hostname, + int port, + List pathSegments, + Map parameters + ) throws URISyntaxException { HttpUrl.Builder builder = new HttpUrl.Builder(); builder.scheme("http"); builder.host(hostname); diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java index 5ba0865502c..a3b2cfd77c6 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; public class SolrClientUtilsException extends RuntimeException { + public SolrClientUtilsException(int statusCode, String msg) { super("Http Call Status: " + statusCode + "\n" + msg); } diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java index e583c1f54ee..5161bce2738 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainer.java @@ -8,11 +8,10 @@ import java.net.URL; import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.Set; -import static java.time.temporal.ChronoUnit.SECONDS; - /** * SolrContainer allows a solr container to be launched and controlled. */ @@ -27,6 +26,7 @@ public class SolrContainer extends GenericContainer { public static final String DEFAULT_TAG = "8.3.0"; public static final Integer ZOOKEEPER_PORT = 9983; + public static final Integer SOLR_PORT = 8983; private SolrContainerConfiguration configuration; @@ -48,12 +48,12 @@ public SolrContainer(final String dockerImageName) { public SolrContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); - this.waitStrategy = new LogMessageWaitStrategy() - .withRegEx(".*o\\.e\\.j\\.s\\.Server Started.*") - .withStartupTimeout(Duration.of(60, SECONDS)); + this.waitStrategy = + new LogMessageWaitStrategy() + .withRegEx(".*o\\.e\\.j\\.s\\.Server Started.*") + .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS)); this.configuration = new SolrContainerConfiguration(); } @@ -129,7 +129,9 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { if (!configuration.isZookeeper()) { ExecResult result = execInContainer("solr", "create_core", "-c", configuration.getCollectionName()); if (result.getExitCode() != 0) { - throw new IllegalStateException("Unable to create solr core:\nStdout: " + result.getStdout() + "\nStderr:" + result.getStderr()); + throw new IllegalStateException( + "Unable to create solr core:\nStdout: " + result.getStdout() + "\nStderr:" + result.getStderr() + ); } return; } @@ -140,14 +142,15 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { getSolrPort(), configuration.getConfigurationName(), configuration.getSolrConfiguration(), - configuration.getSolrSchema()); + configuration.getSolrSchema() + ); } SolrClientUtils.createCollection( getHost(), getSolrPort(), configuration.getCollectionName(), - configuration.getConfigurationName()); + configuration.getConfigurationName() + ); } } - diff --git a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java index 1f35ce2a810..698e956c8fe 100644 --- a/modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java +++ b/modules/solr/src/main/java/org/testcontainers/containers/SolrContainerConfiguration.java @@ -1,9 +1,9 @@ package org.testcontainers.containers; -import java.net.URL; - import lombok.Data; +import java.net.URL; + /** * @author Simon Schneider */ @@ -11,8 +11,12 @@ public class SolrContainerConfiguration { private boolean zookeeper = true; + private String collectionName = "dummy"; + private String configurationName; + private URL solrConfiguration; + private URL solrSchema; } diff --git a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java index 9f82e2c3af9..9b561e5cda9 100644 --- a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java +++ b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java @@ -10,9 +10,9 @@ import java.io.IOException; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; /** * @author Simon Schneider @@ -20,6 +20,7 @@ public class SolrContainerTest { private static final DockerImageName SOLR_IMAGE = DockerImageName.parse("solr:8.3.0"); + private SolrClient client = null; @After @@ -60,7 +61,10 @@ public void solrCloudPingTest() throws IOException, SolrServerException { container.start(); // Do whatever you want with the client ... - SolrClient client = new Http2SolrClient.Builder("http://" + container.getHost() + ":" + container.getSolrPort() + "/solr").build(); + SolrClient client = new Http2SolrClient.Builder( + "http://" + container.getHost() + ":" + container.getSolrPort() + "/solr" + ) + .build(); SolrPingResponse response = client.ping("dummy"); // Stop the container. @@ -70,9 +74,10 @@ public void solrCloudPingTest() throws IOException, SolrServerException { private SolrClient getClient(SolrContainer container) { if (client == null) { - client = new Http2SolrClient.Builder("http://" + container.getHost() + ":" + container.getSolrPort() + "/solr").build(); + client = + new Http2SolrClient.Builder("http://" + container.getHost() + ":" + container.getSolrPort() + "/solr") + .build(); } return client; } - } diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy index 85b58724000..6c71ac421c6 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/SpockTestDescription.groovy @@ -12,25 +12,25 @@ import org.testcontainers.lifecycle.TestDescription @PackageScope class SpockTestDescription implements TestDescription { - String specName - String featureName + String specName + String featureName - static SpockTestDescription fromTestDescription(IMethodInvocation invocation) { - return new SpockTestDescription([ - specName: invocation.spec.name, - featureName: invocation.feature.name - ]) - } + static SpockTestDescription fromTestDescription(IMethodInvocation invocation) { + return new SpockTestDescription([ + specName: invocation.spec.name, + featureName: invocation.feature.name + ]) + } - @Override - String getTestId() { - return getFilesystemFriendlyName() - } + @Override + String getTestId() { + return getFilesystemFriendlyName() + } - @Override - String getFilesystemFriendlyName() { - return [specName, featureName].collect { - URLEncoder.encode(it, 'UTF-8') - }.join('-') - } + @Override + String getFilesystemFriendlyName() { + return [specName, featureName].collect { + URLEncoder.encode(it, 'UTF-8') + }.join('-') + } } diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy index 675ed68c4a6..2e70b6d589f 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/Testcontainers.groovy @@ -13,5 +13,4 @@ import java.lang.annotation.Target @Target([ElementType.TYPE, ElementType.METHOD]) @ExtensionAnnotation(TestcontainersExtension) @interface Testcontainers { - } diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy index 1f66fd8f596..40392210f3a 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersExtension.groovy @@ -7,26 +7,24 @@ import org.spockframework.runtime.model.SpecInfo class TestcontainersExtension extends AbstractAnnotationDrivenExtension { - @Override - void visitSpecAnnotation(Testcontainers annotation, SpecInfo spec) { - def listener = new ErrorListener() - def interceptor = new TestcontainersMethodInterceptor(spec, listener) - spec.addSetupSpecInterceptor(interceptor) - spec.addCleanupSpecInterceptor(interceptor) - spec.addSetupInterceptor(interceptor) - spec.addCleanupInterceptor(interceptor) - - spec.addListener(listener) - - } - - private class ErrorListener extends AbstractRunListener { - List errors = [] - - @Override - void error(ErrorInfo error) { - errors.add(error) - } - } - + @Override + void visitSpecAnnotation(Testcontainers annotation, SpecInfo spec) { + def listener = new ErrorListener() + def interceptor = new TestcontainersMethodInterceptor(spec, listener) + spec.addSetupSpecInterceptor(interceptor) + spec.addCleanupSpecInterceptor(interceptor) + spec.addSetupInterceptor(interceptor) + spec.addCleanupInterceptor(interceptor) + + spec.addListener(listener) + } + + private class ErrorListener extends AbstractRunListener { + List errors = [] + + @Override + void error(ErrorInfo error) { + errors.add(error) + } + } } diff --git a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy index 16be002aeb1..2399a0a6e32 100644 --- a/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy +++ b/modules/spock/src/main/groovy/org/testcontainers/spock/TestcontainersMethodInterceptor.groovy @@ -11,116 +11,116 @@ import org.testcontainers.spock.TestcontainersExtension.ErrorListener class TestcontainersMethodInterceptor extends AbstractMethodInterceptor { - private final SpecInfo spec - private final ErrorListener errorListener - - TestcontainersMethodInterceptor(SpecInfo spec, ErrorListener errorListener) { - this.spec = spec - this.errorListener = errorListener - } - - @Override - void interceptSetupSpecMethod(IMethodInvocation invocation) throws Throwable { - def containers = findAllContainers(true) - startContainers(containers, invocation) - - def compose = findAllComposeContainers(true) - startComposeContainers(compose, invocation) - - invocation.proceed() - } - - @Override - void interceptCleanupSpecMethod(IMethodInvocation invocation) throws Throwable { - def containers = findAllContainers(true) - stopContainers(containers, invocation) - - def compose = findAllComposeContainers(true) - stopComposeContainers(compose, invocation) - - invocation.proceed() - } - - @Override - void interceptSetupMethod(IMethodInvocation invocation) throws Throwable { - def containers = findAllContainers(false) - startContainers(containers, invocation) - - def compose = findAllComposeContainers(false) - startComposeContainers(compose, invocation) - - invocation.proceed() - } - - - @Override - void interceptCleanupMethod(IMethodInvocation invocation) throws Throwable { - def containers = findAllContainers(false) - stopContainers(containers, invocation) - - def compose = findAllComposeContainers(false) - stopComposeContainers(compose, invocation) - - invocation.proceed() - } - - private List findAllContainers(boolean shared) { - spec.allFields.findAll { FieldInfo f -> - GenericContainer.isAssignableFrom(f.type) && f.shared == shared - } - } - - private List findAllComposeContainers(boolean shared) { - spec.allFields.findAll { FieldInfo f -> - DockerComposeContainer.isAssignableFrom(f.type) && f.shared == shared - } - } - - private static void startContainers(List containers, IMethodInvocation invocation) { - containers.each { FieldInfo f -> - GenericContainer container = readContainerFromField(f, invocation) - if(!container.isRunning()){ - container.start() - } - - if (container instanceof TestLifecycleAware) { - def testDescription = SpockTestDescription.fromTestDescription(invocation) - (container as TestLifecycleAware).beforeTest(testDescription) - } - } - } - - private void stopContainers(List containers, IMethodInvocation invocation) { - containers.each { FieldInfo f -> - GenericContainer container = readContainerFromField(f, invocation) - - if (container instanceof TestLifecycleAware) { - // we assume first error is the one we want - def maybeException = Optional.ofNullable(errorListener.errors[0]?.exception) - def testDescription = SpockTestDescription.fromTestDescription(invocation) - (container as TestLifecycleAware).afterTest(testDescription, maybeException) - } - - container.stop() - } - } - - private static void startComposeContainers(List compose, IMethodInvocation invocation) { - compose.each { FieldInfo f -> - DockerComposeContainer c = f.readValue(invocation.instance) as DockerComposeContainer - c.start() - } - } - - private static void stopComposeContainers(List compose, IMethodInvocation invocation) { - compose.each { FieldInfo f -> - DockerComposeContainer c = f.readValue(invocation.instance) as DockerComposeContainer - c.stop() - } - } - - - private static GenericContainer readContainerFromField(FieldInfo f, IMethodInvocation invocation) { - f.readValue(invocation.instance) as GenericContainer - } + private final SpecInfo spec + private final ErrorListener errorListener + + TestcontainersMethodInterceptor(SpecInfo spec, ErrorListener errorListener) { + this.spec = spec + this.errorListener = errorListener + } + + @Override + void interceptSetupSpecMethod(IMethodInvocation invocation) throws Throwable { + def containers = findAllContainers(true) + startContainers(containers, invocation) + + def compose = findAllComposeContainers(true) + startComposeContainers(compose, invocation) + + invocation.proceed() + } + + @Override + void interceptCleanupSpecMethod(IMethodInvocation invocation) throws Throwable { + def containers = findAllContainers(true) + stopContainers(containers, invocation) + + def compose = findAllComposeContainers(true) + stopComposeContainers(compose, invocation) + + invocation.proceed() + } + + @Override + void interceptSetupMethod(IMethodInvocation invocation) throws Throwable { + def containers = findAllContainers(false) + startContainers(containers, invocation) + + def compose = findAllComposeContainers(false) + startComposeContainers(compose, invocation) + + invocation.proceed() + } + + + @Override + void interceptCleanupMethod(IMethodInvocation invocation) throws Throwable { + def containers = findAllContainers(false) + stopContainers(containers, invocation) + + def compose = findAllComposeContainers(false) + stopComposeContainers(compose, invocation) + + invocation.proceed() + } + + private List findAllContainers(boolean shared) { + spec.allFields.findAll { FieldInfo f -> + GenericContainer.isAssignableFrom(f.type) && f.shared == shared + } + } + + private List findAllComposeContainers(boolean shared) { + spec.allFields.findAll { FieldInfo f -> + DockerComposeContainer.isAssignableFrom(f.type) && f.shared == shared + } + } + + private static void startContainers(List containers, IMethodInvocation invocation) { + containers.each { FieldInfo f -> + GenericContainer container = readContainerFromField(f, invocation) + if(!container.isRunning()){ + container.start() + } + + if (container instanceof TestLifecycleAware) { + def testDescription = SpockTestDescription.fromTestDescription(invocation) + (container as TestLifecycleAware).beforeTest(testDescription) + } + } + } + + private void stopContainers(List containers, IMethodInvocation invocation) { + containers.each { FieldInfo f -> + GenericContainer container = readContainerFromField(f, invocation) + + if (container instanceof TestLifecycleAware) { + // we assume first error is the one we want + def maybeException = Optional.ofNullable(errorListener.errors[0]?.exception) + def testDescription = SpockTestDescription.fromTestDescription(invocation) + (container as TestLifecycleAware).afterTest(testDescription, maybeException) + } + + container.stop() + } + } + + private static void startComposeContainers(List compose, IMethodInvocation invocation) { + compose.each { FieldInfo f -> + DockerComposeContainer c = f.readValue(invocation.instance) as DockerComposeContainer + c.start() + } + } + + private static void stopComposeContainers(List compose, IMethodInvocation invocation) { + compose.each { FieldInfo f -> + DockerComposeContainer c = f.readValue(invocation.instance) as DockerComposeContainer + c.stop() + } + } + + + private static GenericContainer readContainerFromField(FieldInfo f, IMethodInvocation invocation) { + f.readValue(invocation.instance) as GenericContainer + } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/ComposeContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/ComposeContainerIT.groovy index b952dd1c5dc..7294d534275 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/ComposeContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/ComposeContainerIT.groovy @@ -9,27 +9,27 @@ import spock.lang.Specification @Testcontainers class ComposeContainerIT extends Specification { - DockerComposeContainer composeContainer = new DockerComposeContainer( - new File("src/test/resources/docker-compose.yml")) - .withExposedService("whoami_1", 80, Wait.forHttp("/")) + DockerComposeContainer composeContainer = new DockerComposeContainer( + new File("src/test/resources/docker-compose.yml")) + .withExposedService("whoami_1", 80, Wait.forHttp("/")) - String host + String host - int port + int port - def setup() { - host = composeContainer.getServiceHost("whoami_1", 80) - port = composeContainer.getServicePort("whoami_1", 80) - } + def setup() { + host = composeContainer.getServiceHost("whoami_1", 80) + port = composeContainer.getServicePort("whoami_1", 80) + } - def "running compose defined container is accessible on configured port"() { - given: "a http client" - def client = HttpClientBuilder.create().build() + def "running compose defined container is accessible on configured port"() { + given: "a http client" + def client = HttpClientBuilder.create().build() - when: "accessing web server" - def response = client.execute(new HttpGet("http://$host:$port")) + when: "accessing web server" + def response = client.execute(new HttpGet("http://$host:$port")) - then: "docker container is running and returns http status code 200" - response.statusLine.statusCode == 200 - } + then: "docker container is running and returns http status code 200" + response.statusLine.statusCode == 200 + } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy index 639b46f5886..2f44408fed6 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/MySqlContainerIT.groovy @@ -14,13 +14,11 @@ import spock.lang.Specification @Testcontainers class MySqlContainerIT extends Specification { - @Shared - MySQLContainer mySQLContainer = new MySQLContainer(SpockTestImages.MYSQL_IMAGE) - - def "dummy test"() { - expect: - mySQLContainer.isRunning() - } - + @Shared + MySQLContainer mySQLContainer = new MySQLContainer(SpockTestImages.MYSQL_IMAGE) + def "dummy test"() { + expect: + mySQLContainer.isRunning() + } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy index a886d552732..19edca4b459 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/PostgresContainerIT.groovy @@ -13,34 +13,34 @@ import java.sql.Statement @Testcontainers class PostgresContainerIT extends Specification { - @Shared - PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(SpockTestImages.POSTGRES_TEST_IMAGE) - .withDatabaseName("foo") - .withUsername("foo") - .withPassword("secret") - - def "waits until postgres accepts jdbc connections"() { - - given: "a jdbc connection" - HikariConfig hikariConfig = new HikariConfig() - hikariConfig.setJdbcUrl(postgreSQLContainer.jdbcUrl) - hikariConfig.setUsername("foo") - hikariConfig.setPassword("secret") - HikariDataSource ds = new HikariDataSource(hikariConfig) - - when: "querying the database" - Statement statement = ds.getConnection().createStatement() - statement.execute("SELECT 1") - ResultSet resultSet = statement.getResultSet() - resultSet.next() - - then: "result is returned" - int resultSetInt = resultSet.getInt(1) - resultSetInt == 1 - - cleanup: - ds.close() - } + @Shared + PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(SpockTestImages.POSTGRES_TEST_IMAGE) + .withDatabaseName("foo") + .withUsername("foo") + .withPassword("secret") + + def "waits until postgres accepts jdbc connections"() { + + given: "a jdbc connection" + HikariConfig hikariConfig = new HikariConfig() + hikariConfig.setJdbcUrl(postgreSQLContainer.jdbcUrl) + hikariConfig.setUsername("foo") + hikariConfig.setPassword("secret") + HikariDataSource ds = new HikariDataSource(hikariConfig) + + when: "querying the database" + Statement statement = ds.getConnection().createStatement() + statement.execute("SELECT 1") + ResultSet resultSet = statement.getResultSet() + resultSet.next() + + then: "result is returned" + int resultSetInt = resultSet.getInt(1) + resultSetInt == 1 + + cleanup: + ds.close() + } } // } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SharedComposeContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SharedComposeContainerIT.groovy index dd2ce9f5b3c..f728212278f 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/SharedComposeContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SharedComposeContainerIT.groovy @@ -10,28 +10,28 @@ import spock.lang.Specification @Testcontainers class SharedComposeContainerIT extends Specification { - @Shared - DockerComposeContainer composeContainer = new DockerComposeContainer( - new File("src/test/resources/docker-compose.yml")) - .withExposedService("whoami_1", 80, Wait.forHttp("/")) + @Shared + DockerComposeContainer composeContainer = new DockerComposeContainer( + new File("src/test/resources/docker-compose.yml")) + .withExposedService("whoami_1", 80, Wait.forHttp("/")) - String host + String host - int port + int port - def setup() { - host = composeContainer.getServiceHost("whoami_1", 80) - port = composeContainer.getServicePort("whoami_1", 80) - } + def setup() { + host = composeContainer.getServiceHost("whoami_1", 80) + port = composeContainer.getServicePort("whoami_1", 80) + } - def "running compose defined container is accessible on configured port"() { - given: "a http client" - def client = HttpClientBuilder.create().build() + def "running compose defined container is accessible on configured port"() { + given: "a http client" + def client = HttpClientBuilder.create().build() - when: "accessing web server" - def response = client.execute(new HttpGet("http://$host:$port")) + when: "accessing web server" + def response = client.execute(new HttpGet("http://$host:$port")) - then: "docker container is running and returns http status code 200" - response.statusLine.statusCode == 200 - } + then: "docker container is running and returns http status code 200" + response.statusLine.statusCode == 200 + } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy index b9ef64fe475..41432e5e514 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy @@ -3,8 +3,8 @@ package org.testcontainers.spock import org.testcontainers.utility.DockerImageName interface SpockTestImages { - DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.34") - DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") - DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") - DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14") + DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.34") + DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") + DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14") } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy index c28643910a4..567998281a7 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestHierarchyIT.groovy @@ -9,17 +9,15 @@ import spock.lang.Shared */ class TestHierarchyIT extends MySqlContainerIT { - @Shared - PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(SpockTestImages.POSTGRES_TEST_IMAGE) - .withDatabaseName("foo") - .withUsername("foo") - .withPassword("secret") - - def "both containers are running"() { - expect: - postgreSQLContainer.isRunning() - mySQLContainer.isRunning() - - } + @Shared + PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(SpockTestImages.POSTGRES_TEST_IMAGE) + .withDatabaseName("foo") + .withUsername("foo") + .withPassword("secret") + def "both containers are running"() { + expect: + postgreSQLContainer.isRunning() + mySQLContainer.isRunning() + } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java index eb628fd2f33..7502d097008 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareContainerMock.java @@ -8,20 +8,22 @@ import java.util.List; import java.util.Optional; -import static org.testcontainers.spock.SpockTestImages.TINY_IMAGE; - -public class TestLifecycleAwareContainerMock extends GenericContainer implements TestLifecycleAware { +public class TestLifecycleAwareContainerMock + extends GenericContainer + implements TestLifecycleAware { static final String BEFORE_TEST = "beforeTest"; + static final String AFTER_TEST = "afterTest"; final List lifecycleMethodCalls = new ArrayList<>(); + final List lifecycleFilesystemFriendlyNames = new ArrayList<>(); Throwable capturedThrowable; public TestLifecycleAwareContainerMock() { - super(TINY_IMAGE); + super(SpockTestImages.TINY_IMAGE); } @Override diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy index 18f7517ea3f..fae834ea422 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestLifecycleAwareIT.groovy @@ -7,12 +7,12 @@ import spock.util.EmbeddedSpecRunner class TestLifecycleAwareIT extends Specification { - @Unroll("When failing test is #fails, afterTest receives '#filesystemFriendlyNames' and throwable starting with message '#errorMessageStartsWith'") - def "lifecycle awareness"() { - given: + @Unroll("When failing test is #fails, afterTest receives '#filesystemFriendlyNames' and throwable starting with message '#errorMessageStartsWith'") + def "lifecycle awareness"() { + given: - @Language("groovy") - String myTest = """ + @Language("groovy") + String myTest = """ import org.testcontainers.spock.Testcontainers import org.testcontainers.containers.GenericContainer import spock.lang.Specification @@ -28,28 +28,27 @@ class TestLifecycleAwareIT extends Specification { } } """ - and: - def container = new TestLifecycleAwareContainerMock() - System.properties["org.testcontainers.container"] = container - System.properties["org.testcontainers.shouldFail"] = fails - - when: "executing the test" - def runner = new EmbeddedSpecRunner(throwFailure: false) - runner.run(myTest) - - then: "mock container received lifecycle calls as expected" - container.lifecycleMethodCalls == ["beforeTest", "afterTest"] - container.lifecycleFilesystemFriendlyNames.join(",") == filesystemFriendlyNames - if (errorMessageStartsWith) { - assert container.capturedThrowable.message.startsWith(errorMessageStartsWith) - } else { - assert container.capturedThrowable == null - } - - where: - fails | filesystemFriendlyNames | errorMessageStartsWith - false | 'TestLifecycleAwareIT-perform+test' | null - true | 'TestLifecycleAwareIT-perform+test' | "Condition not satisfied:" - } - + and: + def container = new TestLifecycleAwareContainerMock() + System.properties["org.testcontainers.container"] = container + System.properties["org.testcontainers.shouldFail"] = fails + + when: "executing the test" + def runner = new EmbeddedSpecRunner(throwFailure: false) + runner.run(myTest) + + then: "mock container received lifecycle calls as expected" + container.lifecycleMethodCalls == ["beforeTest", "afterTest"] + container.lifecycleFilesystemFriendlyNames.join(",") == filesystemFriendlyNames + if (errorMessageStartsWith) { + assert container.capturedThrowable.message.startsWith(errorMessageStartsWith) + } else { + assert container.capturedThrowable == null + } + + where: + fails | filesystemFriendlyNames | errorMessageStartsWith + false | 'TestLifecycleAwareIT-perform+test' | null + true | 'TestLifecycleAwareIT-perform+test' | "Condition not satisfied:" + } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersRestartBetweenTestsIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersRestartBetweenTestsIT.groovy index 81ed0eea724..ebbb1de2474 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersRestartBetweenTestsIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersRestartBetweenTestsIT.groovy @@ -9,23 +9,22 @@ import spock.lang.Stepwise @Testcontainers class TestcontainersRestartBetweenTestsIT extends Specification { - GenericContainer genericContainer = new GenericContainer(SpockTestImages.HTTPD_IMAGE) - .withExposedPorts(80) + GenericContainer genericContainer = new GenericContainer(SpockTestImages.HTTPD_IMAGE) + .withExposedPorts(80) - @Shared - String lastContainerId + @Shared + String lastContainerId - def "retrieving first id"() { - when: - lastContainerId = genericContainer.containerId + def "retrieving first id"() { + when: + lastContainerId = genericContainer.containerId - then: - true - } - - def "containers is recreated between tests"() { - expect: - genericContainer.containerId != lastContainerId - } + then: + true + } + def "containers is recreated between tests"() { + expect: + genericContainer.containerId != lastContainerId + } } diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy index 23b761fcc38..dd2f8443772 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/TestcontainersSharedContainerIT.groovy @@ -13,35 +13,34 @@ import spock.lang.Stepwise @Testcontainers class TestcontainersSharedContainerIT extends Specification { - @Shared - GenericContainer genericContainer = new GenericContainer(SpockTestImages.HTTPD_IMAGE) - .withExposedPorts(80) - - @Shared - String lastContainerId - - def "starts accessible docker container"() { - given: "a http client" - def client = HttpClientBuilder.create().build() - lastContainerId = genericContainer.containerId - - when: "accessing web server" - CloseableHttpResponse response = performHttpRequest(client) - - then: "docker container is running and returns http status code 200" - response.statusLine.statusCode == 200 - } - - def "containers keeps on running between features"() { - expect: - genericContainer.containerId == lastContainerId - } - - private CloseableHttpResponse performHttpRequest(CloseableHttpClient client) { - String ip = genericContainer.host - String port = genericContainer.getMappedPort(80) - def response = client.execute(new HttpGet("http://$ip:$port")) - response - } - + @Shared + GenericContainer genericContainer = new GenericContainer(SpockTestImages.HTTPD_IMAGE) + .withExposedPorts(80) + + @Shared + String lastContainerId + + def "starts accessible docker container"() { + given: "a http client" + def client = HttpClientBuilder.create().build() + lastContainerId = genericContainer.containerId + + when: "accessing web server" + CloseableHttpResponse response = performHttpRequest(client) + + then: "docker container is running and returns http status code 200" + response.statusLine.statusCode == 200 + } + + def "containers keeps on running between features"() { + expect: + genericContainer.containerId == lastContainerId + } + + private CloseableHttpResponse performHttpRequest(CloseableHttpClient client) { + String ip = genericContainer.host + String port = genericContainer.getMappedPort(80) + def response = client.execute(new HttpGet("http://$ip:$port")) + response + } } diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index e22cc1fdd55..ed8413a2a31 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -22,13 +22,19 @@ public class ToxiproxyContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("shopify/toxiproxy"); + private static final String DEFAULT_TAG = "2.1.0"; + private static final int TOXIPROXY_CONTROL_PORT = 8474; + private static final int FIRST_PROXIED_PORT = 8666; + private static final int LAST_PROXIED_PORT = 8666 + 31; private ToxiproxyClient client; + private final Map proxies = new HashMap<>(); + private final AtomicInteger nextPort = new AtomicInteger(FIRST_PROXIED_PORT); /** @@ -45,7 +51,6 @@ public ToxiproxyContainer(String dockerImageName) { public ToxiproxyContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPorts(TOXIPROXY_CONTROL_PORT); @@ -99,42 +104,55 @@ public ContainerProxy getProxy(GenericContainer container, int port) { public ContainerProxy getProxy(String hostname, int port) { String upstream = hostname + ":" + port; - return proxies.computeIfAbsent(upstream, __ -> { - try { - final int toxiPort = nextPort.getAndIncrement(); - if (toxiPort > LAST_PROXIED_PORT) { - throw new IllegalStateException("Maximum number of proxies exceeded"); + return proxies.computeIfAbsent( + upstream, + __ -> { + try { + final int toxiPort = nextPort.getAndIncrement(); + if (toxiPort > LAST_PROXIED_PORT) { + throw new IllegalStateException("Maximum number of proxies exceeded"); + } + + final Proxy proxy = client.createProxy(upstream, "0.0.0.0:" + toxiPort, upstream); + final int mappedPort = getMappedPort(toxiPort); + return new ContainerProxy(proxy, getHost(), mappedPort, toxiPort); + } catch (IOException e) { + throw new RuntimeException("Proxy could not be created", e); } - - final Proxy proxy = client.createProxy(upstream, "0.0.0.0:" + toxiPort, upstream); - final int mappedPort = getMappedPort(toxiPort); - return new ContainerProxy(proxy, getHost(), mappedPort, toxiPort); - } catch (IOException e) { - throw new RuntimeException("Proxy could not be created", e); } - }); + ); } @RequiredArgsConstructor(access = AccessLevel.PROTECTED) public static class ContainerProxy { + private static final String CUT_CONNECTION_DOWNSTREAM = "CUT_CONNECTION_DOWNSTREAM"; + private static final String CUT_CONNECTION_UPSTREAM = "CUT_CONNECTION_UPSTREAM"; + private final Proxy toxi; + /** * The IP address that this proxy container may be reached on from the host machine. */ - @Getter private final String containerIpAddress; + @Getter + private final String containerIpAddress; + /** * The mapped port of this proxy. This is a port of the host machine. It can be used to * access the Toxiproxy container from the host machine. */ - @Getter private final int proxyPort; + @Getter + private final int proxyPort; + /** * The original (exposed) port of this proxy. This is a port of the Toxiproxy Docker * container. It can be used to access this container from a different Docker container * on the same network. */ - @Getter private final int originalProxyPort; + @Getter + private final int originalProxyPort; + private boolean isCurrentlyCut; public String getName() { diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index 3177fb2e8e8..c5982bc45c1 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -10,7 +10,6 @@ import java.io.IOException; import java.time.Duration; -import static java.lang.String.format; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; @@ -19,6 +18,7 @@ public class ToxiproxyTest { private static final Duration JEDIS_TIMEOUT = Duration.ofSeconds(10); + // spotless:off // creatingProxy { // An alias that can be used to resolve the Toxiproxy container by name in the network it is connected to. // It can be used as a hostname of the Toxiproxy container by other containers in the same network. @@ -29,6 +29,7 @@ public class ToxiproxyTest { public Network network = Network.newNetwork(); private static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:5.0.4"); + // The target container - this could be anything @Rule public GenericContainer redis = new GenericContainer<>(REDIS_IMAGE) @@ -36,12 +37,15 @@ public class ToxiproxyTest { .withNetwork(network); private static final DockerImageName TOXIPROXY_IMAGE = DockerImageName.parse("shopify/toxiproxy:2.1.0"); + // Toxiproxy container, which will be used as a TCP proxy @Rule public ToxiproxyContainer toxiproxy = new ToxiproxyContainer(TOXIPROXY_IMAGE) .withNetwork(network) .withNetworkAliases(TOXIPROXY_NETWORK_ALIAS); + // } + // spotless:on @Test public void testDirect() { @@ -68,12 +72,14 @@ public void testLatencyViaProxy() throws IOException { checkCallWithLatency(jedis, "without interference", 0, 250); + // spotless:off // addingLatency { proxy.toxics() .latency("latency", ToxicDirection.DOWNSTREAM, 1_100) .setJitter(100); // from now on the connection latency should be from 1000-1200 ms. // } + // spotless:on checkCallWithLatency(jedis, "with interference", 1_000, 1_500); } @@ -84,30 +90,42 @@ public void testConnectionCut() { final Jedis jedis = createJedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); jedis.set("somekey", "somevalue"); - assertEquals("access to the container works OK before cutting the connection", "somevalue", jedis.get("somekey")); + assertEquals( + "access to the container works OK before cutting the connection", + "somevalue", + jedis.get("somekey") + ); // disableProxy { proxy.setConnectionCut(true); // for example, expect failure when the connection is cut - assertThrows("calls fail when the connection is cut", - JedisConnectionException.class, () -> { + assertThrows( + "calls fail when the connection is cut", + JedisConnectionException.class, + () -> { jedis.get("somekey"); - }); + } + ); proxy.setConnectionCut(false); // and with the connection re-established, expect success - assertEquals("access to the container works OK after re-establishing the connection", "somevalue", jedis.get("somekey")); + assertEquals( + "access to the container works OK after re-establishing the connection", + "somevalue", + jedis.get("somekey") + ); // } } @Test public void testMultipleProxiesCanBeCreated() { - try (GenericContainer secondRedis = new GenericContainer<>(REDIS_IMAGE) - .withExposedPorts(6379) - .withNetwork(network)) { - + try ( + GenericContainer secondRedis = new GenericContainer<>(REDIS_IMAGE) + .withExposedPorts(6379) + .withNetwork(network) + ) { secondRedis.start(); final ToxiproxyContainer.ContainerProxy firstProxy = toxiproxy.getProxy(redis, 6379); @@ -121,10 +139,13 @@ public void testMultipleProxiesCanBeCreated() { firstProxy.setConnectionCut(true); - assertThrows("calls fail when the connection is cut, for only the relevant proxy", - JedisConnectionException.class, () -> { + assertThrows( + "calls fail when the connection is cut, for only the relevant proxy", + JedisConnectionException.class, + () -> { firstJedis.get("somekey"); - }); + } + ); assertEquals("access via a different proxy is OK", "somevalue", secondJedis.get("somekey")); } @@ -142,11 +163,19 @@ public void testOriginalAndMappedPorts() { final ToxiproxyContainer.ContainerProxy proxy1 = toxiproxy.getProxy("hostname1", 8080); assertEquals("original port is correct", 8667, proxy1.getOriginalProxyPort()); - assertEquals("mapped port is correct", toxiproxy.getMappedPort(proxy1.getOriginalProxyPort()), proxy1.getProxyPort()); + assertEquals( + "mapped port is correct", + toxiproxy.getMappedPort(proxy1.getOriginalProxyPort()), + proxy1.getProxyPort() + ); final ToxiproxyContainer.ContainerProxy proxy2 = toxiproxy.getProxy("hostname2", 9090); assertEquals("original port is correct", 8668, proxy2.getOriginalProxyPort()); - assertEquals("mapped port is correct", toxiproxy.getMappedPort(proxy2.getOriginalProxyPort()), proxy2.getProxyPort()); + assertEquals( + "mapped port is correct", + toxiproxy.getMappedPort(proxy2.getOriginalProxyPort()), + proxy2.getProxyPort() + ); } @Test @@ -163,15 +192,26 @@ public void testControlPort() { assertEquals("control port is mapped from port 8474", toxiproxy.getMappedPort(8474), controlPort); } - private void checkCallWithLatency(Jedis jedis, final String description, int expectedMinLatency, long expectedMaxLatency) { + private void checkCallWithLatency( + Jedis jedis, + final String description, + int expectedMinLatency, + long expectedMaxLatency + ) { final long start = System.currentTimeMillis(); String s = jedis.get("somekey"); final long end = System.currentTimeMillis(); final long duration = end - start; - assertEquals(format("access to the container %s works OK", description), "somevalue", s); - assertTrue(format("%s there is at least %dms latency", description, expectedMinLatency), duration >= expectedMinLatency); - assertTrue(format("%s there is no more than %dms latency", description, expectedMaxLatency), duration < expectedMaxLatency); + assertEquals(String.format("access to the container %s works OK", description), "somevalue", s); + assertTrue( + String.format("%s there is at least %dms latency", description, expectedMinLatency), + duration >= expectedMinLatency + ); + assertTrue( + String.format("%s there is no more than %dms latency", description, expectedMaxLatency), + duration < expectedMaxLatency + ); } private static Jedis createJedis(String host, int port) { diff --git a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java index 825340459f3..9ed18e96d28 100644 --- a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java +++ b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java @@ -1,5 +1,6 @@ package org.testcontainers.containers; +import com.google.common.base.Strings; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.VisibleForTesting; import org.testcontainers.utility.DockerImageName; @@ -9,19 +10,21 @@ import java.util.HashSet; import java.util.Set; -import static com.google.common.base.Strings.nullToEmpty; -import static java.lang.String.format; - public class TrinoContainer extends JdbcDatabaseContainer { + static final String NAME = "trino"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("trinodb/trino"); + static final String IMAGE = "trinodb/trino"; + @VisibleForTesting static final String DEFAULT_TAG = "352"; private static final int TRINO_PORT = 8080; private String username = "test"; + private String catalog = null; public TrinoContainer(final String dockerImageName) { @@ -30,7 +33,6 @@ public TrinoContainer(final String dockerImageName) { public TrinoContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); addExposedPort(TRINO_PORT); } @@ -48,7 +50,12 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return format("jdbc:trino://%s:%s/%s", getHost(), getMappedPort(TRINO_PORT), nullToEmpty(catalog)); + return String.format( + "jdbc:trino://%s:%s/%s", + getHost(), + getMappedPort(TRINO_PORT), + Strings.nullToEmpty(catalog) + ); } @Override diff --git a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java index 233fc1b9b07..30d877c9e4a 100644 --- a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java +++ b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainerProvider.java @@ -6,6 +6,7 @@ * Factory for Trino containers. */ public class TrinoContainerProvider extends JdbcDatabaseContainerProvider { + @Override public boolean supports(String databaseType) { return databaseType.equals(TrinoContainer.NAME); diff --git a/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java index d7f8014ca9a..97bbdf6dedd 100644 --- a/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java +++ b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java @@ -1,20 +1,12 @@ package org.testcontainers.containers; -import org.junit.Assert; import org.junit.Test; import org.testcontainers.TrinoTestImages; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.ResultSet; -import java.sql.SQLException; import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import static java.lang.Integer.parseInt; -import static java.lang.String.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -25,9 +17,11 @@ public class TrinoContainerTest { public void testSimple() throws Exception { try (TrinoContainer trino = new TrinoContainer(TrinoTestImages.TRINO_TEST_IMAGE)) { trino.start(); - try (Connection connection = trino.createConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + try ( + Connection connection = trino.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") + ) { assertTrue("No result", resultSet.next()); assertEquals("Trino version", TrinoContainer.DEFAULT_TAG, resultSet.getString("node_version")); } @@ -38,11 +32,17 @@ public void testSimple() throws Exception { public void testSpecificVersion() throws Exception { try (TrinoContainer trino = new TrinoContainer(TrinoTestImages.TRINO_PREVIOUS_VERSION_TEST_IMAGE)) { trino.start(); - try (Connection connection = trino.createConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) { + try ( + Connection connection = trino.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") + ) { assertTrue("No result", resultSet.next()); - assertEquals("Trino version", TrinoTestImages.TRINO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), resultSet.getString("node_version")); + assertEquals( + "Trino version", + TrinoTestImages.TRINO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), + resultSet.getString("node_version") + ); } } } @@ -52,9 +52,11 @@ public void testInitScript() throws Exception { try (TrinoContainer trino = new TrinoContainer(TrinoTestImages.TRINO_TEST_IMAGE)) { trino.withInitScript("initial.sql"); trino.start(); - try (Connection connection = trino.createConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table")) { + try ( + Connection connection = trino.createConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table") + ) { assertTrue("No result", resultSet.next()); assertEquals("Value", 12345678909324L, resultSet.getObject("a")); assertFalse("Too many result", resultSet.next()); diff --git a/modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java b/modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java index 8f06aef7278..9ec98c2e6d7 100644 --- a/modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java +++ b/modules/trino/src/test/java/org/testcontainers/jdbc/trino/TrinoJDBCDriverTest.java @@ -4,18 +4,18 @@ import org.junit.runners.Parameterized; import org.testcontainers.jdbc.AbstractJDBCDriverTest; +import java.util.Arrays; import java.util.EnumSet; -import static java.util.Arrays.asList; - @RunWith(Parameterized.class) public class TrinoJDBCDriverTest extends AbstractJDBCDriverTest { @Parameterized.Parameters(name = "{index} - {0}") public static Iterable data() { - return asList( - new Object[][]{ - {"jdbc:tc:trino:352://hostname/", EnumSet.of(Options.PmdKnownBroken)}, - }); + return Arrays.asList( + new Object[][] { // + { "jdbc:tc:trino:352://hostname/", EnumSet.of(Options.PmdKnownBroken) }, + } + ); } } diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java index 37e78a14f95..31bb1f31d9f 100644 --- a/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java +++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultContainer.java @@ -1,6 +1,7 @@ package org.testcontainers.vault; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Capability; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; @@ -14,9 +15,6 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import static com.github.dockerjava.api.model.Capability.IPC_LOCK; - - /** * GenericContainer subclass for Vault specific configuration and features. The main feature is the * withSecretInVault method, where users can specify which secrets to be pre-loaded into Vault for @@ -27,11 +25,13 @@ public class VaultContainer> extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("vault"); + private static final String DEFAULT_TAG = "1.1.3"; private static final int VAULT_PORT = 8200; private Map> secretsMap = new HashMap<>(); + private List initCommands = new ArrayList<>(); private int port = VAULT_PORT; @@ -50,13 +50,12 @@ public VaultContainer(String dockerImageName) { public VaultContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); // Use the vault healthcheck endpoint to check for readiness, per https://www.vaultproject.io/api/system/health.html setWaitStrategy(Wait.forHttp("/v1/sys/health").forStatusCode(200)); - withCreateContainerCmdModifier(cmd -> cmd.withCapAdd(IPC_LOCK)); + withCreateContainerCmdModifier(cmd -> cmd.withCapAdd(Capability.IPC_LOCK)); withEnv("VAULT_ADDR", "http://0.0.0.0:" + port); withExposedPorts(port); } @@ -72,7 +71,12 @@ private void addSecrets() { try { this.execInContainer(buildExecCommand(secretsMap)).getStdout().contains("Success"); } catch (IOException | InterruptedException e) { - logger().error("Failed to add these secrets {} into Vault via exec command. Exception message: {}", secretsMap, e.getMessage()); + logger() + .error( + "Failed to add these secrets {} into Vault via exec command. Exception message: {}", + secretsMap, + e.getMessage() + ); } } } @@ -83,22 +87,34 @@ private String[] buildExecCommand(Map> map) { stringBuilder.append(" && vault kv put " + path); secrets.forEach(item -> stringBuilder.append(" " + item)); }); - return new String[]{"/bin/sh", "-c", stringBuilder.toString().substring(4)}; + return new String[] { "/bin/sh", "-c", stringBuilder.toString().substring(4) }; } private void runInitCommands() { if (!initCommands.isEmpty()) { - String commands = initCommands.stream() - .map(command -> "vault " + command) - .collect(Collectors.joining(" && ")); + String commands = initCommands + .stream() + .map(command -> "vault " + command) + .collect(Collectors.joining(" && ")); try { - ExecResult execResult = this.execInContainer(new String[]{"/bin/sh", "-c", commands}); + ExecResult execResult = this.execInContainer(new String[] { "/bin/sh", "-c", commands }); if (execResult.getExitCode() != 0) { - logger().error("Failed to execute these init commands {}. Exit code {}. Stdout {}. Stderr {}", - initCommands, execResult.getExitCode(), execResult.getStdout(), execResult.getStderr()); + logger() + .error( + "Failed to execute these init commands {}. Exit code {}. Stdout {}. Stderr {}", + initCommands, + execResult.getExitCode(), + execResult.getStdout(), + execResult.getStderr() + ); } } catch (IOException | InterruptedException e) { - logger().error("Failed to execute these init commands {}. Exception message: {}", initCommands, e.getMessage()); + logger() + .error( + "Failed to execute these init commands {}. Exception message: {}", + initCommands, + e.getMessage() + ); } } } @@ -166,7 +182,7 @@ public SELF withSecretInVault(String path, String firstSecret, String... remaini /** * Run initialization commands using the vault cli. - * + * * Useful for enableing more secret engines like: *

      *     .withInitCommand("secrets enable pki")
diff --git a/modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java b/modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java
index 58b22f975ff..e5f0db784a8 100644
--- a/modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java
+++ b/modules/vault/src/main/java/org/testcontainers/vault/VaultLogLevel.java
@@ -4,7 +4,11 @@
  * Vault preset of logging levels.
  */
 public enum VaultLogLevel {
-    Trace("trace"), Debug("debug"), Info("info"), Warn("warn"), Error("err");
+    Trace("trace"),
+    Debug("debug"),
+    Info("info"),
+    Warn("warn"),
+    Error("err");
 
     public final String config;
 
diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java
index 4a1a800da17..cd1f1a8acea 100644
--- a/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java
+++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultClientTest.java
@@ -10,7 +10,6 @@
 import java.util.Map;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.testcontainers.vault.VaultTestImages.VAULT_IMAGE;
 
 public class VaultClientTest {
 
@@ -19,10 +18,9 @@ public class VaultClientTest {
     @Test
     public void writeAndReadMultipleValues() throws VaultException {
         try (
-            VaultContainer vaultContainer = new VaultContainer<>(VAULT_IMAGE)
-                    .withVaultToken(VAULT_TOKEN)
+            VaultContainer vaultContainer = new VaultContainer<>(VaultTestImages.VAULT_IMAGE)
+                .withVaultToken(VAULT_TOKEN)
         ) {
-
             vaultContainer.start();
 
             final VaultConfig config = new VaultConfig()
@@ -37,22 +35,14 @@ public void writeAndReadMultipleValues() throws VaultException {
             secrets.put("other_value", "another world");
 
             // Write operation
-            final LogicalResponse writeResponse = vault.logical()
-                .write("secret/hello", secrets);
+            final LogicalResponse writeResponse = vault.logical().write("secret/hello", secrets);
 
             assertThat(writeResponse.getRestResponse().getStatus()).isEqualTo(200);
 
             // Read operation
-            final Map value = vault.logical()
-                .read("secret/hello")
-                .getData();
-
-
-            assertThat(value)
-                .containsEntry("value", "world")
-                .containsEntry("other_value", "another world");
+            final Map value = vault.logical().read("secret/hello").getData();
 
+            assertThat(value).containsEntry("value", "world").containsEntry("other_value", "another world");
         }
-
     }
 }
diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java
index 9dee4c21416..22310bf7a23 100644
--- a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java
+++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java
@@ -7,7 +7,7 @@
 import java.io.IOException;
 
 import static io.restassured.RestAssured.given;
-import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.assertThat;
 
 /**
@@ -22,24 +22,38 @@ public class VaultContainerTest {
     public static VaultContainer vaultContainer = new VaultContainer<>(VaultTestImages.VAULT_IMAGE)
         .withVaultToken(VAULT_TOKEN)
         .withSecretInVault("secret/testing1", "top_secret=password123")
-        .withSecretInVault("secret/testing2",
+        .withSecretInVault(
+            "secret/testing2",
             "secret_one=password1",
             "secret_two=password2",
             "secret_three=password3",
             "secret_three=password3",
-            "secret_four=password4")
+            "secret_four=password4"
+        )
         .withInitCommand("secrets enable transit", "write -f transit/keys/my-key");
 
     @Test
     public void readFirstSecretPathWithCli() throws IOException, InterruptedException {
-        GenericContainer.ExecResult result = vaultContainer.execInContainer("vault", "kv", "get", "-format=json", "secret/testing1");
+        GenericContainer.ExecResult result = vaultContainer.execInContainer(
+            "vault",
+            "kv",
+            "get",
+            "-format=json",
+            "secret/testing1"
+        );
         final String output = result.getStdout().replaceAll("\\r?\\n", "");
         assertThat(output, containsString("password123"));
     }
 
     @Test
     public void readSecondSecretPathWithCli() throws IOException, InterruptedException {
-        GenericContainer.ExecResult result = vaultContainer.execInContainer("vault", "kv", "get", "-format=json", "secret/testing2");
+        GenericContainer.ExecResult result = vaultContainer.execInContainer(
+            "vault",
+            "kv",
+            "get",
+            "-format=json",
+            "secret/testing2"
+        );
         final String output = result.getStdout().replaceAll("\\r?\\n", "");
         System.out.println("output = " + output);
         assertThat(output, containsString("password1"));
@@ -50,40 +64,44 @@ public void readSecondSecretPathWithCli() throws IOException, InterruptedExcepti
 
     @Test
     public void readFirstSecretPathOverHttpApi() throws InterruptedException {
-        given().
-            header("X-Vault-Token", VAULT_TOKEN).
-            when().
-            get("http://" + getHostAndPort() + "/v1/secret/data/testing1").
-            then().
-            assertThat().body("data.data.top_secret", equalTo("password123"));
+        given()
+            .header("X-Vault-Token", VAULT_TOKEN)
+            .when()
+            .get("http://" + getHostAndPort() + "/v1/secret/data/testing1")
+            .then()
+            .assertThat()
+            .body("data.data.top_secret", equalTo("password123"));
     }
 
     @Test
     public void readSecondSecretPathOverHttpApi() throws InterruptedException {
-        given().
-            header("X-Vault-Token", VAULT_TOKEN).
-            when().
-            get("http://" + getHostAndPort() + "/v1/secret/data/testing2").
-            then().
-            assertThat().body("data.data.secret_one", containsString("password1")).
-            assertThat().body("data.data.secret_two", containsString("password2")).
-            assertThat().body("data.data.secret_three", hasItem("password3")).
-            assertThat().body("data.data.secret_four", containsString("password4"));
+        given()
+            .header("X-Vault-Token", VAULT_TOKEN)
+            .when()
+            .get("http://" + getHostAndPort() + "/v1/secret/data/testing2")
+            .then()
+            .assertThat()
+            .body("data.data.secret_one", containsString("password1"))
+            .assertThat()
+            .body("data.data.secret_two", containsString("password2"))
+            .assertThat()
+            .body("data.data.secret_three", hasItem("password3"))
+            .assertThat()
+            .body("data.data.secret_four", containsString("password4"));
     }
 
     @Test
     public void readTransitKeyOverHttpApi() throws InterruptedException {
-        given().
-            header("X-Vault-Token", VAULT_TOKEN).
-            when().
-            get("http://" + getHostAndPort() + "/v1/transit/keys/my-key").
-            then().
-            assertThat().body("data.name", equalTo("my-key"));
+        given()
+            .header("X-Vault-Token", VAULT_TOKEN)
+            .when()
+            .get("http://" + getHostAndPort() + "/v1/transit/keys/my-key")
+            .then()
+            .assertThat()
+            .body("data.name", equalTo("my-key"));
     }
 
     private String getHostAndPort() {
         return vaultContainer.getHost() + ":" + vaultContainer.getMappedPort(8200);
     }
-
-
 }
diff --git a/test-support/src/main/java/org/testcontainers/testsupport/Flaky.java b/test-support/src/main/java/org/testcontainers/testsupport/Flaky.java
index cc5f6f947fa..83e18bfa161 100644
--- a/test-support/src/main/java/org/testcontainers/testsupport/Flaky.java
+++ b/test-support/src/main/java/org/testcontainers/testsupport/Flaky.java
@@ -1,19 +1,17 @@
 package org.testcontainers.testsupport;
 
+import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
 /**
  * Annotation for test methods that should be retried in the event of failure. See {@link FlakyTestJUnit4RetryRule} for
  * more details.
  */
-@Retention(RUNTIME)
-@Target({METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
 public @interface Flaky {
-
     /**
      * @return a URL for a GitHub issue where this flaky test can be discussed, and where actions to resolve it can be
      * coordinated.
diff --git a/test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java b/test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java
index aa1a3ed3c5f..759e23ebbca 100644
--- a/test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java
+++ b/test-support/src/main/java/org/testcontainers/testsupport/FlakyTestJUnit4RetryRule.java
@@ -31,7 +31,6 @@ public class FlakyTestJUnit4RetryRule implements TestRule {
 
     @Override
     public Statement apply(Statement base, Description description) {
-
         final Flaky annotation = description.getAnnotation(Flaky.class);
 
         if (annotation == null) {
@@ -53,11 +52,13 @@ public Statement apply(Statement base, Description description) {
         try {
             reviewDate = LocalDate.parse(annotation.reviewDate());
         } catch (DateTimeParseException e) {
-            throw new IllegalArgumentException("@Flaky reviewDate could not be parsed. Please provide a date in yyyy-mm-dd format");
+            throw new IllegalArgumentException(
+                "@Flaky reviewDate could not be parsed. Please provide a date in yyyy-mm-dd format"
+            );
         }
 
         // the annotation should only have an effect before the review date, to encourage review and resolution
-        if ( LocalDate.now().isBefore(reviewDate) ) {
+        if (LocalDate.now().isBefore(reviewDate)) {
             return new RetryingStatement(base, description, maxTries);
         } else {
             return base;
@@ -65,8 +66,11 @@ public Statement apply(Statement base, Description description) {
     }
 
     private static class RetryingStatement extends Statement {
+
         private final Statement base;
+
         private final Description description;
+
         private final int maxTries;
 
         RetryingStatement(Statement base, Description description, int maxTries) {
@@ -77,7 +81,6 @@ private static class RetryingStatement extends Statement {
 
         @Override
         public void evaluate() {
-
             int attempts = 0;
             final List causes = new ArrayList<>();
 
@@ -93,7 +96,8 @@ public void evaluate() {
 
             throw new IllegalStateException(
                 "@Flaky-annotated test failed despite retries.",
-                new MultipleFailureException(causes));
+                new MultipleFailureException(causes)
+            );
         }
     }
 }
diff --git a/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java b/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java
index 07b0ffe1fa8..14a3d4c018c 100644
--- a/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java
+++ b/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java
@@ -12,11 +12,15 @@
 public class FlakyRuleTest {
 
     private static final String VALID_URL = "http://some.url/here";
+
     private static final String INVALID_URL = "";
 
     private static final String VALID_DATE_IN_FAR_FUTURE = "2063-04-05";
+
     private static final String VALID_DATE_IN_PAST = "1991-08-16";
+
     private static final String INVALID_DATE = "91-01-45";
+
     private static final int DEFAULT_TRIES = 3;
 
     private FlakyTestJUnit4RetryRule rule = new FlakyTestJUnit4RetryRule();
@@ -28,9 +32,7 @@ public void testIgnoresMethodWithoutAnnotation() throws Throwable {
         try {
             rule.apply(statement, description).evaluate();
             fail("Should not reach here");
-        } catch (Exception ignored) {
-
-        }
+        } catch (Exception ignored) {}
         assertEquals("The statement should only be invoked once, even if it throws", 1, statement.invocationCount);
     }
 
@@ -42,9 +44,7 @@ public void testRetriesMethodWithAnnotationUntilFailure() throws Throwable {
         try {
             rule.apply(statement, description).evaluate();
             fail("Should not reach here");
-        } catch (Exception ignored) {
-
-        }
+        } catch (Exception ignored) {}
         assertEquals("The statement should be invoked three times", 3, statement.invocationCount);
     }
 
@@ -56,9 +56,7 @@ public void testCustomRetryCount() throws Throwable {
         try {
             rule.apply(statement, description).evaluate();
             fail("Should not reach here");
-        } catch (Exception ignored) {
-
-        }
+        } catch (Exception ignored) {}
         assertEquals("The statement should be invoked ten times", 10, statement.invocationCount);
     }
 
@@ -70,7 +68,11 @@ public void testRetriesMethodWithAnnotationUntilSuccess() throws Throwable {
 
         rule.apply(statement, description).evaluate();
 
-        assertEquals("The statement should be invoked three times, and succeed the third time", 3, statement.invocationCount);
+        assertEquals(
+            "The statement should be invoked three times, and succeed the third time",
+            3,
+            statement.invocationCount
+        );
     }
 
     @Test
@@ -91,9 +93,7 @@ public void testTreatsExpiredAnnotationAsNoAnnotation() throws Throwable {
         try {
             rule.apply(statement, description).evaluate();
             fail("Should not reach here");
-        } catch (Exception ignored) {
-
-        }
+        } catch (Exception ignored) {}
         assertEquals("The statement should only be invoked once, even if it throws", 1, statement.invocationCount);
     }
 
@@ -104,9 +104,7 @@ public void testThrowsOnInvalidDateFormat() throws Throwable {
         try {
             rule.apply(statement, description).evaluate();
             fail("Should not reach here");
-        } catch (IllegalArgumentException ignored) {
-
-        }
+        } catch (IllegalArgumentException ignored) {}
         assertEquals("The statement should not be invoked if the annotation is invalid", 0, statement.invocationCount);
     }
 
@@ -117,14 +115,16 @@ public void testThrowsOnInvalidGitHubUrl() throws Throwable {
         try {
             rule.apply(statement, description).evaluate();
             fail("Should not reach here");
-        } catch (IllegalArgumentException ignored) {
-
-        }
+        } catch (IllegalArgumentException ignored) {}
         assertEquals("The statement should not be invoked if the annotation is invalid", 0, statement.invocationCount);
     }
 
     private Description newDescriptionWithAnnotation(String reviewDate, String gitHubUrl) {
-        return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(reviewDate, gitHubUrl, DEFAULT_TRIES));
+        return Description.createTestDescription(
+            "SomeTestClass",
+            "someMethod",
+            newAnnotation(reviewDate, gitHubUrl, DEFAULT_TRIES)
+        );
     }
 
     private Description newDescriptionWithoutAnnotation() {
@@ -132,15 +132,27 @@ private Description newDescriptionWithoutAnnotation() {
     }
 
     private Description newDescriptionWithAnnotation() {
-        return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(VALID_DATE_IN_FAR_FUTURE, VALID_URL, DEFAULT_TRIES));
+        return Description.createTestDescription(
+            "SomeTestClass",
+            "someMethod",
+            newAnnotation(VALID_DATE_IN_FAR_FUTURE, VALID_URL, DEFAULT_TRIES)
+        );
     }
 
     private Description newDescriptionWithAnnotationAndCustomTries(int maxTries) {
-        return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(VALID_DATE_IN_FAR_FUTURE, VALID_URL, maxTries));
+        return Description.createTestDescription(
+            "SomeTestClass",
+            "someMethod",
+            newAnnotation(VALID_DATE_IN_FAR_FUTURE, VALID_URL, maxTries)
+        );
     }
 
     private Description newDescriptionWithExpiredAnnotation() {
-        return Description.createTestDescription("SomeTestClass", "someMethod", newAnnotation(VALID_DATE_IN_PAST, VALID_URL, DEFAULT_TRIES));
+        return Description.createTestDescription(
+            "SomeTestClass",
+            "someMethod",
+            newAnnotation(VALID_DATE_IN_PAST, VALID_URL, DEFAULT_TRIES)
+        );
     }
 
     private Flaky newAnnotation(final String reviewDate, String gitHubUrl, int tries) {
@@ -174,7 +186,9 @@ private DummyStatement newStatement(int timesToThrow) {
     }
 
     private static class DummyStatement extends Statement {
+
         int shouldThrowTimes = -1;
+
         int invocationCount = 0;
 
         @Override

From 3a82068bf2b20ff7dfce801fc5ca063698c3e0c9 Mon Sep 17 00:00:00 2001
From: Sergei Egorov 
Date: Thu, 26 May 2022 09:39:03 -0400
Subject: [PATCH 1898/4969] Update mkdocs.yml

---
 mkdocs.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mkdocs.yml b/mkdocs.yml
index 16b2106bb3f..f6daad68155 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -102,4 +102,4 @@ nav:
           - contributing_docs.md
           - bounty.md
 extra:
-    latest_version: 1.16.3
+    latest_version: 1.17.2

From 5d3349ffd6a376f89b92e530b9b7048c826e16b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?=
 
Date: Thu, 26 May 2022 10:13:11 -0500
Subject: [PATCH 1899/4969] Add try-with-resources to HttpWaitStrategyTest
 (#5397)

Co-authored-by: Sergei Egorov 
---
 .../strategy/AbstractWaitStrategyTest.java    |  8 +-
 .../wait/strategy/HttpWaitStrategyTest.java   | 85 ++++++++++++-------
 2 files changed, 58 insertions(+), 35 deletions(-)

diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java
index de16eb0e582..530638f0f70 100644
--- a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java
+++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java
@@ -84,7 +84,9 @@ protected GenericContainer startContainerWithCommand(
      * @param shellCommand the shell command to execute
      */
     protected void waitUntilReadyAndSucceed(String shellCommand) {
-        waitUntilReadyAndSucceed(startContainerWithCommand(shellCommand));
+        try (GenericContainer container = startContainerWithCommand(shellCommand)) {
+            waitUntilReadyAndSucceed(container);
+        }
     }
 
     /**
@@ -94,7 +96,9 @@ protected void waitUntilReadyAndSucceed(String shellCommand) {
      * @param shellCommand the shell command to execute
      */
     protected void waitUntilReadyAndTimeout(String shellCommand) {
-        waitUntilReadyAndTimeout(startContainerWithCommand(shellCommand));
+        try (GenericContainer container = startContainerWithCommand(shellCommand)) {
+            waitUntilReadyAndTimeout(container);
+        }
     }
 
     /**
diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java
index 7014749115e..972bf2ab66a 100644
--- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java
+++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java
@@ -11,8 +11,8 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Predicate;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
-import static org.junit.Assert.assertThat;
 
 /**
  * Tests for {@link HttpWaitStrategy}.
@@ -45,16 +45,19 @@ public void testWaitUntilReadyWithSuccess() {
     public void testWaitUntilReadyWithSuccessWithCustomHeaders() {
         HashMap headers = new HashMap<>();
         headers.put("baz", "boo");
-        GenericContainer container = startContainerWithCommand(
-            createShellCommand("200 OK", GOOD_RESPONSE_BODY),
-            createHttpWaitStrategy(ready).withHeader("foo", "bar").withHeaders(headers)
-        );
-        waitUntilReadyAndSucceed(container);
+        try (
+            GenericContainer container = startContainerWithCommand(
+                createShellCommand("200 OK", GOOD_RESPONSE_BODY),
+                createHttpWaitStrategy(ready).withHeader("foo", "bar").withHeaders(headers)
+            )
+        ) {
+            waitUntilReadyAndSucceed(container);
 
-        String logs = container.getLogs();
+            String logs = container.getLogs();
 
-        assertThat(logs, containsString("foo: bar"));
-        assertThat(logs, containsString("baz: boo"));
+            assertThat(logs, containsString("foo: bar"));
+            assertThat(logs, containsString("baz: boo"));
+        }
     }
 
     /**
@@ -63,12 +66,14 @@ public void testWaitUntilReadyWithSuccessWithCustomHeaders() {
      */
     @Test
     public void testWaitUntilReadyWithTlsAndAllowUnsecure() {
-        waitUntilReadyAndSucceed(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createHttpsShellCommand("200 OK", GOOD_RESPONSE_BODY, 8080),
                 createHttpWaitStrategy(ready).usingTls().allowInsecure()
             )
-        );
+        ) {
+            waitUntilReadyAndSucceed(container);
+        }
     }
 
     /**
@@ -77,12 +82,14 @@ public void testWaitUntilReadyWithTlsAndAllowUnsecure() {
      */
     @Test
     public void testWaitUntilReadyWithUnauthorizedWithLambda() {
-        waitUntilReadyAndSucceed(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY),
                 createHttpWaitStrategy(ready).forStatusCodeMatching(it -> it >= 200 && it < 300 || it == 401)
             )
-        );
+        ) {
+            waitUntilReadyAndSucceed(container);
+        }
     }
 
     /**
@@ -91,12 +98,14 @@ public void testWaitUntilReadyWithUnauthorizedWithLambda() {
      */
     @Test
     public void testWaitUntilReadyWithManyStatusCodes() {
-        waitUntilReadyAndSucceed(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY),
                 createHttpWaitStrategy(ready).forStatusCode(300).forStatusCode(401).forStatusCode(500)
             )
-        );
+        ) {
+            waitUntilReadyAndSucceed(container);
+        }
     }
 
     /**
@@ -106,15 +115,17 @@ public void testWaitUntilReadyWithManyStatusCodes() {
      */
     @Test
     public void testWaitUntilReadyWithManyStatusCodesAndLambda() {
-        waitUntilReadyAndSucceed(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY),
                 createHttpWaitStrategy(ready)
                     .forStatusCode(300)
                     .forStatusCode(500)
                     .forStatusCodeMatching(it -> it == 401)
             )
-        );
+        ) {
+            waitUntilReadyAndSucceed(container);
+        }
     }
 
     /**
@@ -124,12 +135,14 @@ public void testWaitUntilReadyWithManyStatusCodesAndLambda() {
      */
     @Test
     public void testWaitUntilReadyWithTimeoutAndWithManyStatusCodesAndLambda() {
-        waitUntilReadyAndTimeout(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createShellCommand("401 UNAUTHORIZED", GOOD_RESPONSE_BODY),
                 createHttpWaitStrategy(ready).forStatusCode(300).forStatusCodeMatching(it -> it == 500)
             )
-        );
+        ) {
+            waitUntilReadyAndTimeout(container);
+        }
     }
 
     /**
@@ -141,12 +154,14 @@ public void testWaitUntilReadyWithTimeoutAndWithManyStatusCodesAndLambda() {
      */
     @Test
     public void testWaitUntilReadyWithTimeoutAndWithLambdaShouldNotMatchOk() {
-        waitUntilReadyAndTimeout(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createShellCommand("200 OK", GOOD_RESPONSE_BODY),
                 createHttpWaitStrategy(ready).forStatusCodeMatching(it -> it >= 300)
             )
-        );
+        ) {
+            waitUntilReadyAndTimeout(container);
+        }
     }
 
     /**
@@ -172,26 +187,30 @@ public void testWaitUntilReadyWithTimeoutAndBadResponseBody() {
      */
     @Test
     public void testWaitUntilReadyWithSpecificPort() {
-        waitUntilReadyAndSucceed(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createShellCommand("200 OK", GOOD_RESPONSE_BODY, 9090),
                 createHttpWaitStrategy(ready).forPort(9090),
                 7070,
                 8080,
                 9090
             )
-        );
+        ) {
+            waitUntilReadyAndSucceed(container);
+        }
     }
 
     @Test
     public void testWaitUntilReadyWithTimoutCausedByReadTimeout() {
-        waitUntilReadyAndTimeout(
-            startContainerWithCommand(
+        try (
+            GenericContainer container = startContainerWithCommand(
                 createShellCommand("0 Connection Refused", GOOD_RESPONSE_BODY, 9090),
                 createHttpWaitStrategy(ready).forPort(9090).withReadTimeout(Duration.ofMillis(1)),
                 9090
             )
-        );
+        ) {
+            waitUntilReadyAndTimeout(container);
+        }
     }
 
     /**

From aeab7a55c4564e7199efe531705f4c9268839f43 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:40 +0000
Subject: [PATCH 1900/4969] Bump tomcat-jdbc from 10.0.20 to 10.0.21 in
 /modules/jdbc-test

Bumps tomcat-jdbc from 10.0.20 to 10.0.21.

---
updated-dependencies:
- dependency-name: org.apache.tomcat:tomcat-jdbc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/jdbc-test/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle
index d77465c5616..5674f235c7f 100644
--- a/modules/jdbc-test/build.gradle
+++ b/modules/jdbc-test/build.gradle
@@ -14,7 +14,7 @@ dependencies {
         exclude(group: "net.java.dev.jna", module: "jna")
     }
 
-    api 'org.apache.tomcat:tomcat-jdbc:10.0.20'
+    api 'org.apache.tomcat:tomcat-jdbc:10.0.21'
     api 'org.vibur:vibur-dbcp:25.0'
     api 'mysql:mysql-connector-java:8.0.29'
 }

From af64f653ecced7237ee1035504ebaa8d07b430de Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:42 +0000
Subject: [PATCH 1901/4969] Bump neo4j from 3.5.32 to 3.5.33 in /modules/neo4j

Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.32 to 3.5.33.
- [Release notes](https://github.com/neo4j/neo4j/releases)
- [Commits](https://github.com/neo4j/neo4j/compare/3.5.32...3.5.33)

---
updated-dependencies:
- dependency-name: org.neo4j:neo4j
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/neo4j/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle
index efba3dd0db5..da996db865f 100644
--- a/modules/neo4j/build.gradle
+++ b/modules/neo4j/build.gradle
@@ -29,7 +29,7 @@ task customNeo4jPluginJar(type: Jar) {
 processTestResources.dependsOn customNeo4jPluginJar
 
 dependencies {
-    customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.32"
+    customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.33"
 
     api project(":testcontainers")
 

From 443f9d250456be62802b7d8c11bdf8f77e37dac9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:43 +0000
Subject: [PATCH 1902/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/jdbc

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/jdbc/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle
index 84b927ac4a9..54023b6bed4 100644
--- a/modules/jdbc/build.gradle
+++ b/modules/jdbc/build.gradle
@@ -11,5 +11,5 @@ dependencies {
     testImplementation 'com.zaxxer:HikariCP-java6:2.3.13'
     testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4'
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
 }

From a615e261b90cc2d1f1e177f593b529865d5fcac8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:43 +0000
Subject: [PATCH 1903/4969] Bump mockito-core from 4.3.1 to 4.6.0 in /core

Bumps [mockito-core](https://github.com/mockito/mockito) from 4.3.1 to 4.6.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v4.3.1...v4.6.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 core/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/build.gradle b/core/build.gradle
index efb08991f8d..3b148503c51 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -95,7 +95,7 @@ dependencies {
     testImplementation 'com.rabbitmq:amqp-client:5.14.2'
     testImplementation 'org.mongodb:mongo-java-driver:3.12.10'
 
-    testImplementation ('org.mockito:mockito-core:4.3.1') {
+    testImplementation ('org.mockito:mockito-core:4.6.0') {
         exclude(module: 'hamcrest-core')
     }
     // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest

From 84f5d0cebb278b058d3b00bc3e2f3f6008ab154d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:43 +0000
Subject: [PATCH 1904/4969] Bump postgresql from 42.3.4 to 42.3.6 in
 /modules/postgresql

Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.4 to 42.3.6.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.4...REL42.3.6)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/postgresql/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle
index f2c50c30754..d849ad408df 100644
--- a/modules/postgresql/build.gradle
+++ b/modules/postgresql/build.gradle
@@ -11,7 +11,7 @@ dependencies {
 
     testImplementation project(':jdbc-test')
     testImplementation project(':test-support')
-    testImplementation 'org.postgresql:postgresql:42.3.4'
+    testImplementation 'org.postgresql:postgresql:42.3.6'
 
     testImplementation testFixtures(project(':r2dbc'))
     testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE'

From c36cdcad20c666f83b42de1ef9b7e0bb2950d5b7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:43 +0000
Subject: [PATCH 1905/4969] Bump mariadb-java-client from 3.0.3 to 3.0.5 in
 /modules/mariadb

Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 3.0.3 to 3.0.5.
- [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases)
- [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.0.3...3.0.5)

---
updated-dependencies:
- dependency-name: org.mariadb.jdbc:mariadb-java-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/mariadb/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle
index 8d65ed00deb..fd534915ba1 100644
--- a/modules/mariadb/build.gradle
+++ b/modules/mariadb/build.gradle
@@ -10,7 +10,7 @@ dependencies {
     compileOnly 'org.mariadb:r2dbc-mariadb:1.0.3'
 
     testImplementation project(':jdbc-test')
-    testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.3'
+    testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.5'
 
     testImplementation testFixtures(project(':r2dbc'))
     testImplementation 'org.mariadb:r2dbc-mariadb:1.0.2'

From fab88d0d60f90fa9e08f2f6c2f083b3323dbc145 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:44 +0000
Subject: [PATCH 1906/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/neo4j

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/neo4j/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle
index efba3dd0db5..555d55e3a72 100644
--- a/modules/neo4j/build.gradle
+++ b/modules/neo4j/build.gradle
@@ -34,5 +34,5 @@ dependencies {
     api project(":testcontainers")
 
     testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.5'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
 }

From af16f640661406c78c2a591f6dcc80ba981203d6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:44 +0000
Subject: [PATCH 1907/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/kafka

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/kafka/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle
index b9157d9d539..a1022ae1720 100644
--- a/modules/kafka/build.gradle
+++ b/modules/kafka/build.gradle
@@ -13,6 +13,6 @@ dependencies {
     api project(':testcontainers')
 
     testImplementation 'org.apache.kafka:kafka-clients:3.0.0'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
     testImplementation 'com.google.guava:guava:23.0'
 }

From 670f523cee9bdcc1bdf258a83905071ea0b5a417 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:44 +0000
Subject: [PATCH 1908/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/pulsar

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/pulsar/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle
index cf11a36b411..69c63cc3033 100644
--- a/modules/pulsar/build.gradle
+++ b/modules/pulsar/build.gradle
@@ -4,6 +4,6 @@ dependencies {
     api project(':testcontainers')
 
     testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.4'
-    testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.22.0'
+    testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.23.1'
     testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.4'
 }

From 43feb287518abb1d777cb10a46d839f03fd9e10b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:45 +0000
Subject: [PATCH 1909/4969] Bump tomcat-jdbc from 10.0.20 to 10.0.21 in
 /modules/jdbc

Bumps tomcat-jdbc from 10.0.20 to 10.0.21.

---
updated-dependencies:
- dependency-name: org.apache.tomcat:tomcat-jdbc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/jdbc/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle
index 84b927ac4a9..3c9865b5246 100644
--- a/modules/jdbc/build.gradle
+++ b/modules/jdbc/build.gradle
@@ -7,7 +7,7 @@ dependencies {
     compileOnly 'org.jetbrains:annotations:23.0.0'
     testImplementation 'commons-dbutils:commons-dbutils:1.7'
     testImplementation 'org.vibur:vibur-dbcp:25.0'
-    testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.20'
+    testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.21'
     testImplementation 'com.zaxxer:HikariCP-java6:2.3.13'
     testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4'
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'

From e267d78335346416aaf065d04b9c5a39757d78e9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:46 +0000
Subject: [PATCH 1910/4969] Bump aws-java-sdk-s3 from 1.12.191 to 1.12.231 in
 /modules/localstack

Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.191 to 1.12.231.
- [Release notes](https://github.com/aws/aws-sdk-java/releases)
- [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.191...1.12.231)

---
updated-dependencies:
- dependency-name: com.amazonaws:aws-java-sdk-s3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/localstack/build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle
index 496b4e23983..8a12cd75327 100644
--- a/modules/localstack/build.gradle
+++ b/modules/localstack/build.gradle
@@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack"
 dependencies {
     api project(':testcontainers')
 
-    compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.191'
-    testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.169'
+    compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.231'
+    testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231'
     testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.210'
     testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.169'
     testImplementation 'software.amazon.awssdk:s3:2.17.181'

From a67d40a1e1fa8447b021ad6e98350fe4edc898b1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:47 +0000
Subject: [PATCH 1911/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite

Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.210 to 1.12.232.
- [Release notes](https://github.com/aws/aws-sdk-java/releases)
- [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.210...1.12.232)

---
updated-dependencies:
- dependency-name: com.amazonaws:aws-java-sdk-dynamodb
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/dynalite/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle
index 6dabdec119b..09cb51e10a4 100644
--- a/modules/dynalite/build.gradle
+++ b/modules/dynalite/build.gradle
@@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite"
 dependencies {
     api project(':testcontainers')
 
-    compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.210'
+    compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.232'
     testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.210'
 
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'

From 7fb15fbac3912e999aedd63431461142c61a0fb1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:48 +0000
Subject: [PATCH 1912/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/junit-jupiter

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/junit-jupiter/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle
index 6685eddf15a..7efd4fe3afa 100644
--- a/modules/junit-jupiter/build.gradle
+++ b/modules/junit-jupiter/build.gradle
@@ -12,7 +12,7 @@ dependencies {
     testImplementation ('org.mockito:mockito-core:4.4.0') {
         exclude(module: 'hamcrest-core')
     }
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
     testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
 
     testRuntimeOnly 'org.postgresql:postgresql:42.3.4'

From 6f33590747b80490d0f7c873fa366e559e9e9ffc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:49 +0000
Subject: [PATCH 1913/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/vault

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/vault/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle
index 80b416ce235..f6e94f2139d 100644
--- a/modules/vault/build.gradle
+++ b/modules/vault/build.gradle
@@ -5,6 +5,6 @@ dependencies {
 
     testImplementation 'com.bettercloud:vault-java-driver:5.1.0'
     testImplementation 'io.rest-assured:rest-assured:5.0.1'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
 
 }

From 0f2f843d5b205a8dbda4be9ca5840722bf9777f8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:49 +0000
Subject: [PATCH 1914/4969] Bump common-custom-user-data-gradle-plugin in
 /examples

Bumps common-custom-user-data-gradle-plugin from 1.6.2 to 1.7.

---
updated-dependencies:
- dependency-name: com.gradle:common-custom-user-data-gradle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 examples/settings.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/settings.gradle b/examples/settings.gradle
index ceb39498854..2046a7d282e 100644
--- a/examples/settings.gradle
+++ b/examples/settings.gradle
@@ -7,7 +7,7 @@ buildscript {
     dependencies {
         classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0"
         classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10"
-        classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.2"
+        classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7"
     }
 }
 

From 761e70a06761036246647dd0a1313d7f2ff9d1bc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:52 +0000
Subject: [PATCH 1915/4969] Bump assertj-core from 3.22.0 to 3.23.1 in /core

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 core/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/build.gradle b/core/build.gradle
index efb08991f8d..3b870a59e5c 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -102,7 +102,7 @@ dependencies {
     testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar')
 
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
     testImplementation project(':test-support')
 
     jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}"

From b8466947c2451bebc2760397293e57334f101697 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:52 +0000
Subject: [PATCH 1916/4969] Bump postgresql from 42.3.1 to 42.3.6 in
 /modules/spock

Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.1 to 42.3.6.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.1...REL42.3.6)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/spock/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle
index 396c0071042..e609733d398 100644
--- a/modules/spock/build.gradle
+++ b/modules/spock/build.gradle
@@ -15,7 +15,7 @@ dependencies {
     testImplementation 'com.zaxxer:HikariCP:4.0.3'
     testImplementation 'org.apache.httpcomponents:httpclient:4.5.13'
 
-    testRuntimeOnly 'org.postgresql:postgresql:42.3.1'
+    testRuntimeOnly 'org.postgresql:postgresql:42.3.6'
     testRuntimeOnly 'mysql:mysql-connector-java:8.0.29'
 
     testCompileClasspath 'org.jetbrains:annotations:23.0.0'

From a76a9ca56f20070a0bf96b73dc155eec6e07c817 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:53 +0000
Subject: [PATCH 1917/4969] Bump jedis from 4.2.2 to 4.2.3 in /core

Bumps [jedis](https://github.com/redis/jedis) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/redis/jedis/releases)
- [Commits](https://github.com/redis/jedis/compare/v4.2.2...v4.2.3)

---
updated-dependencies:
- dependency-name: redis.clients:jedis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 core/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/build.gradle b/core/build.gradle
index efb08991f8d..833831f0aed 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -91,7 +91,7 @@ dependencies {
     shaded 'org.zeroturnaround:zt-exec:1.12'
 
     testImplementation 'org.apache.httpcomponents:httpclient:4.5.9'
-    testImplementation 'redis.clients:jedis:4.2.2'
+    testImplementation 'redis.clients:jedis:4.2.3'
     testImplementation 'com.rabbitmq:amqp-client:5.14.2'
     testImplementation 'org.mongodb:mongo-java-driver:3.12.10'
 

From e97b0c2073f1ec59ccf89890442ed50047fbf7f2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:56 +0000
Subject: [PATCH 1918/4969] Bump postgresql from 42.3.4 to 42.3.6 in
 /modules/junit-jupiter

Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.4 to 42.3.6.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.4...REL42.3.6)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/junit-jupiter/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle
index 6685eddf15a..0b1a21a3970 100644
--- a/modules/junit-jupiter/build.gradle
+++ b/modules/junit-jupiter/build.gradle
@@ -15,7 +15,7 @@ dependencies {
     testImplementation 'org.assertj:assertj-core:3.22.0'
     testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
 
-    testRuntimeOnly 'org.postgresql:postgresql:42.3.4'
+    testRuntimeOnly 'org.postgresql:postgresql:42.3.6'
     testRuntimeOnly 'mysql:mysql-connector-java:8.0.27'
     testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
 }

From 553405f0c0e28ade15637578922f0bd6f7936ed0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:57 +0000
Subject: [PATCH 1919/4969] Bump transport from 7.17.3 to 7.17.4 in
 /modules/elasticsearch

Bumps [transport](https://github.com/elastic/elasticsearch) from 7.17.3 to 7.17.4.
- [Release notes](https://github.com/elastic/elasticsearch/releases)
- [Changelog](https://github.com/elastic/elasticsearch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/elastic/elasticsearch/compare/v7.17.3...v7.17.4)

---
updated-dependencies:
- dependency-name: org.elasticsearch.client:transport
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/elasticsearch/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle
index 3d8f7bff12d..4bff8106f0b 100644
--- a/modules/elasticsearch/build.gradle
+++ b/modules/elasticsearch/build.gradle
@@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch"
 dependencies {
     api project(':testcontainers')
     testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2"
-    testImplementation "org.elasticsearch.client:transport:7.17.3"
+    testImplementation "org.elasticsearch.client:transport:7.17.4"
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'
 }

From dd539ed0409658cd278ee26f4c795e472bbd0c67 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:57 +0000
Subject: [PATCH 1920/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/database-commons

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/database-commons/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/database-commons/build.gradle b/modules/database-commons/build.gradle
index 7a201d772fb..33a6d1e9826 100644
--- a/modules/database-commons/build.gradle
+++ b/modules/database-commons/build.gradle
@@ -3,5 +3,5 @@ description = "Testcontainers :: Database-Commons"
 dependencies {
     api project(':testcontainers')
 
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
 }

From 4f6fea6c5feaf1c5c90ecbec8b823aa09fec708b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:00:57 +0000
Subject: [PATCH 1921/4969] Bump aws-java-sdk-logs from 1.12.169 to 1.12.232 in
 /modules/localstack

Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.169 to 1.12.232.
- [Release notes](https://github.com/aws/aws-sdk-java/releases)
- [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.169...1.12.232)

---
updated-dependencies:
- dependency-name: com.amazonaws:aws-java-sdk-logs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/localstack/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle
index 496b4e23983..6917199b470 100644
--- a/modules/localstack/build.gradle
+++ b/modules/localstack/build.gradle
@@ -6,7 +6,7 @@ dependencies {
     compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.191'
     testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.169'
     testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.210'
-    testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.169'
+    testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.232'
     testImplementation 'software.amazon.awssdk:s3:2.17.181'
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'
 }

From 62d34bd7899fadbc9c4ba2874d5cdc2e2f0ef7f5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:01:01 +0000
Subject: [PATCH 1922/4969] Bump postgresql from 42.3.3 to 42.3.6 in /examples

Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.3.6.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.3.6)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 examples/linked-container/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle
index c61ce36e473..05c5b241b51 100644
--- a/examples/linked-container/build.gradle
+++ b/examples/linked-container/build.gradle
@@ -9,7 +9,7 @@ dependencies {
     compileOnly 'org.slf4j:slf4j-api:1.7.32'
     implementation 'com.squareup.okhttp3:okhttp:4.9.3'
     implementation 'org.json:json:20211205'
-    testImplementation 'org.postgresql:postgresql:42.3.3'
+    testImplementation 'org.postgresql:postgresql:42.3.6'
     testImplementation 'ch.qos.logback:logback-classic:1.2.11'
     testImplementation 'org.testcontainers:postgresql'
 }

From ce9b09a1fdbc28509d53485371089339416ed44c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:01:25 +0000
Subject: [PATCH 1923/4969] Bump peter-evans/create-pull-request from 4.0.2 to
 4.0.3

Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.0.2 to 4.0.3.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/bd72e1b7922d417764d27d30768117ad7da78a0e...f094b77505fb89581e68a1163fbd2fffece39da1)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 .github/workflows/update-docs-version.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml
index b5d672c092d..b4d4d250346 100644
--- a/.github/workflows/update-docs-version.yml
+++ b/.github/workflows/update-docs-version.yml
@@ -17,7 +17,7 @@ jobs:
           sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml
           git diff
       - name: Create Pull Request
-        uses: peter-evans/create-pull-request@bd72e1b7922d417764d27d30768117ad7da78a0e # v3.10.1
+        uses: peter-evans/create-pull-request@f094b77505fb89581e68a1163fbd2fffece39da1 # v3.10.1
         with:
           title: Update docs version to ${GITHUB_REF##*/}
           body: |

From 76381504e6c5cf4083ec1e42a1ffd4f241820793 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:01:30 +0000
Subject: [PATCH 1924/4969] Bump actions/cache from 3.0.2 to 3.0.3

Bumps [actions/cache](https://github.com/actions/cache) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3.0.2...v3.0.3)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 .github/workflows/ci-examples.yml | 4 ++--
 .github/workflows/ci.yml          | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml
index 90b493df481..9a7b314c67f 100644
--- a/.github/workflows/ci-examples.yml
+++ b/.github/workflows/ci-examples.yml
@@ -22,7 +22,7 @@ jobs:
           java-version: '8.0.302'
           distribution: temurin
       - name: Cache Gradle Home files
-        uses: actions/cache@v3.0.2
+        uses: actions/cache@v3.0.3
         continue-on-error: true
         with:
           path: ~/.gradle/caches
@@ -50,7 +50,7 @@ jobs:
           java-version: '8.0.302'
           distribution: temurin
       - name: Cache Gradle Home files
-        uses: actions/cache@v3.0.2
+        uses: actions/cache@v3.0.3
         continue-on-error: true
         with:
           path: ~/.gradle/caches
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0c0e5eaf601..56bb4e0799d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,7 +30,7 @@ jobs:
           java-version: '8.0.302'
           distribution: temurin
       - name: Cache Gradle Home files
-        uses: actions/cache@v3.0.2
+        uses: actions/cache@v3.0.3
         with:
           path: ~/.gradle/caches
           key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }}
@@ -56,7 +56,7 @@ jobs:
           java-version: '8.0.302'
           distribution: temurin
       - name: Cache Gradle Home files
-        uses: actions/cache@v3.0.2
+        uses: actions/cache@v3.0.3
         continue-on-error: true
         with:
           path: ~/.gradle/caches

From c3e8979012144fa559629f11ad8bad9d742839d6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:01:35 +0000
Subject: [PATCH 1925/4969] Bump release-drafter/release-drafter from 5.19.0 to
 5.20.0

Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.19.0 to 5.20.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/e9ee02fbac03d922bac6212003695e8358dd88b0...ac463ffd9cc4c6ad5682af93dc3e3591c4657ee3)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 .github/workflows/release-drafter.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
index 839fb43df4d..132b5ffd0a5 100644
--- a/.github/workflows/release-drafter.yml
+++ b/.github/workflows/release-drafter.yml
@@ -12,6 +12,6 @@ jobs:
     if: github.repository == 'testcontainers/testcontainers-java'
     runs-on: ubuntu-latest
     steps:
-      - uses: release-drafter/release-drafter@e9ee02fbac03d922bac6212003695e8358dd88b0 # v5.19.0
+      - uses: release-drafter/release-drafter@ac463ffd9cc4c6ad5682af93dc3e3591c4657ee3 # v5.19.0
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

From b8c4ddf2a2c2eb1b56b6b566db9e29ff3e88991b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:19 +0000
Subject: [PATCH 1926/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/orientdb

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/orientdb/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/orientdb/build.gradle b/modules/orientdb/build.gradle
index 820e96e114f..05bdb380c28 100644
--- a/modules/orientdb/build.gradle
+++ b/modules/orientdb/build.gradle
@@ -5,7 +5,7 @@ dependencies {
 
     api "com.orientechnologies:orientdb-client:3.0.24"
 
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
     testImplementation 'org.apache.tinkerpop:gremlin-driver:3.3.4'
     testImplementation "com.orientechnologies:orientdb-gremlin:3.0.18"
 }

From 7e93a7e78e710589e14ef8da91a1b5d392274471 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:22 +0000
Subject: [PATCH 1927/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/rabbitmq

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/rabbitmq/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle
index 967b9eb4ed9..6c2953909bb 100644
--- a/modules/rabbitmq/build.gradle
+++ b/modules/rabbitmq/build.gradle
@@ -3,6 +3,6 @@ description = "TestContainers :: RabbitMQ"
 dependencies {
     api project(":testcontainers")
     testImplementation 'com.rabbitmq:amqp-client:5.14.2'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
     compileOnly 'org.jetbrains:annotations:23.0.0'
 }

From 46d75a20b081044fc341e7db3b4278d36450a67a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:25 +0000
Subject: [PATCH 1928/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/k3s

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/k3s/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle
index 0ab368d60c2..1c7e6138b7f 100644
--- a/modules/k3s/build.gradle
+++ b/modules/k3s/build.gradle
@@ -10,5 +10,5 @@ dependencies {
 
     testImplementation 'io.fabric8:kubernetes-client:5.12.2'
     testImplementation 'io.kubernetes:client-java:15.0.0'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
 }

From 0c7730eb1d1e4e034a872b9bb52dced44e65ece7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:25 +0000
Subject: [PATCH 1929/4969] Bump trino-jdbc from 379 to 382 in /modules/trino

Bumps trino-jdbc from 379 to 382.

---
updated-dependencies:
- dependency-name: io.trino:trino-jdbc
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] 
---
 modules/trino/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle
index d0b56af633f..8305e8e0629 100644
--- a/modules/trino/build.gradle
+++ b/modules/trino/build.gradle
@@ -4,6 +4,6 @@ dependencies {
     api project(':jdbc')
 
     testImplementation project(':jdbc-test')
-    testImplementation 'io.trino:trino-jdbc:379'
+    testImplementation 'io.trino:trino-jdbc:382'
     compileOnly 'org.jetbrains:annotations:23.0.0'
 }

From c0b0612ace8545533258f2295358fb750d65d6af Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:26 +0000
Subject: [PATCH 1930/4969] Bump google-cloud-pubsub from 1.116.4 to 1.119.0 in
 /modules/gcloud

Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.116.4 to 1.119.0.
- [Release notes](https://github.com/googleapis/java-pubsub/releases)
- [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/java-pubsub/compare/v1.116.4...v1.119.0)

---
updated-dependencies:
- dependency-name: com.google.cloud:google-cloud-pubsub
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/gcloud/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle
index 031e68a7f76..c493020c61f 100644
--- a/modules/gcloud/build.gradle
+++ b/modules/gcloud/build.gradle
@@ -5,7 +5,7 @@ dependencies {
 
     testImplementation 'com.google.cloud:google-cloud-datastore:2.4.0'
     testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21'
-    testImplementation 'com.google.cloud:google-cloud-pubsub:1.116.4'
+    testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0'
     testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0'
     testImplementation 'com.google.cloud:google-cloud-bigtable:2.6.2'
     testImplementation 'org.assertj:assertj-core:3.22.0'

From c6beb9219642e0b054802e9cc221462dd3218751 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:27 +0000
Subject: [PATCH 1931/4969] Bump postgresql from 42.3.4 to 42.3.6 in
 /modules/cockroachdb

Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.4 to 42.3.6.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.4...REL42.3.6)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/cockroachdb/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle
index ad1007a4744..490b2d7fb11 100644
--- a/modules/cockroachdb/build.gradle
+++ b/modules/cockroachdb/build.gradle
@@ -4,5 +4,5 @@ dependencies {
     api project(':jdbc')
 
     testImplementation project(':jdbc-test')
-    testImplementation 'org.postgresql:postgresql:42.3.4'
+    testImplementation 'org.postgresql:postgresql:42.3.6'
 }

From 2e6ac22bcbf163329d171c5b4f57b3ecbb2e2ed8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:31 +0000
Subject: [PATCH 1932/4969] Bump azure-cosmos from 4.29.1 to 4.30.0 in
 /modules/azure

Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.29.1 to 4.30.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-java/releases)
- [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.29.1...azure-cosmos_4.30.0)

---
updated-dependencies:
- dependency-name: com.azure:azure-cosmos
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/azure/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle
index 8ab7612c18b..f26028b8ede 100644
--- a/modules/azure/build.gradle
+++ b/modules/azure/build.gradle
@@ -6,5 +6,5 @@ dependencies {
     shaded 'com.squareup.okhttp3:okhttp:3.14.9'
 
     testImplementation 'org.assertj:assertj-core:3.22.0'
-    testImplementation 'com.azure:azure-cosmos:4.29.1'
+    testImplementation 'com.azure:azure-cosmos:4.30.0'
 }

From 110fe8e4f9e813949779a3d8473655f216b44375 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:44 +0000
Subject: [PATCH 1933/4969] Bump google-cloud-bigtable from 2.6.2 to 2.8.0 in
 /modules/gcloud

Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.6.2 to 2.8.0.
- [Release notes](https://github.com/googleapis/java-bigtable/releases)
- [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/java-bigtable/compare/v2.6.2...v2.8.0)

---
updated-dependencies:
- dependency-name: com.google.cloud:google-cloud-bigtable
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/gcloud/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle
index 031e68a7f76..cdb09edd51f 100644
--- a/modules/gcloud/build.gradle
+++ b/modules/gcloud/build.gradle
@@ -7,6 +7,6 @@ dependencies {
     testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21'
     testImplementation 'com.google.cloud:google-cloud-pubsub:1.116.4'
     testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0'
-    testImplementation 'com.google.cloud:google-cloud-bigtable:2.6.2'
+    testImplementation 'com.google.cloud:google-cloud-bigtable:2.8.0'
     testImplementation 'org.assertj:assertj-core:3.22.0'
 }

From 4a66388f7f10e587280b135673c87958758db9fb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:05:45 +0000
Subject: [PATCH 1934/4969] Bump reactor-core from 3.4.17 to 3.4.18 in
 /modules/r2dbc

Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.17 to 3.4.18.
- [Release notes](https://github.com/reactor/reactor-core/releases)
- [Commits](https://github.com/reactor/reactor-core/compare/v3.4.17...v3.4.18)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/r2dbc/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle
index 2a4e3958af8..11e22e2bc9f 100644
--- a/modules/r2dbc/build.gradle
+++ b/modules/r2dbc/build.gradle
@@ -15,6 +15,6 @@ dependencies {
     testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE'
     testImplementation project(':postgresql')
 
-    testFixturesImplementation 'io.projectreactor:reactor-core:3.4.17'
+    testFixturesImplementation 'io.projectreactor:reactor-core:3.4.18'
     testFixturesImplementation 'org.assertj:assertj-core:3.14.0'
 }

From eeba70a2266b7f20ce94a6566fffdb99f3950ee3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:06:07 +0000
Subject: [PATCH 1935/4969] Bump hivemq-extension-sdk from 4.8.0 to 4.8.1 in
 /modules/hivemq

Bumps [hivemq-extension-sdk](https://github.com/hivemq/hivemq-extension-sdk) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/hivemq/hivemq-extension-sdk/releases)
- [Commits](https://github.com/hivemq/hivemq-extension-sdk/compare/4.8.0...4.8.1)

---
updated-dependencies:
- dependency-name: com.hivemq:hivemq-extension-sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/hivemq/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle
index bfdfecb1761..972e07d1f8a 100644
--- a/modules/hivemq/build.gradle
+++ b/modules/hivemq/build.gradle
@@ -13,7 +13,7 @@ dependencies {
 
     testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
     testImplementation(project(":junit-jupiter"))
-    testImplementation("com.hivemq:hivemq-extension-sdk:4.8.0")
+    testImplementation("com.hivemq:hivemq-extension-sdk:4.8.1")
     testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0")
     testImplementation("org.apache.httpcomponents:httpclient:4.5.13")
     testImplementation("ch.qos.logback:logback-classic:1.2.10")

From 1bbdbb1deccfe70ef1c64de566963c7334ba8bc9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Jun 2022 22:07:49 +0000
Subject: [PATCH 1936/4969] Bump common-custom-user-data-gradle-plugin from
 1.6.5 to 1.7

Bumps common-custom-user-data-gradle-plugin from 1.6.5 to 1.7.

---
updated-dependencies:
- dependency-name: com.gradle:common-custom-user-data-gradle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 settings.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/settings.gradle b/settings.gradle
index 6b80183bc34..cf15e5ec31a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -6,7 +6,7 @@ buildscript {
     }
     dependencies {
         classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10"
-        classpath "com.gradle:common-custom-user-data-gradle-plugin:1.6.5"
+        classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7"
     }
 }
 

From 69856364f1a06803c12719b45e6e693e2258404a Mon Sep 17 00:00:00 2001
From: adrianpozueco 
Date: Thu, 2 Jun 2022 20:35:29 +0200
Subject: [PATCH 1937/4969] [Localstack] Get region from env variables or
 default (#3556)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Pozueco Adrian 
Co-authored-by: Eddú Meléndez Gonzales 
---
 .../localstack/LocalStackContainer.java       |  4 ++-
 .../localstack/LocalstackContainerTest.java   | 26 +++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java
index 8bd6f14d3fd..d37c80d06fa 100644
--- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java
+++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java
@@ -45,6 +45,8 @@ public class LocalStackContainer extends GenericContainer {
 
     private static final String DEFAULT_TAG = "0.11.2";
 
+    private static final String DEFAULT_REGION = "us-east-1";
+
     @Deprecated
     public static final String VERSION = DEFAULT_TAG;
 
@@ -311,7 +313,7 @@ public String getSecretKey() {
      * @return a default region
      */
     public String getRegion() {
-        return "us-east-1";
+        return this.getEnvMap().getOrDefault("DEFAULT_REGION", DEFAULT_REGION);
     }
 
     public interface EnabledService {
diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java
index cf4e1a813a4..3b85c69ca34 100644
--- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java
+++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java
@@ -1,5 +1,6 @@
 package org.testcontainers.containers.localstack;
 
+import com.amazonaws.client.builder.AwsClientBuilder;
 import com.amazonaws.services.kms.AWSKMS;
 import com.amazonaws.services.kms.AWSKMSClientBuilder;
 import com.amazonaws.services.kms.model.CreateKeyRequest;
@@ -286,4 +287,29 @@ private String runAwsCliAgainstDockerNetworkContainer(String command) throws Exc
             return logs;
         }
     }
+
+    public static class WithRegion {
+
+        // with_region {
+        private static String region = "eu-west-1";
+
+        @ClassRule
+        public static LocalStackContainer localstack = new LocalStackContainer(LocalstackTestImages.LOCALSTACK_IMAGE)
+            .withEnv("DEFAULT_REGION", region)
+            .withServices(Service.S3);
+
+        // }
+
+        @Test
+        public void s3EndpointHasProperRegion() {
+            final AwsClientBuilder.EndpointConfiguration endpointConfiguration = localstack.getEndpointConfiguration(
+                Service.S3
+            );
+            assertEquals(
+                "The endpoint configuration has right region",
+                region,
+                endpointConfiguration.getSigningRegion()
+            );
+        }
+    }
 }

From 74e87885ecd4737c392eb4c67ec41e7294977089 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?=
 
Date: Thu, 2 Jun 2022 14:05:48 -0500
Subject: [PATCH 1938/4969] Cleanup japicmp baselines (#5463)

Co-authored-by: Sergei Egorov 
---
 core/build.gradle          | 4 ----
 gradle/japicmp.gradle      | 2 +-
 modules/kafka/build.gradle | 9 ---------
 3 files changed, 1 insertion(+), 14 deletions(-)

diff --git a/core/build.gradle b/core/build.gradle
index efb08991f8d..7aac72e50ed 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -60,10 +60,6 @@ configurations.all {
 }
 
 dependencies {
-    baseline 'org.testcontainers:testcontainers:1.17.1', {
-        exclude group: "*", module: "*"
-    }
-
     api 'junit:junit:4.13.2'
     api 'org.slf4j:slf4j-api:1.7.35'
     compileOnly 'org.jetbrains:annotations:23.0.0'
diff --git a/gradle/japicmp.gradle b/gradle/japicmp.gradle
index e74cdccd3af..fe3f8881b1c 100644
--- a/gradle/japicmp.gradle
+++ b/gradle/japicmp.gradle
@@ -3,7 +3,7 @@ configurations {
 }
 
 dependencies {
-    baseline "org.testcontainers:${project.name}:1.16.0", {
+    baseline "org.testcontainers:${project.name}:1.17.2", {
         exclude group: "*", module: "*"
     }
 }
diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle
index b9157d9d539..6d1cf82e5c8 100644
--- a/modules/kafka/build.gradle
+++ b/modules/kafka/build.gradle
@@ -1,14 +1,5 @@
 description = "Testcontainers :: Kafka"
 
-tasks.japicmp {
-    // TODO clean after 1.17.0 is released
-    methodExcludes = [
-        // Overrides removed, not a breaking change per se
-        "org.testcontainers.containers.KafkaContainer#containerIsStarting(com.github.dockerjava.api.command.InspectContainerResponse,boolean)",
-        "org.testcontainers.containers.KafkaContainer#doStart()",
-    ]
-}
-
 dependencies {
     api project(':testcontainers')
 

From 7ea69bdd4e911c98003487b5ee444b47aa52432f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:47:36 +0000
Subject: [PATCH 1939/4969] Bump neo4j-java-driver from 4.4.5 to 4.4.6 in
 /examples

Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 4.4.5 to 4.4.6.
- [Release notes](https://github.com/neo4j/neo4j-java-driver/releases)
- [Commits](https://github.com/neo4j/neo4j-java-driver/compare/4.4.5...4.4.6)

---
updated-dependencies:
- dependency-name: org.neo4j.driver:neo4j-java-driver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 examples/neo4j-container/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/neo4j-container/build.gradle b/examples/neo4j-container/build.gradle
index 652937d8b33..745d3206953 100644
--- a/examples/neo4j-container/build.gradle
+++ b/examples/neo4j-container/build.gradle
@@ -8,7 +8,7 @@ repositories {
 
 dependencies {
     testImplementation 'org.assertj:assertj-core:3.22.0'
-    testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.5'
+    testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.6'
     testImplementation 'org.testcontainers:neo4j'
     testImplementation 'org.testcontainers:junit-jupiter'
 }

From 3e4d1213715d08886e5abeabf6df4a1b93eff883 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:47:54 +0000
Subject: [PATCH 1940/4969] Bump mongo-java-driver from 3.12.10 to 3.12.11 in
 /core

Bumps [mongo-java-driver](https://github.com/mongodb/mongo-java-driver) from 3.12.10 to 3.12.11.
- [Release notes](https://github.com/mongodb/mongo-java-driver/releases)
- [Commits](https://github.com/mongodb/mongo-java-driver/compare/r3.12.10...r3.12.11)

---
updated-dependencies:
- dependency-name: org.mongodb:mongo-java-driver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 core/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/build.gradle b/core/build.gradle
index f6b336e9600..310b4f43ef0 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -89,7 +89,7 @@ dependencies {
     testImplementation 'org.apache.httpcomponents:httpclient:4.5.9'
     testImplementation 'redis.clients:jedis:4.2.3'
     testImplementation 'com.rabbitmq:amqp-client:5.14.2'
-    testImplementation 'org.mongodb:mongo-java-driver:3.12.10'
+    testImplementation 'org.mongodb:mongo-java-driver:3.12.11'
 
     testImplementation ('org.mockito:mockito-core:4.6.0') {
         exclude(module: 'hamcrest-core')

From deef741188cc4d659dfae0849cb2e0ea948b4c24 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:47:55 +0000
Subject: [PATCH 1941/4969] Bump mysql-connector-java in /modules/junit-jupiter

Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.27 to 8.0.29.
- [Release notes](https://github.com/mysql/mysql-connector-j/releases)
- [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES)
- [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.27...8.0.29)

---
updated-dependencies:
- dependency-name: mysql:mysql-connector-java
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/junit-jupiter/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle
index 5c42d57fcbb..386fc023902 100644
--- a/modules/junit-jupiter/build.gradle
+++ b/modules/junit-jupiter/build.gradle
@@ -16,7 +16,7 @@ dependencies {
     testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
 
     testRuntimeOnly 'org.postgresql:postgresql:42.3.6'
-    testRuntimeOnly 'mysql:mysql-connector-java:8.0.27'
+    testRuntimeOnly 'mysql:mysql-connector-java:8.0.29'
     testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
 }
 

From c22e1e7dbe84614b79cea59d970c882b97a4abe9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:00 +0000
Subject: [PATCH 1942/4969] Bump json from 20211205 to 20220320 in /examples

Bumps [json](https://github.com/douglascrockford/JSON-java) from 20211205 to 20220320.
- [Release notes](https://github.com/douglascrockford/JSON-java/releases)
- [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md)
- [Commits](https://github.com/douglascrockford/JSON-java/commits)

---
updated-dependencies:
- dependency-name: org.json:json
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] 
---
 examples/linked-container/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle
index 05c5b241b51..a801e4f8588 100644
--- a/examples/linked-container/build.gradle
+++ b/examples/linked-container/build.gradle
@@ -8,7 +8,7 @@ repositories {
 dependencies {
     compileOnly 'org.slf4j:slf4j-api:1.7.32'
     implementation 'com.squareup.okhttp3:okhttp:4.9.3'
-    implementation 'org.json:json:20211205'
+    implementation 'org.json:json:20220320'
     testImplementation 'org.postgresql:postgresql:42.3.6'
     testImplementation 'ch.qos.logback:logback-classic:1.2.11'
     testImplementation 'org.testcontainers:postgresql'

From a8ae7c898c297b81d6d872865a823ef8b02ef106 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:02 +0000
Subject: [PATCH 1943/4969] Bump client-java from 15.0.0 to 15.0.1 in
 /modules/k3s

Bumps [client-java](https://github.com/kubernetes-client/java) from 15.0.0 to 15.0.1.
- [Release notes](https://github.com/kubernetes-client/java/releases)
- [Changelog](https://github.com/kubernetes-client/java/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes-client/java/compare/v15.0.0...v15.0.1)

---
updated-dependencies:
- dependency-name: io.kubernetes:client-java
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/k3s/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle
index 1c7e6138b7f..bf51cbfefa9 100644
--- a/modules/k3s/build.gradle
+++ b/modules/k3s/build.gradle
@@ -9,6 +9,6 @@ dependencies {
     shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8'
 
     testImplementation 'io.fabric8:kubernetes-client:5.12.2'
-    testImplementation 'io.kubernetes:client-java:15.0.0'
+    testImplementation 'io.kubernetes:client-java:15.0.1'
     testImplementation 'org.assertj:assertj-core:3.23.1'
 }

From bbb31506cb890ef75c48461ac107c73615885e99 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:03 +0000
Subject: [PATCH 1944/4969] Bump slf4j-api from 1.7.35 to 1.7.36 in /core

Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.35 to 1.7.36.
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.35...v_1.7.36)

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 core/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/build.gradle b/core/build.gradle
index f6b336e9600..393272aabf3 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -61,7 +61,7 @@ configurations.all {
 
 dependencies {
     api 'junit:junit:4.13.2'
-    api 'org.slf4j:slf4j-api:1.7.35'
+    api 'org.slf4j:slf4j-api:1.7.36'
     compileOnly 'org.jetbrains:annotations:23.0.0'
     testCompileClasspath 'org.jetbrains:annotations:23.0.0'
     api 'org.apache.commons:commons-compress:1.21'

From e7b77ba2a640672e2893920351f374010c241df6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:06 +0000
Subject: [PATCH 1945/4969] Bump logback-classic from 1.2.10 to 1.2.11 in
 /modules/hivemq

Bumps logback-classic from 1.2.10 to 1.2.11.

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/hivemq/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle
index 972e07d1f8a..7add9af67ea 100644
--- a/modules/hivemq/build.gradle
+++ b/modules/hivemq/build.gradle
@@ -16,7 +16,7 @@ dependencies {
     testImplementation("com.hivemq:hivemq-extension-sdk:4.8.1")
     testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0")
     testImplementation("org.apache.httpcomponents:httpclient:4.5.13")
-    testImplementation("ch.qos.logback:logback-classic:1.2.10")
+    testImplementation("ch.qos.logback:logback-classic:1.2.11")
     testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
 }
 

From 0891ac2410871133c57b2931ac89bec97673224f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:09 +0000
Subject: [PATCH 1946/4969] Bump kafka-clients from 3.0.0 to 3.2.0 in
 /modules/kafka

Bumps kafka-clients from 3.0.0 to 3.2.0.

---
updated-dependencies:
- dependency-name: org.apache.kafka:kafka-clients
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/kafka/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle
index cc081326932..79264b8207f 100644
--- a/modules/kafka/build.gradle
+++ b/modules/kafka/build.gradle
@@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka"
 dependencies {
     api project(':testcontainers')
 
-    testImplementation 'org.apache.kafka:kafka-clients:3.0.0'
+    testImplementation 'org.apache.kafka:kafka-clients:3.2.0'
     testImplementation 'org.assertj:assertj-core:3.23.1'
     testImplementation 'com.google.guava:guava:23.0'
 }

From 231a01b52e7e97409f0ea2fdfa94e92c6725e624 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:16 +0000
Subject: [PATCH 1947/4969] Bump elasticsearch-rest-client in
 /modules/elasticsearch

Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 7.16.2 to 8.2.2.
- [Release notes](https://github.com/elastic/elasticsearch/releases)
- [Changelog](https://github.com/elastic/elasticsearch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/elastic/elasticsearch/compare/v7.16.2...v8.2.2)

---
updated-dependencies:
- dependency-name: org.elasticsearch.client:elasticsearch-rest-client
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] 
---
 modules/elasticsearch/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle
index 4bff8106f0b..6d2b5b8a667 100644
--- a/modules/elasticsearch/build.gradle
+++ b/modules/elasticsearch/build.gradle
@@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch"
 
 dependencies {
     api project(':testcontainers')
-    testImplementation "org.elasticsearch.client:elasticsearch-rest-client:7.16.2"
+    testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.2.2"
     testImplementation "org.elasticsearch.client:transport:7.17.4"
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'
 }

From 0cab47b7b3fa3b8fb41b619a1ea4ea8c2c771bfe Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:18 +0000
Subject: [PATCH 1948/4969] Bump jedis from 4.2.2 to 4.2.3 in
 /modules/junit-jupiter

Bumps [jedis](https://github.com/redis/jedis) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/redis/jedis/releases)
- [Commits](https://github.com/redis/jedis/compare/v4.2.2...v4.2.3)

---
updated-dependencies:
- dependency-name: redis.clients:jedis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/junit-jupiter/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle
index 5c42d57fcbb..371eb6ea4a8 100644
--- a/modules/junit-jupiter/build.gradle
+++ b/modules/junit-jupiter/build.gradle
@@ -7,7 +7,7 @@ dependencies {
     testImplementation project(':mysql')
     testImplementation project(':postgresql')
     testImplementation 'com.zaxxer:HikariCP:4.0.3'
-    testImplementation 'redis.clients:jedis:4.2.2'
+    testImplementation 'redis.clients:jedis:4.2.3'
     testImplementation 'org.apache.httpcomponents:httpclient:4.5.13'
     testImplementation ('org.mockito:mockito-core:4.4.0') {
         exclude(module: 'hamcrest-core')

From 74dd5f49055fbb5160426548ff6784336491caa7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:23 +0000
Subject: [PATCH 1949/4969] Bump s3 from 2.17.181 to 2.17.204 in
 /modules/localstack

Bumps s3 from 2.17.181 to 2.17.204.

---
updated-dependencies:
- dependency-name: software.amazon.awssdk:s3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/localstack/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle
index f512b3d5fab..0b8aa654dd5 100644
--- a/modules/localstack/build.gradle
+++ b/modules/localstack/build.gradle
@@ -7,6 +7,6 @@ dependencies {
     testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231'
     testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.210'
     testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.232'
-    testImplementation 'software.amazon.awssdk:s3:2.17.181'
+    testImplementation 'software.amazon.awssdk:s3:2.17.204'
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'
 }

From 9ae45502f706067a7cb1a8b637c6769cf6235adc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:23 +0000
Subject: [PATCH 1950/4969] Bump com.gradle.enterprise.gradle.plugin from 3.10
 to 3.10.1

Bumps com.gradle.enterprise.gradle.plugin from 3.10 to 3.10.1.

---
updated-dependencies:
- dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 settings.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/settings.gradle b/settings.gradle
index cf15e5ec31a..16b3fcdf98a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -5,7 +5,7 @@ buildscript {
         }
     }
     dependencies {
-        classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10"
+        classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.1"
         classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7"
     }
 }

From 97d436d90b463e5f6182b63e945ec2452f52ea03 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:27 +0000
Subject: [PATCH 1951/4969] Bump jedis from 4.2.2 to 4.2.3 in /examples

Bumps [jedis](https://github.com/redis/jedis) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/redis/jedis/releases)
- [Commits](https://github.com/redis/jedis/compare/v4.2.2...v4.2.3)

---
updated-dependencies:
- dependency-name: redis.clients:jedis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 examples/redis-backed-cache-testng/build.gradle | 2 +-
 examples/redis-backed-cache/build.gradle        | 2 +-
 examples/singleton-container/build.gradle       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle
index 4faead13f3a..ba883520719 100644
--- a/examples/redis-backed-cache-testng/build.gradle
+++ b/examples/redis-backed-cache-testng/build.gradle
@@ -8,7 +8,7 @@ repositories {
 
 dependencies {
     compileOnly 'org.slf4j:slf4j-api:1.7.32'
-    implementation 'redis.clients:jedis:4.2.2'
+    implementation 'redis.clients:jedis:4.2.3'
     implementation 'com.google.code.gson:gson:2.8.9'
     implementation 'com.google.guava:guava:23.0'
     testImplementation 'org.testcontainers:testcontainers'
diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle
index b0d64f0524b..87c54f81a8d 100644
--- a/examples/redis-backed-cache/build.gradle
+++ b/examples/redis-backed-cache/build.gradle
@@ -8,7 +8,7 @@ repositories {
 
 dependencies {
     compileOnly 'org.slf4j:slf4j-api:1.7.32'
-    implementation 'redis.clients:jedis:4.2.2'
+    implementation 'redis.clients:jedis:4.2.3'
     implementation 'com.google.code.gson:gson:2.8.9'
     implementation 'com.google.guava:guava:23.0'
     testImplementation 'org.testcontainers:testcontainers'
diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle
index 2b7c3b7dda4..0195c1704f8 100644
--- a/examples/singleton-container/build.gradle
+++ b/examples/singleton-container/build.gradle
@@ -8,7 +8,7 @@ repositories {
 
 dependencies {
 
-    implementation 'redis.clients:jedis:4.2.2'
+    implementation 'redis.clients:jedis:4.2.3'
     implementation 'com.google.code.gson:gson:2.8.9'
     implementation 'com.google.guava:guava:23.0'
     compileOnly 'org.slf4j:slf4j-api:1.7.32'

From f4281805934055ac969c6b9aedca4fd5620362f3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:28 +0000
Subject: [PATCH 1952/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/r2dbc

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/r2dbc/build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle
index 11e22e2bc9f..51199c9a53c 100644
--- a/modules/r2dbc/build.gradle
+++ b/modules/r2dbc/build.gradle
@@ -11,10 +11,10 @@ dependencies {
     api project(':testcontainers')
     api 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE'
 
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
     testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE'
     testImplementation project(':postgresql')
 
     testFixturesImplementation 'io.projectreactor:reactor-core:3.4.18'
-    testFixturesImplementation 'org.assertj:assertj-core:3.14.0'
+    testFixturesImplementation 'org.assertj:assertj-core:3.23.1'
 }

From 1fe3c1f17ef7f02bbb032fb3e1bc01ce92198b4c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:29 +0000
Subject: [PATCH 1953/4969] Bump google-cloud-datastore from 2.4.0 to 2.7.0 in
 /modules/gcloud

Bumps [google-cloud-datastore](https://github.com/googleapis/java-datastore) from 2.4.0 to 2.7.0.
- [Release notes](https://github.com/googleapis/java-datastore/releases)
- [Changelog](https://github.com/googleapis/java-datastore/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/java-datastore/compare/v2.4.0...v2.7.0)

---
updated-dependencies:
- dependency-name: com.google.cloud:google-cloud-datastore
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/gcloud/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle
index 32854badc04..cc674a584b2 100644
--- a/modules/gcloud/build.gradle
+++ b/modules/gcloud/build.gradle
@@ -3,7 +3,7 @@ description = "Testcontainers :: GCloud"
 dependencies {
     api project(':testcontainers')
 
-    testImplementation 'com.google.cloud:google-cloud-datastore:2.4.0'
+    testImplementation 'com.google.cloud:google-cloud-datastore:2.7.0'
     testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21'
     testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0'
     testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0'

From 133233647c587993bc5214940240161a159914f8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:36 +0000
Subject: [PATCH 1954/4969] Bump rest-assured from 5.0.1 to 5.1.0 in
 /modules/vault

Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 5.0.1 to 5.1.0.
- [Release notes](https://github.com/rest-assured/rest-assured/releases)
- [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt)
- [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-5.0.1...rest-assured-5.1.0)

---
updated-dependencies:
- dependency-name: io.rest-assured:rest-assured
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/vault/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle
index f6e94f2139d..1ffc366987c 100644
--- a/modules/vault/build.gradle
+++ b/modules/vault/build.gradle
@@ -4,7 +4,7 @@ dependencies {
     api project(':testcontainers')
 
     testImplementation 'com.bettercloud:vault-java-driver:5.1.0'
-    testImplementation 'io.rest-assured:rest-assured:5.0.1'
+    testImplementation 'io.rest-assured:rest-assured:5.1.0'
     testImplementation 'org.assertj:assertj-core:3.23.1'
 
 }

From a8cbbdce72ba627410935824034ba82117a3bf5c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:39 +0000
Subject: [PATCH 1955/4969] Bump aws-java-sdk-sqs from 1.12.210 to 1.12.233 in
 /modules/localstack

Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.210 to 1.12.233.
- [Release notes](https://github.com/aws/aws-sdk-java/releases)
- [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.210...1.12.233)

---
updated-dependencies:
- dependency-name: com.amazonaws:aws-java-sdk-sqs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
---
 modules/localstack/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle
index f512b3d5fab..5fc67214e69 100644
--- a/modules/localstack/build.gradle
+++ b/modules/localstack/build.gradle
@@ -5,7 +5,7 @@ dependencies {
 
     compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.231'
     testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231'
-    testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.210'
+    testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.233'
     testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.232'
     testImplementation 'software.amazon.awssdk:s3:2.17.181'
     testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2'

From 0b15e6ecd3dbbb96bb9d9f4c2ccc12ba1b4dd5eb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:40 +0000
Subject: [PATCH 1956/4969] Bump google-cloud-spanner from 6.20.0 to 6.25.5 in
 /modules/gcloud

Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.20.0 to 6.25.5.
- [Release notes](https://github.com/googleapis/java-spanner/releases)
- [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/java-spanner/compare/v6.20.0...v6.25.5)

---
updated-dependencies:
- dependency-name: com.google.cloud:google-cloud-spanner
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/gcloud/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle
index 32854badc04..29df32c0b33 100644
--- a/modules/gcloud/build.gradle
+++ b/modules/gcloud/build.gradle
@@ -6,7 +6,7 @@ dependencies {
     testImplementation 'com.google.cloud:google-cloud-datastore:2.4.0'
     testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21'
     testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0'
-    testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0'
+    testImplementation 'com.google.cloud:google-cloud-spanner:6.25.5'
     testImplementation 'com.google.cloud:google-cloud-bigtable:2.8.0'
     testImplementation 'org.assertj:assertj-core:3.22.0'
 }

From b544343eeb97ffa2e6ca4c4e4c53e0af4910e9fb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:41 +0000
Subject: [PATCH 1957/4969] Bump assertj-core from 3.22.0 to 3.23.1 in
 /modules/gcloud

Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1.
- [Release notes](https://github.com/assertj/assertj-core/releases)
- [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/gcloud/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle
index 32854badc04..9b3bcd403de 100644
--- a/modules/gcloud/build.gradle
+++ b/modules/gcloud/build.gradle
@@ -8,5 +8,5 @@ dependencies {
     testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0'
     testImplementation 'com.google.cloud:google-cloud-spanner:6.20.0'
     testImplementation 'com.google.cloud:google-cloud-bigtable:2.8.0'
-    testImplementation 'org.assertj:assertj-core:3.22.0'
+    testImplementation 'org.assertj:assertj-core:3.23.1'
 }

From 4ad81aebc92107af531b970cc3db04eda00d27c7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 2 Jun 2022 21:48:56 +0000
Subject: [PATCH 1958/4969] Bump mockito-core from 4.4.0 to 4.6.1 in
 /modules/junit-jupiter

Bumps [mockito-core](https://github.com/mockito/mockito) from 4.4.0 to 4.6.1.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v4.4.0...v4.6.1)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] 
---
 modules/junit-jupiter/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle
index 5c42d57fcbb..27d62be6b6d 100644
--- a/modules/junit-jupiter/build.gradle
+++ b/modules/junit-jupiter/build.gradle
@@ -9,7 +9,7 @@ dependencies {
     testImplementation 'com.zaxxer:HikariCP:4.0.3'
     testImplementation 'redis.clients:jedis:4.2.2'
     testImplementation 'org.apache.httpcomponents:httpclient:4.5.13'
-    testImplementation ('org.mockito:mockito-core:4.4.0') {
+    testImplementation ('org.mockito:mockito-core:4.6.1') {
         exclude(module: 'hamcrest-core')
     }
     testImplementation 'org.assertj:assertj-core:3.23.1'

From 979d74a785daa96fc380a346c64491d1710503ea Mon Sep 17 00:00:00 2001
From: Maxim Bartkov <84171296+MaxBartkov@users.noreply.github.com>
Date: Sat, 11 Jun 2022 00:29:07 +0300
Subject: [PATCH 1959/4969] Added the Bucket4j library to "Who is using
 Testcontainers?" (#5480)

---
 docs/index.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/index.md b/docs/index.md
index b2c11d6d8e8..0ad72bcb400 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -201,6 +201,7 @@ A huge thank you to our sponsors:
 * [Togglz](https://www.togglz.org/) - Feature Flags for the Java platform
 * [Byzer](https://www.byzer.org/home) - Integration tests for Data and AI platforms are based on multiple versions of Byzer, Ray and Apache Spark.
 * [Apache SeaTunnel](https://github.com/apache/incubator-seatunnel) - Integration testing with different datasource.
+* [Bucket4j](https://github.com/bucket4j/bucket4j) - Java rate-limiting library based on the token-bucket algorithm.
 
 ## License
 

From e7cdfa31af08074aa9dbb3f3d21a622144995b9d Mon Sep 17 00:00:00 2001
From: anatoly0karyakin 
Date: Mon, 13 Jun 2022 14:02:09 +0300
Subject: [PATCH 1960/4969] Don't ignore sql test query exception, add it as
 cause exception (#5484)

---
 .../org/testcontainers/containers/JdbcDatabaseContainer.java | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java
index 84d242a29c7..0b80eaac406 100644
--- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java
+++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java
@@ -151,6 +151,7 @@ protected void waitUntilContainerStarted() {
         // Repeatedly try and open a connection to the DB and execute a test query
         long start = System.currentTimeMillis();
 
+        Exception lastConnectionException = null;
         while (System.currentTimeMillis() < start + (1000 * startupTimeoutSeconds)) {
             if (!isRunning()) {
                 Thread.sleep(100L);
@@ -165,6 +166,7 @@ protected void waitUntilContainerStarted() {
                     // we explicitly want this exception to fail fast without retries
                     throw e;
                 } catch (Exception e) {
+                    lastConnectionException = e;
                     // ignore so that we can try again
                     logger().debug("Failure when trying test query", e);
                     Thread.sleep(100L);
@@ -176,7 +178,8 @@ protected void waitUntilContainerStarted() {
             String.format(
                 "Container is started, but cannot be accessed by (JDBC URL: %s), please check container logs",
                 this.getJdbcUrl()
-            )
+            ),
+            lastConnectionException
         );
     }
 

From 7f9293b089bf4a2e27d28f12e91ef9b22963c473 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?=
 
Date: Mon, 13 Jun 2022 11:32:19 -0500
Subject: [PATCH 1961/4969] [LocalStack] Deprecate methods using aws sdk v1
 (#5489)

Currently, `LocalStackContainer` depends on aws sdk v1. We have received
feedback about moving to aws sdk v2. However, we think that the
class already provides the enough information to be used such as
`getEndpointOverride()`, `getRegion()`, `getAccessKey()` and `getSecretKey`.
So, we are deprecating `getDefaultCredentialsProvider()` and `getEndpointConfiguration`
which are going to be removed in the feature and `LocalStack` module will
not depend on any aws sdk.
---
 .../containers/localstack/LocalStackContainer.java            | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java
index d37c80d06fa..f3f905b84f6 100644
--- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java
+++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java
@@ -193,7 +193,9 @@ public LocalStackContainer withServices(EnabledService... services) {
      *
      * @param service the service that is to be accessed
      * @return an {@link AwsClientBuilder.EndpointConfiguration}
+     * @deprecated {@link LocalStackContainer} will not depend on aws sdk.
      */
+    @Deprecated
     public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service service) {
         return new AwsClientBuilder.EndpointConfiguration(getEndpointOverride(service).toString(), getRegion());
     }
@@ -257,7 +259,9 @@ private int getServicePort(EnabledService service) {
              .build()
      
* @return an {@link AWSCredentialsProvider} + * @deprecated {@link LocalStackContainer} will not depend on aws sdk. */ + @Deprecated public AWSCredentialsProvider getDefaultCredentialsProvider() { return new AWSStaticCredentialsProvider(new BasicAWSCredentials(getAccessKey(), getSecretKey())); } From 2cd6b560bcb67087b12e172bbde6bf5902f853f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 02:32:59 +0000 Subject: [PATCH 1962/4969] Bump gson from 2.8.9 to 2.9.0 in /examples Bumps [gson](https://github.com/google/gson) from 2.8.9 to 2.9.0. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.8.9...gson-parent-2.9.0) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index bfb89f9cef2..1dc3497ec42 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.24" annotationProcessor "org.projectlombok:lombok:1.18.24" implementation 'biz.paluch.redis:spinach:0.3' - implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.mockito:mockito-all:1.10.19' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index ba883520719..56ba5934bdb 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:4.2.3' - implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.11' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 87c54f81a8d..c563cc658d8 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.32' implementation 'redis.clients:jedis:4.2.3' - implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 0195c1704f8..416f29de095 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation 'redis.clients:jedis:4.2.3' - implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.32' From 2fec86109e9bedb6f18d5627a6e7074b019e02a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 02:33:00 +0000 Subject: [PATCH 1963/4969] Bump slf4j-api from 1.7.32 to 1.7.36 in /examples Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.32 to 1.7.36. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.32...v_1.7.36) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index a801e4f8588..f25127f75eb 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { mavenCentral() } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.32' + compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'org.json:json:20220320' testImplementation 'org.postgresql:postgresql:42.3.6' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index ba883520719..d7e174d55c1 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.32' + compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 87c54f81a8d..11bec04a48b 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.32' + compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 0195c1704f8..61a63f6fab5 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:1.7.32' + compileOnly 'org.slf4j:slf4j-api:1.7.36' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:testcontainers' From a35a4e13eead2a10e13bd9a62264256eb13508c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 02:33:28 +0000 Subject: [PATCH 1964/4969] Bump google-cloud-firestore from 3.0.21 to 3.2.0 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.0.21 to 3.2.0. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.0.21...v3.2.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index f1060b8ec83..cdea13f5fac 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.7.0' - testImplementation 'com.google.cloud:google-cloud-firestore:3.0.21' + testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.25.5' testImplementation 'com.google.cloud:google-cloud-bigtable:2.8.0' From 7831ef2bceb076d584c69ffd29eb5f2f3bb62e39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 02:33:28 +0000 Subject: [PATCH 1965/4969] Bump assertj-core from 3.22.0 to 3.23.1 in /modules/azure Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index f26028b8ede..6656445af09 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:3.14.9' - testImplementation 'org.assertj:assertj-core:3.22.0' + testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.azure:azure-cosmos:4.30.0' } From 731da03265983689c80d9c6faee96c77e910d2bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 02:33:48 +0000 Subject: [PATCH 1966/4969] Bump common-custom-user-data-gradle-plugin in /examples Bumps common-custom-user-data-gradle-plugin from 1.7 to 1.7.2. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 2046a7d282e..b9fb73f86c1 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -7,7 +7,7 @@ buildscript { dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" } } From 4083228e0f72e9155a47b9a651c24ac896dd2a08 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 14 Jun 2022 18:30:46 +0200 Subject: [PATCH 1967/4969] Add section about MySQL root user password to docs (#5497) --- docs/modules/databases/mysql.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/modules/databases/mysql.md b/docs/modules/databases/mysql.md index 26fc62308ef..6e6265e91ba 100644 --- a/docs/modules/databases/mysql.md +++ b/docs/modules/databases/mysql.md @@ -12,6 +12,11 @@ is a directory on the classpath containing .cnf files, the following URL can be Any .cnf files in this classpath directory will be mapped into the database container's /etc/mysql/conf.d directory, and will be able to override server settings when the container starts. +## MySQL `root` user password + +If no custom password is specified, the container will use the default user password `test` for the `root` user as well. +When you specify a custom password for the database user, +this will also act as the password of the MySQL `root` user automatically. ## Adding this module to your project dependencies From d96137a6614f06c5288de6000d43c7dab726b024 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 14 Jun 2022 18:41:02 +0200 Subject: [PATCH 1968/4969] Add MariaDB `root` user password section to docs (#5498) --- docs/modules/databases/mariadb.md | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/docs/modules/databases/mariadb.md b/docs/modules/databases/mariadb.md index 495965bee0a..25367d629bd 100644 --- a/docs/modules/databases/mariadb.md +++ b/docs/modules/databases/mariadb.md @@ -2,22 +2,11 @@ See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. -## Usage example +## MariaDB `root` user password -Running MariaDB as a stand-in for in a test: - -```java -public class SomeTest { - - @Rule - public MariaDBContainer mariaDB = new MariaDBContainer(); - - @Test - public void someTestMethod() { - String url = mariaDB.getJdbcUrl(); - - ... create a connection and run test as normal -``` +If no custom password is specified, the container will use the default user password `test` for the `root` user as well. +When you specify a custom password for the database user, +this will also act as the password of the MariaDB `root` user automatically. ## Adding this module to your project dependencies From b3f1b6676e934e67987fd564ddec701d6e0b6647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 14 Jun 2022 13:11:11 -0500 Subject: [PATCH 1969/4969] Add issue forms (#5490) Introducing issue forms for: bug report, enhacements and features. In case of help or question there is a link to the slack channel. Co-authored-by: Kevin Wittek --- .github/ISSUE_TEMPLATE/bug_report.yaml | 96 +++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ .github/ISSUE_TEMPLATE/enhancement.yaml | 56 +++++++++++++++ .github/ISSUE_TEMPLATE/feature.yaml | 85 ++++++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/enhancement.yaml create mode 100644 .github/ISSUE_TEMPLATE/feature.yaml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 00000000000..80e0b47741d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,96 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["type/bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: dropdown + id: module + attributes: + label: Module + description: Which Testcontainers module are you using? + options: + - Core + - Azure + - Cassandra + - Clickhouse + - Couchbase + - DB2 + - Dynalite + - Elasticsearch + - GCloud + - HiveMQ + - InfluxDB + - K3S + - Kafka + - LocalStack + - MariaDB + - MockServer + - MongoDB + - MSSQLServer + - MySQL + - Neo4j + - NGINX + - Oracle-XE + - OrientDB + - PostgreSQL + - Presto + - Pulsar + - RabbitMQ + - Selenium + - Solr + - ToxiProxy + - Trino + - Vault + validations: + required: true + - type: input + id: tc-version + attributes: + label: Testcontainers version + description: Which Testcontainers version are you using? + placeholder: ex. 1.17.2 + validations: + required: true + - type: dropdown + id: latest-version + attributes: + label: Using the latest Testcontainers version? + description: If you are not using the latest version, can you update your project and try to reproduce the issue? Is it still happening? + options: + - 'Yes' + - 'No' + validations: + required: true + - type: textarea + id: docker-version + attributes: + label: Docker version + description: Please run `docker version` and copy and paste the output into this field. + render: shell + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Provide the context and the expected result. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. The content will be automatically formatted as code, so no need for backticks. + render: shell + - type: textarea + id: additional-information + attributes: + label: Additional Information + description: | + Any links or references to have more context about the issue. + + Tip: You can attach a minimal sample project to reproduce the issue or provide further log files by clicking into this area to focus it and then dragging files in. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..d27b0d086e9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Need help or have a question? + url: https://slack.testcontainers.org/ + about: Visit our slack channel. diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml new file mode 100644 index 00000000000..f06ea99c8ba --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -0,0 +1,56 @@ +name: Enhancement +description: Suggest an enhancement +title: "[Enhancement]: " +labels: ["type/enhancement"] +body: + - type: markdown + attributes: + value: | + Please provide the following information + - type: dropdown + id: module + attributes: + label: Module + description: For which Testcontainers module does the enhancement proposal apply? + options: + - Core + - Azure + - Cassandra + - Clickhouse + - Couchbase + - DB2 + - Dynalite + - Elasticsearch + - GCloud + - HiveMQ + - InfluxDB + - K3S + - Kafka + - LocalStack + - MariaDB + - MockServer + - MongoDB + - MSSQLServer + - MySQL + - Neo4j + - NGINX + - Oracle-XE + - OrientDB + - PostgreSQL + - Presto + - Pulsar + - RabbitMQ + - Selenium + - Solr + - ToxiProxy + - Trino + - Vault + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposal + description: What should be improved? What are the limitations of the current implications that would be solved by the proposal? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml new file mode 100644 index 00000000000..32edb0d25f5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -0,0 +1,85 @@ +name: Feature +description: Suggest a new feature +title: "[Feature]: " +labels: ["type/feature"] +body: + - type: markdown + attributes: + value: | + Please provide the following information + - type: dropdown + id: module + attributes: + label: Module + description: Is this feature related to any of the existing modules? + options: + - Core + - Azure + - Cassandra + - Clickhouse + - Couchbase + - DB2 + - Dynalite + - Elasticsearch + - GCloud + - HiveMQ + - InfluxDB + - K3S + - Kafka + - LocalStack + - MariaDB + - MockServer + - MongoDB + - MSSQLServer + - MySQL + - Neo4j + - NGINX + - Oracle-XE + - OrientDB + - PostgreSQL + - Presto + - Pulsar + - RabbitMQ + - Selenium + - Solr + - ToxiProxy + - Trino + - Vault + - New Module + - type: textarea + id: problem + attributes: + label: Problem + description: Is this feature related to a problem? Please describe it. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Solution + description: What's the proposed solution for this feature? + validations: + required: true + - type: textarea + id: benefit + attributes: + label: Benefit + description: What's the benefit of addng this feature to the project? + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Benefit + description: Are there other alternatives? Please describe them. + validations: + required: true + - type: dropdown + id: contribute + attributes: + label: Would you like to help contributing this feature? + options: + - 'Yes' + - 'No' + validations: + required: true From c769e64d94a1d756245c53a62ab17670fcfff78c Mon Sep 17 00:00:00 2001 From: Hyeonmin Park Date: Thu, 16 Jun 2022 23:54:24 +0900 Subject: [PATCH 1970/4969] Remove free disk space check log in example (#5502) --- docs/features/configuration.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 1761d1a2a71..cccae7a86df 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -30,7 +30,6 @@ Before running any containers Testcontainers will perform a set of startup check ``` ℹ︎ Checking the system... ✔ Docker version should be at least 1.6.0 - ✔ Docker environment should have more than 2GB free disk space ✔ File should be mountable ✔ A port exposed by a docker container should be accessible ``` From d57d7e940a02098b0f75c0599d4d4e8614e9c970 Mon Sep 17 00:00:00 2001 From: Cheng Pan Date: Fri, 17 Jun 2022 07:00:50 +0800 Subject: [PATCH 1971/4969] Docs: Add Spark ClickHouse Connector use case (#5270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 0ad72bcb400..3a99c88a5b1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -202,6 +202,7 @@ A huge thank you to our sponsors: * [Byzer](https://www.byzer.org/home) - Integration tests for Data and AI platforms are based on multiple versions of Byzer, Ray and Apache Spark. * [Apache SeaTunnel](https://github.com/apache/incubator-seatunnel) - Integration testing with different datasource. * [Bucket4j](https://github.com/bucket4j/bucket4j) - Java rate-limiting library based on the token-bucket algorithm. +* [Spark ClickHouse Connector](https://github.com/housepower/spark-clickhouse-connector) - Integration tests for Apache Spark with both single node ClickHouse instance and multi-node ClickHouse cluster. ## License From 5dc5c21b3f4ae29fcf05d7c6ba9b287b65cc2517 Mon Sep 17 00:00:00 2001 From: Cristian Briscaru <39033668+cristianbriscaru@users.noreply.github.com> Date: Fri, 17 Jun 2022 00:23:43 +0100 Subject: [PATCH 1972/4969] adds docs cockroach jdbc example (#5100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- docs/modules/databases/jdbc.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index b2a1588ae22..3c52dd1d8a8 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -47,6 +47,10 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database `jdbc:tc:trino:352://localhost/memory/default` +#### Using CockroachDB + +`jdbc:tc:cockroach:v21.2.3:///databasename` + ### Using a classpath init script Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: From 745bfc337071ffec7289758df0fe136c2c307430 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 20 Jun 2022 21:45:49 +0200 Subject: [PATCH 1973/4969] Add color for links (#5508) The rebranding of the docs removed any special rendering of links, so they became invisible to users. This change adds an explicit color for links (with the color taken from the TC logo). This also implicitly highlights the currently selected page in the side-navigation panel. --- docs/css/extra.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/css/extra.css b/docs/css/extra.css index 4c11e3df748..e97480c5341 100644 --- a/docs/css/extra.css +++ b/docs/css/extra.css @@ -5,6 +5,7 @@ h1, h2, h3, h4, h5, h6 { } [data-md-color-scheme="testcontainers"] { - --md-primary-fg-color: #291A3F; + --md-primary-fg-color: #291A3F; --md-accent-fg-color: #291A3F; + --md-typeset-a-color: #0C94AA; } From 2afe714517640b24a404124dce23fe49bbe910f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Tue, 21 Jun 2022 01:41:15 +0200 Subject: [PATCH 1974/4969] Pulsar: add flag to enable transactions and set configuration (#5479) * Add `withTransactions()` method to enable transactions on Pulsar container * Set default version to latest released (2.10.0) * New docker command that enables the user to easily change configuration parameters * Added new tests to cover new methods * Improved the documentation with simple usage and new methods --- docs/modules/pulsar.md | 46 +++++++ modules/pulsar/build.gradle | 4 +- .../containers/PulsarContainer.java | 57 +++++++-- .../containers/PulsarContainerTest.java | 113 ++++++++++++++++-- 4 files changed, 195 insertions(+), 25 deletions(-) diff --git a/docs/modules/pulsar.md b/docs/modules/pulsar.md index 6d16a248872..f74c315cbdc 100644 --- a/docs/modules/pulsar.md +++ b/docs/modules/pulsar.md @@ -1,5 +1,51 @@ # Apache Pulsar Module +Testcontainers can be used to automatically create [Apache Pulsar](https://pulsar.apache.org) containers without external services. + +It's based on the official Apache Pulsar docker image, it is recommended to read the [official guide](https://pulsar.apache.org/docs/next/getting-started-docker/). + +## Example + +Create a `PulsarContainer` to use it in your tests: + + +[Create a Pulsar container](../../modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java) inside_block:constructorWithVersion + + +Then you can retrieve the broker and the admin url: + + +[Get broker and admin urls](../../modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java) inside_block:coordinates + + +## Options + +### Configuration +If you need to set Pulsar configuration variables you can use the native APIs and set each variable with `PULSAR_PREFIX_` as prefix. + +For example, if you want to enable `brokerDeduplicationEnabled`: + + +[Set configuration variables](../../modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java) inside_block:constructorWithEnv + + +### Pulsar IO + +If you need to test Pulsar IO framework you can enable the Pulsar Functions Worker: + + +[Create a Pulsar container with functions worker](../../modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java) inside_block:constructorWithFunctionsWorker + + +### Pulsar Transactions + +If you need to test Pulsar Transactions you can enable the transactions feature: + + +[Create a Pulsar container with transactions](../../modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java) inside_block:constructorWithTransactions + + + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 69c63cc3033..a1b24efba37 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { api project(':testcontainers') - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.7.4' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.10.0' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.23.1' - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.7.4' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.10.0' } diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 9b14e90d736..069fccaae65 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -2,8 +2,12 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; +import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.utility.DockerImageName; +import java.util.ArrayList; +import java.util.List; + /** * This container wraps Apache Pulsar running in standalone mode */ @@ -15,13 +19,21 @@ public class PulsarContainer extends GenericContainer { public static final String METRICS_ENDPOINT = "/metrics"; + /** + * See SystemTopicNames. + */ + private static final String TRANSACTION_TOPIC_ENDPOINT = + "/admin/v2/persistent/pulsar/system/transaction_coordinator_assign/partitions"; + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("apachepulsar/pulsar"); @Deprecated - private static final String DEFAULT_TAG = "2.2.0"; + private static final String DEFAULT_TAG = "2.10.0"; private boolean functionsWorkerEnabled = false; + private boolean transactionsEnabled = false; + /** * @deprecated use {@link PulsarContainer(DockerImageName)} instead */ @@ -41,24 +53,13 @@ public PulsarContainer(String pulsarVersion) { public PulsarContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DockerImageName.parse("apachepulsar/pulsar")); - withExposedPorts(BROKER_PORT, BROKER_HTTP_PORT); - withCommand("/pulsar/bin/pulsar", "standalone", "--no-functions-worker", "-nss"); - waitingFor(Wait.forHttp(METRICS_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); } @Override protected void configure() { super.configure(); - - if (functionsWorkerEnabled) { - withCommand("/pulsar/bin/pulsar", "standalone"); - waitingFor( - new WaitAllStrategy() - .withStrategy(waitStrategy) - .withStrategy(Wait.forLogMessage(".*Function worker service started.*", 1)) - ); - } + setupCommandAndEnv(); } public PulsarContainer withFunctionsWorker() { @@ -66,6 +67,11 @@ public PulsarContainer withFunctionsWorker() { return this; } + public PulsarContainer withTransactions() { + transactionsEnabled = true; + return this; + } + public String getPulsarBrokerUrl() { return String.format("pulsar://%s:%s", getHost(), getMappedPort(BROKER_PORT)); } @@ -73,4 +79,29 @@ public String getPulsarBrokerUrl() { public String getHttpServiceUrl() { return String.format("http://%s:%s", getHost(), getMappedPort(BROKER_HTTP_PORT)); } + + protected void setupCommandAndEnv() { + String standaloneBaseCommand = + "/pulsar/bin/apply-config-from-env.py /pulsar/conf/standalone.conf " + "&& bin/pulsar standalone"; + + if (!functionsWorkerEnabled) { + standaloneBaseCommand += " --no-functions-worker -nss"; + } + + withCommand("/bin/bash", "-c", standaloneBaseCommand); + + List waitStrategies = new ArrayList<>(); + waitStrategies.add(Wait.defaultWaitStrategy()); + waitStrategies.add(Wait.forHttp(METRICS_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); + if (transactionsEnabled) { + withEnv("PULSAR_PREFIX_transactionCoordinatorEnabled", "true"); + waitStrategies.add(Wait.forHttp(TRANSACTION_TOPIC_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); + } + if (functionsWorkerEnabled) { + waitStrategies.add(Wait.forLogMessage(".*Function worker service started.*", 1)); + } + final WaitAllStrategy compoundedWaitStrategy = new WaitAllStrategy(); + waitStrategies.forEach(compoundedWaitStrategy::withStrategy); + waitingFor(compoundedWaitStrategy); + } } diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index 6d739dfbf98..91397d00c40 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -6,6 +6,9 @@ import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.client.api.SubscriptionInitialPosition; +import org.apache.pulsar.client.api.transaction.Transaction; import org.junit.Test; import org.testcontainers.utility.DockerImageName; @@ -19,11 +22,33 @@ public class PulsarContainerTest { public static final String TEST_TOPIC = "test_topic"; - private static final DockerImageName PULSAR_IMAGE = DockerImageName.parse("apachepulsar/pulsar:2.2.0"); + private static final DockerImageName PULSAR_IMAGE = DockerImageName.parse("apachepulsar/pulsar:2.10.0"); @Test public void testUsage() throws Exception { - try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE)) { + try ( + // do not use PULSAR_IMAGE to make the doc looks easier + // constructorWithVersion { + PulsarContainer pulsar = new PulsarContainer(DockerImageName.parse("apachepulsar/pulsar:2.10.0")); + // } + ) { + pulsar.start(); + // coordinates { + final String pulsarBrokerUrl = pulsar.getPulsarBrokerUrl(); + final String httpServiceUrl = pulsar.getHttpServiceUrl(); + // } + testPulsarFunctionality(pulsarBrokerUrl); + } + } + + @Test + public void envVarsUsage() throws Exception { + try ( + // constructorWithEnv { + PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE) + .withEnv("PULSAR_PREFIX_brokerDeduplicationEnabled", "true"); + // } + ) { pulsar.start(); testPulsarFunctionality(pulsar.getPulsarBrokerUrl()); } @@ -31,24 +56,69 @@ public void testUsage() throws Exception { @Test public void shouldNotEnableFunctionsWorkerByDefault() throws Exception { - try (PulsarContainer pulsar = new PulsarContainer("2.5.1")) { + try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE)) { pulsar.start(); - PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build(); - - assertThatThrownBy(() -> pulsarAdmin.functions().getFunctions("public", "default")) - .isInstanceOf(PulsarAdminException.class); + try (PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build()) { + assertThatThrownBy(() -> pulsarAdmin.functions().getFunctions("public", "default")) + .isInstanceOf(PulsarAdminException.class); + } } } @Test public void shouldWaitForFunctionsWorkerStarted() throws Exception { - try (PulsarContainer pulsar = new PulsarContainer("2.5.1").withFunctionsWorker()) { + try ( + // constructorWithFunctionsWorker { + PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE).withFunctionsWorker(); + // } + ) { + pulsar.start(); + + try (PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build()) { + assertThat(pulsarAdmin.functions().getFunctions("public", "default")).hasSize(0); + } + } + } + + @Test + public void testTransactions() throws Exception { + try ( + // constructorWithTransactions { + PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE).withTransactions(); + // } + ) { pulsar.start(); - PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build(); + try (PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build()) { + assertThat( + pulsarAdmin + .topics() + .getList("pulsar/system") + .contains("persistent://pulsar/system/transaction_coordinator_assign-partition-0") + ) + .isTrue(); + } + testTransactionFunctionality(pulsar.getPulsarBrokerUrl()); + } + } + + @Test + public void testTransactionsAndFunctionsWorker() throws Exception { + try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE).withTransactions().withFunctionsWorker()) { + pulsar.start(); - assertThat(pulsarAdmin.functions().getFunctions("public", "default")).hasSize(0); + try (PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build();) { + assertThat( + pulsarAdmin + .topics() + .getList("pulsar/system") + .contains("persistent://pulsar/system/transaction_coordinator_assign-partition-0") + ) + .isTrue(); + assertThat(pulsarAdmin.functions().getFunctions("public", "default")).hasSize(0); + } + testTransactionFunctionality(pulsar.getPulsarBrokerUrl()); } } @@ -65,4 +135,27 @@ protected void testPulsarFunctionality(String pulsarBrokerUrl) throws Exception assertThat(new String(message.getData())).isEqualTo("test containers"); } } + + protected void testTransactionFunctionality(String pulsarBrokerUrl) throws Exception { + try ( + PulsarClient client = PulsarClient.builder().serviceUrl(pulsarBrokerUrl).enableTransaction(true).build(); + Consumer consumer = client + .newConsumer(Schema.STRING) + .topic("transaction-topic") + .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest) + .subscriptionName("test-transaction-sub") + .subscribe(); + Producer producer = client + .newProducer(Schema.STRING) + .sendTimeout(0, TimeUnit.SECONDS) + .topic("transaction-topic") + .create() + ) { + final Transaction transaction = client.newTransaction().build().get(); + producer.newMessage(transaction).value("first").send(); + transaction.commit(); + Message message = consumer.receive(); + assertThat(message.getValue()).isEqualTo("first"); + } + } } From a2acf3cc6f828ad81a92eb4cc624ee9ddd29c2e2 Mon Sep 17 00:00:00 2001 From: Daniel Shuy Date: Tue, 21 Jun 2022 07:43:11 +0800 Subject: [PATCH 1975/4969] Feature template: Fix typo in Alternatives section label (#5505) --- .github/ISSUE_TEMPLATE/feature.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 32edb0d25f5..9e79553d357 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -70,7 +70,7 @@ body: - type: textarea id: alternatives attributes: - label: Benefit + label: Alternatives description: Are there other alternatives? Please describe them. validations: required: true From 00faa95834120b482117d7d0363e9b713adb18eb Mon Sep 17 00:00:00 2001 From: Yannick Weber Date: Wed, 22 Jun 2022 10:56:25 +0200 Subject: [PATCH 1976/4969] [HiveMQ] do not delete /opt/hivemq/temp-extensions in startup command (#5509) * do not delete /opt/hivemq/temp-extensions in startup command * command does not get stuck when '/opt/hivemq/temp-extensions' does not exist --- .../main/java/org/testcontainers/hivemq/HiveMQContainer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 242cc7bdb43..8a2832f65bd 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -123,8 +123,7 @@ protected void configure() { "-c", removeCommand + "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ " + - "; rm -rf /opt/hivemq/temp-extensions/** " + - "&& chmod -R 777 /opt/hivemq/extensions " + + "; chmod -R 777 /opt/hivemq/extensions " + "&& /opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" ); } From 1f7dc46e2f48d76e6770dce10479a2c63d30bad1 Mon Sep 17 00:00:00 2001 From: Jaromir Hamala Date: Wed, 22 Jun 2022 19:10:26 +0200 Subject: [PATCH 1977/4969] Use sshd container 1.1.0 (#5486) --- .../testcontainers/containers/PortForwardingContainer.java | 7 +++++-- docs/features/configuration.md | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java index 22d364c0762..4a99ccacd91 100644 --- a/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java +++ b/core/src/main/java/org/testcontainers/containers/PortForwardingContainer.java @@ -31,14 +31,17 @@ public enum PortForwardingContainer { private Connection createSSHSession() { String password = UUID.randomUUID().toString(); container = - new GenericContainer<>(DockerImageName.parse("testcontainers/sshd:1.0.0")) + new GenericContainer<>(DockerImageName.parse("testcontainers/sshd:1.1.0")) .withExposedPorts(22) .withEnv("PASSWORD", password) .withCommand( "sh", "-c", // Disable ipv6 & Make it listen on all interfaces, not just localhost - "echo \"root:$PASSWORD\" | chpasswd && /usr/sbin/sshd -D -o PermitRootLogin=yes -o AddressFamily=inet -o GatewayPorts=yes" + // Enable algorithms supported by our ssh client library + "echo \"root:$PASSWORD\" | chpasswd && /usr/sbin/sshd -D -o PermitRootLogin=yes " + + "-o AddressFamily=inet -o GatewayPorts=yes -o AllowAgentForwarding=yes -o AllowTcpForwarding=yes " + + "-o KexAlgorithms=+diffie-hellman-group1-sha1 -o HostkeyAlgorithms=+ssh-rsa " ); container.start(); diff --git a/docs/features/configuration.md b/docs/features/configuration.md index cccae7a86df..fbb369fe6a6 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -52,7 +52,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **tinyimage.container.image = alpine:3.14** > Used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](#disabling-the-startup-checks)) -> **sshd.container.image = testcontainers/sshd:1.0.0** +> **sshd.container.image = testcontainers/sshd:1.1.0** > Required if [exposing host ports to containers](./networking.md#exposing-host-ports-to-the-container) > **vncrecorder.container.image = testcontainers/vnc-recorder:1.1.0** From cfc64bd2997000f67c46fa891dc402fd4ddbc5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 22 Jun 2022 12:56:20 -0500 Subject: [PATCH 1978/4969] Add clickhouse/clickhouse-server compatibility (#5488) `clickhouse` was initially developed by Yandex and now it is OpenSource. See more [here](https://clickhouse.com/blog/yandex-opensources-click-house/) For backward compatibility, we will be supporting the image provided by Yandex too. --- .../containers/ClickHouseContainer.java | 4 +++- .../testcontainers/ClickhouseTestImages.java | 3 ++- .../clickhouse/SimpleClickhouseTest.java | 20 ++++++++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 4528c48e935..16bbeef6c81 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -13,6 +13,8 @@ public class ClickHouseContainer extends JdbcDatabaseContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("yandex/clickhouse-server"); + private static final DockerImageName CLICKHOUSE_IMAGE_NAME = DockerImageName.parse("clickhouse/clickhouse-server"); + @Deprecated public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); @@ -49,7 +51,7 @@ public ClickHouseContainer(String dockerImageName) { public ClickHouseContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, CLICKHOUSE_IMAGE_NAME); withExposedPorts(HTTP_PORT, NATIVE_PORT); waitingFor( diff --git a/modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java b/modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java index 961df045bd1..a6707705ff8 100644 --- a/modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java +++ b/modules/clickhouse/src/test/java/org/testcontainers/ClickhouseTestImages.java @@ -3,5 +3,6 @@ import org.testcontainers.utility.DockerImageName; public interface ClickhouseTestImages { - DockerImageName CLICKHOUSE_IMAGE = DockerImageName.parse("yandex/clickhouse-server:18.10.3"); + DockerImageName YANDEX_CLICKHOUSE_IMAGE = DockerImageName.parse("yandex/clickhouse-server:18.10.3"); + DockerImageName CLICKHOUSE_IMAGE = DockerImageName.parse("clickhouse/clickhouse-server:21.9.2-alpine"); } diff --git a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java index d2375891f8c..2f6edcc722d 100644 --- a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java +++ b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java @@ -1,20 +1,38 @@ package org.testcontainers.junit.clickhouse; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import org.testcontainers.ClickhouseTestImages; import org.testcontainers.containers.ClickHouseContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; +import org.testcontainers.utility.DockerImageName; import java.sql.ResultSet; import java.sql.SQLException; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +@RunWith(Parameterized.class) public class SimpleClickhouseTest extends AbstractContainerDatabaseTest { + private final DockerImageName imageName; + + public SimpleClickhouseTest(DockerImageName imageName) { + this.imageName = imageName; + } + + @Parameterized.Parameters(name = "{0}") + public static Object[][] data() { + return new Object[][] { // + { ClickhouseTestImages.CLICKHOUSE_IMAGE }, + { ClickhouseTestImages.YANDEX_CLICKHOUSE_IMAGE }, + }; + } + @Test public void testSimple() throws SQLException { - try (ClickHouseContainer clickhouse = new ClickHouseContainer(ClickhouseTestImages.CLICKHOUSE_IMAGE)) { + try (ClickHouseContainer clickhouse = new ClickHouseContainer(this.imageName)) { clickhouse.start(); ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); From a9c2e9e148097f4996dc7a96f85fced1ee857ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 22 Jun 2022 13:30:09 -0500 Subject: [PATCH 1979/4969] [LocalStack] Remove usage of deprecated methods (#5491) Improve documentation and tests avoiding usage of deprecated methods. --- docs/modules/localstack.md | 35 +++------ .../localstack/LocalStackContainer.java | 5 +- .../containers/localstack/LegacyModeTest.java | 38 +++++++--- .../localstack/LocalstackContainerTest.java | 75 ++++++++++++++++--- 4 files changed, 102 insertions(+), 51 deletions(-) diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index b551536af74..dcc474e484e 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -12,33 +12,18 @@ DockerImageName localstackImage = DockerImageName.parse("localstack/localstack:0 @Rule public LocalStackContainer localstack = new LocalStackContainer(localstackImage) .withServices(S3); - -@Test -public void someTestMethod() { - // AWS SDK v1 - AmazonS3 s3 = AmazonS3ClientBuilder - .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) - .withCredentials(localstack.getDefaultCredentialsProvider()) - .build(); - - s3.createBucket("foo"); - s3.putObject("foo", "bar", "baz"); - - // AWS SDK v2 - S3Client s3 = S3Client - .builder() - .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3)) - .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create( - localstack.getAccessKey(), localstack.getSecretKey() - ))) - .region(Region.of(localstack.getRegion())) - .build(); - - s3.createBucket(b -> b.bucket("foo")); - s3.putObject(b -> b.bucket("foo").key("bar"), RequestBody.fromBytes("baz".getBytes())); ``` +## Creating a client using AWS SDK + + +[AWS SDK V1](../../modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java) inside_block:with_aws_sdk_v1 + + + +[AWS SDK V2](../../modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java) inside_block:with_aws_sdk_v2 + + Environment variables listed in [Localstack's README](https://github.com/localstack/localstack#configurations) may be used to customize Localstack's configuration. Use the `.withEnv(key, value)` method on `LocalStackContainer` to apply configuration settings. diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index f3f905b84f6..146cb3200f1 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -27,10 +27,7 @@ /** *

Container for LocalStack, 'A fully functional local AWS cloud stack'.

*

{@link LocalStackContainer#withServices(Service...)} should be used to select which services - * are to be launched. See {@link Service} for available choices. It is advised that - * {@link LocalStackContainer#getEndpointConfiguration(Service)} and - * {@link LocalStackContainer#getDefaultCredentialsProvider()} - * be used to obtain compatible endpoint configuration and credentials, respectively.

+ * are to be launched. See {@link Service} for available choices. */ @Slf4j public class LocalStackContainer extends GenericContainer { diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java index a757c11e928..c075d2805d6 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java @@ -1,5 +1,6 @@ package org.testcontainers.containers.localstack; +import com.amazonaws.client.builder.AwsClientBuilder; import com.github.dockerjava.api.DockerClient; import lombok.AllArgsConstructor; import org.junit.BeforeClass; @@ -8,6 +9,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.localstack.LocalStackContainer.Service; import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.utility.DockerImageName; @@ -46,20 +48,28 @@ public static Iterable constructors() { @Test public void samePortIsExposedForAllServices() { - localstack.withServices(LocalStackContainer.Service.S3, LocalStackContainer.Service.SQS); + localstack.withServices(Service.S3, Service.SQS); localstack.start(); try { assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); assertEquals( "Endpoint overrides are different", - localstack.getEndpointOverride(LocalStackContainer.Service.S3).toString(), - localstack.getEndpointOverride(LocalStackContainer.Service.SQS).toString() + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getEndpointOverride(Service.SQS).toString() ); assertEquals( "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(LocalStackContainer.Service.S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(LocalStackContainer.Service.SQS).getServiceEndpoint() + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() + ) + .getServiceEndpoint(), + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.SQS).toString(), + localstack.getRegion() + ) + .getServiceEndpoint() ); } finally { localstack.stop(); @@ -103,20 +113,28 @@ public static Iterable constructors() { @Test public void differentPortsAreExposed() { - localstack.withServices(LocalStackContainer.Service.S3, LocalStackContainer.Service.SQS); + localstack.withServices(Service.S3, Service.SQS); localstack.start(); try { assertTrue("Multiple ports are exposed", localstack.getExposedPorts().size() > 1); assertNotEquals( "Endpoint overrides are different", - localstack.getEndpointOverride(LocalStackContainer.Service.S3).toString(), - localstack.getEndpointOverride(LocalStackContainer.Service.SQS).toString() + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getEndpointOverride(Service.SQS).toString() ); assertNotEquals( "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(LocalStackContainer.Service.S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(LocalStackContainer.Service.SQS).getServiceEndpoint() + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() + ) + .getServiceEndpoint(), + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.SQS).toString(), + localstack.getRegion() + ) + .getServiceEndpoint() ); } finally { localstack.stop(); diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index 3b85c69ca34..950f29866ba 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -1,5 +1,7 @@ package org.testcontainers.containers.localstack; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.kms.AWSKMS; import com.amazonaws.services.kms.AWSKMSClientBuilder; @@ -73,11 +75,22 @@ public static class WithoutNetwork { @Test public void s3TestOverBridgeNetwork() throws IOException { + // with_aws_sdk_v1 { AmazonS3 s3 = AmazonS3ClientBuilder .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.S3)) - .withCredentials(localstack.getDefaultCredentialsProvider()) + .withEndpointConfiguration( + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() + ) + ) + .withCredentials( + new AWSStaticCredentialsProvider( + new BasicAWSCredentials(localstack.getAccessKey(), localstack.getSecretKey()) + ) + ) .build(); + // } final String bucketName = "foo"; s3.createBucket(bucketName); @@ -103,6 +116,7 @@ public void s3TestOverBridgeNetwork() throws IOException { @Test public void s3TestUsingAwsSdkV2() { + // with_aws_sdk_v2 { S3Client s3 = S3Client .builder() .endpointOverride(localstack.getEndpointOverride(Service.S3)) @@ -113,6 +127,7 @@ public void s3TestUsingAwsSdkV2() { ) .region(Region.of(localstack.getRegion())) .build(); + // } final String bucketName = "foov2"; s3.createBucket(b -> b.bucket(bucketName)); @@ -126,8 +141,17 @@ public void s3TestUsingAwsSdkV2() { public void sqsTestOverBridgeNetwork() { AmazonSQS sqs = AmazonSQSClientBuilder .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.SQS)) - .withCredentials(localstack.getDefaultCredentialsProvider()) + .withEndpointConfiguration( + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.SQS).toString(), + localstack.getRegion() + ) + ) + .withCredentials( + new AWSStaticCredentialsProvider( + new BasicAWSCredentials(localstack.getAccessKey(), localstack.getSecretKey()) + ) + ) .build(); CreateQueueResult queueResult = sqs.createQueue("baz"); @@ -157,8 +181,17 @@ public void sqsTestOverBridgeNetwork() { public void cloudWatchLogsTestOverBridgeNetwork() { AWSLogs logs = AWSLogsClientBuilder .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.CLOUDWATCHLOGS)) - .withCredentials(localstack.getDefaultCredentialsProvider()) + .withEndpointConfiguration( + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.CLOUDWATCHLOGS).toString(), + localstack.getRegion() + ) + ) + .withCredentials( + new AWSStaticCredentialsProvider( + new BasicAWSCredentials(localstack.getAccessKey(), localstack.getSecretKey()) + ) + ) .build(); logs.createLogGroup(new CreateLogGroupRequest("foo")); @@ -172,8 +205,17 @@ public void cloudWatchLogsTestOverBridgeNetwork() { public void kmsKeyCreationTest() { AWSKMS awskms = AWSKMSClientBuilder .standard() - .withEndpointConfiguration(localstack.getEndpointConfiguration(Service.KMS)) - .withCredentials(localstack.getDefaultCredentialsProvider()) + .withEndpointConfiguration( + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.KMS).toString(), + localstack.getRegion() + ) + ) + .withCredentials( + new AWSStaticCredentialsProvider( + new BasicAWSCredentials(localstack.getAccessKey(), localstack.getSecretKey()) + ) + ) .build(); String desc = String.format("AWS CMK Description"); @@ -198,8 +240,16 @@ public void samePortIsExposedForAllServices() { ); assertEquals( "Endpoint configuration have different endpoints", - localstack.getEndpointConfiguration(Service.S3).getServiceEndpoint(), - localstack.getEndpointConfiguration(Service.SQS).getServiceEndpoint() + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() + ) + .getServiceEndpoint(), + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.SQS).toString(), + localstack.getRegion() + ) + .getServiceEndpoint() ); } } @@ -302,8 +352,9 @@ public static class WithRegion { @Test public void s3EndpointHasProperRegion() { - final AwsClientBuilder.EndpointConfiguration endpointConfiguration = localstack.getEndpointConfiguration( - Service.S3 + final AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() ); assertEquals( "The endpoint configuration has right region", From afde5d3cde1657625e890740c9f137344b360cee Mon Sep 17 00:00:00 2001 From: Andrei Nevedomskii Date: Mon, 27 Jun 2022 20:34:49 +0200 Subject: [PATCH 1980/4969] JdbcDatabaseContainer: fix wrong instance call (#5465) createConnection() method calls a wrong driver instance when logging --- .../org/testcontainers/containers/JdbcDatabaseContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 0b80eaac406..aa397929497 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -232,7 +232,7 @@ public Connection createConnection(String queryString) throws SQLException, NoDr logger() .debug( "Trying to create JDBC connection using {} to {} with properties: {}", - driver.getClass().getName(), + jdbcDriverInstance.getClass().getName(), url, info ); From c0eb042dabe7b048130f33459d4a542075fb1355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 27 Jun 2022 19:52:38 -0500 Subject: [PATCH 1981/4969] Polish examples (#5520) --- .../examples/CucumberTest.java | 2 +- .../{testcontainsers => testcontainers}/examples/Stepdefs.java | 2 +- .../examples/is_search_possible.feature | 0 .../java/org/testcontainers/containers/Neo4jExampleTest.java | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename examples/cucumber/src/test/java/org/{testcontainsers => testcontainers}/examples/CucumberTest.java (84%) rename examples/cucumber/src/test/java/org/{testcontainsers => testcontainers}/examples/Stepdefs.java (98%) rename examples/cucumber/src/test/resources/org/{testcontainsers => testcontainers}/examples/is_search_possible.feature (100%) diff --git a/examples/cucumber/src/test/java/org/testcontainsers/examples/CucumberTest.java b/examples/cucumber/src/test/java/org/testcontainers/examples/CucumberTest.java similarity index 84% rename from examples/cucumber/src/test/java/org/testcontainsers/examples/CucumberTest.java rename to examples/cucumber/src/test/java/org/testcontainers/examples/CucumberTest.java index 0551b4dbf2e..f55919c0fe6 100644 --- a/examples/cucumber/src/test/java/org/testcontainsers/examples/CucumberTest.java +++ b/examples/cucumber/src/test/java/org/testcontainers/examples/CucumberTest.java @@ -1,4 +1,4 @@ -package org.testcontainsers.examples; +package org.testcontainers.examples; import io.cucumber.junit.Cucumber; import io.cucumber.junit.CucumberOptions; diff --git a/examples/cucumber/src/test/java/org/testcontainsers/examples/Stepdefs.java b/examples/cucumber/src/test/java/org/testcontainers/examples/Stepdefs.java similarity index 98% rename from examples/cucumber/src/test/java/org/testcontainsers/examples/Stepdefs.java rename to examples/cucumber/src/test/java/org/testcontainers/examples/Stepdefs.java index ca70173ae92..e1b9c7e81ef 100644 --- a/examples/cucumber/src/test/java/org/testcontainsers/examples/Stepdefs.java +++ b/examples/cucumber/src/test/java/org/testcontainers/examples/Stepdefs.java @@ -1,4 +1,4 @@ -package org.testcontainsers.examples; +package org.testcontainers.examples; import io.cucumber.java.After; import io.cucumber.java.Before; diff --git a/examples/cucumber/src/test/resources/org/testcontainsers/examples/is_search_possible.feature b/examples/cucumber/src/test/resources/org/testcontainers/examples/is_search_possible.feature similarity index 100% rename from examples/cucumber/src/test/resources/org/testcontainsers/examples/is_search_possible.feature rename to examples/cucumber/src/test/resources/org/testcontainers/examples/is_search_possible.feature diff --git a/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java index 7730d4fa8d0..d151e1a3f24 100644 --- a/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java +++ b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java @@ -24,7 +24,7 @@ // junitExample { @Testcontainers -public class Neo4jExampleTest { +class Neo4jExampleTest { @Container private static Neo4jContainer neo4jContainer = From 56d0cf1941ad5faf77d1223766a4a0c495b29f8c Mon Sep 17 00:00:00 2001 From: Dave Maughan Date: Tue, 28 Jun 2022 02:16:44 +0100 Subject: [PATCH 1982/4969] Check admin endpoint instead of metrics for Pulsar WaitStrategy. (#5514) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #5513 Co-authored-by: Eddú Meléndez Gonzales Co-authored-by: Kevin Wittek --- .../testcontainers/containers/PulsarContainer.java | 13 ++++++++++++- .../containers/PulsarContainerTest.java | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 069fccaae65..30c36db01d8 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -17,8 +17,14 @@ public class PulsarContainer extends GenericContainer { public static final int BROKER_HTTP_PORT = 8080; + /** + * @deprecated The metrics endpoint is no longer being used for the WaitStrategy. + */ + @Deprecated public static final String METRICS_ENDPOINT = "/metrics"; + private static final String ADMIN_CLUSTERS_ENDPOINT = "/admin/v2/clusters"; + /** * See SystemTopicNames. */ @@ -92,7 +98,12 @@ protected void setupCommandAndEnv() { List waitStrategies = new ArrayList<>(); waitStrategies.add(Wait.defaultWaitStrategy()); - waitStrategies.add(Wait.forHttp(METRICS_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); + waitStrategies.add( + Wait + .forHttp(ADMIN_CLUSTERS_ENDPOINT) + .forPort(BROKER_HTTP_PORT) + .forResponsePredicate("[\"standalone\"]"::equals) + ); if (transactionsEnabled) { withEnv("PULSAR_PREFIX_transactionCoordinatorEnabled", "true"); waitStrategies.add(Wait.forHttp(TRANSACTION_TOPIC_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index 91397d00c40..29de6c4c872 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -122,6 +122,17 @@ public void testTransactionsAndFunctionsWorker() throws Exception { } } + @Test + public void testClusterFullyInitialized() throws Exception { + try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE)) { + pulsar.start(); + + try (PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build()) { + assertThat(pulsarAdmin.clusters().getClusters()).hasSize(1).contains("standalone"); + } + } + } + protected void testPulsarFunctionality(String pulsarBrokerUrl) throws Exception { try ( PulsarClient client = PulsarClient.builder().serviceUrl(pulsarBrokerUrl).build(); From 5a2d76fa7f26b5ad1b57c98b2f1cac94ace397cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Mu=C3=B1oz?= Date: Tue, 28 Jun 2022 06:58:54 +0200 Subject: [PATCH 1983/4969] Switch default image to ghcr.io and update default tag to 2.4.0 (#5173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez --- .../org/testcontainers/containers/ToxiproxyContainer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index ed8413a2a31..9850d7a0918 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -25,6 +25,8 @@ public class ToxiproxyContainer extends GenericContainer { private static final String DEFAULT_TAG = "2.1.0"; + private static final DockerImageName GHCR_IMAGE_NAME = DockerImageName.parse("ghcr.io/shopify/toxiproxy"); + private static final int TOXIPROXY_CONTROL_PORT = 8474; private static final int FIRST_PROXIED_PORT = 8666; @@ -51,7 +53,7 @@ public ToxiproxyContainer(String dockerImageName) { public ToxiproxyContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, GHCR_IMAGE_NAME); addExposedPorts(TOXIPROXY_CONTROL_PORT); setWaitStrategy(new HttpWaitStrategy().forPath("/version").forPort(TOXIPROXY_CONTROL_PORT)); From e23f378e68938f2a1f459f82d80c9485c7fcf006 Mon Sep 17 00:00:00 2001 From: Andrei Navrotski <6005070+anavrotski@users.noreply.github.com> Date: Tue, 28 Jun 2022 08:32:35 +0300 Subject: [PATCH 1984/4969] [clickhouse] Add new JDBC driver name (#5474) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also, fix the liveness port. Co-authored-by: Sergei Egorov Co-authored-by: Eddú Meléndez --- .../containers/ClickHouseContainer.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java index 16bbeef6c81..4e87c77ee5b 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/containers/ClickHouseContainer.java @@ -1,13 +1,13 @@ package org.testcontainers.containers; -import com.google.common.collect.Sets; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.DockerImageName; import java.time.Duration; +import java.util.HashSet; import java.util.Set; -public class ClickHouseContainer extends JdbcDatabaseContainer { +public class ClickHouseContainer extends JdbcDatabaseContainer { public static final String NAME = "clickhouse"; @@ -53,23 +53,27 @@ public ClickHouseContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, CLICKHOUSE_IMAGE_NAME); - withExposedPorts(HTTP_PORT, NATIVE_PORT); - waitingFor( + addExposedPorts(HTTP_PORT, NATIVE_PORT); + this.waitStrategy = new HttpWaitStrategy() .forStatusCode(200) - .forResponsePredicate(responseBody -> "Ok.".equals(responseBody)) - .withStartupTimeout(Duration.ofMinutes(1)) - ); + .forResponsePredicate("Ok."::equals) + .withStartupTimeout(Duration.ofMinutes(1)); } @Override public Set getLivenessCheckPortNumbers() { - return Sets.newHashSet(HTTP_PORT); + return new HashSet<>(getMappedPort(HTTP_PORT)); } @Override public String getDriverClassName() { - return DRIVER_CLASS_NAME; + try { + Class.forName(DRIVER_CLASS_NAME); + return DRIVER_CLASS_NAME; + } catch (ClassNotFoundException e) { + return "com.clickhouse.jdbc.ClickHouseDriver"; + } } @Override From 4a14eccad30b0090ea99db7bd1ffa49a94ba37a1 Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Wed, 29 Jun 2022 00:27:00 +0200 Subject: [PATCH 1985/4969] Elasticsearch: Fix startup check for 8.3 and above (#5521) --- .../elasticsearch/ElasticsearchContainer.java | 3 ++- .../ElasticsearchContainerTest.java | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index 5a64a5e67a2..f8b9f779519 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -102,10 +102,11 @@ public ElasticsearchContainer(final DockerImageName dockerImageName) { this.isAtLeastMajorVersion8 = new ComparableVersion(dockerImageName.getVersionPart()).isGreaterThanOrEqualTo("8.0.0"); // regex that + // matches 8.3 JSON logging with started message and some follow up content within the message field // matches 8.0 JSON logging with no whitespace between message field and content // matches 7.x JSON logging with whitespace between message field and content // matches 6.x text logging with node name in brackets and just a 'started' message till the end of the line - String regex = ".*(\"message\":\\s?\"started\".*|] started\n$)"; + String regex = ".*(\"message\":\\s?\"started[\\s?|\"].*|] started\n$)"; setWaitStrategy(new LogMessageWaitStrategy().withRegEx(regex)); if (isAtLeastMajorVersion8) { withPassword(ELASTICSEARCH_DEFAULT_PASSWORD); diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 4427163ca56..9fcfc45af76 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -150,6 +150,20 @@ public void elasticsearchVersion() throws IOException { } } + @Test + public void elasticsearchVersion83() throws IOException { + try ( + ElasticsearchContainer container = new ElasticsearchContainer( + "docker.elastic.co/elasticsearch/elasticsearch:8.3.0" + ) + ) { + container.start(); + Response response = getClient(container).performRequest(new Request("GET", "/")); + assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(EntityUtils.toString(response.getEntity()), containsString("8.3.0")); + } + } + @Test public void elasticsearchOssImage() throws IOException { try ( @@ -406,10 +420,15 @@ private RestClient getClient(ElasticsearchContainer container) { new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD) ); + String protocol = container.caCertAsBytes().isPresent() ? "https://" : "http://"; + client = RestClient - .builder(HttpHost.create(container.getHttpHostAddress())) + .builder(HttpHost.create(protocol + container.getHttpHostAddress())) .setHttpClientConfigCallback(httpClientBuilder -> { + if (container.caCertAsBytes().isPresent()) { + httpClientBuilder.setSSLContext(container.createSslContextFromCa()); + } return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); }) .build(); From 3395ceba894b2f58e37524e1df4786f662c4aab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 29 Jun 2022 03:46:20 -0500 Subject: [PATCH 1986/4969] Add labeler action (#5516) Triage PRs. --- .github/labeler.yml | 79 +++++++++++++++++++++++++++++++++++ .github/workflows/labeler.yml | 14 +++++++ 2 files changed, 93 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/labeler.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 00000000000..9293237182e --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,79 @@ +"github_actions": + - .github/workflows/* +"gradle-wrapper": + - gradle/wrapper/* + - gradlew + - gradlew.bat +"modules/azure": + - modules/azure/* +"modules/cassandra": + - modules/cassandra/* +"modules/clickhouse": + - modules/clickhouse/* +"modules/cockroachdb": + - modules/cockroachdb/* +"modules/couchbase": + - modules/couchbase/* +"modules/db2": + - modules/db2/* +"modules/dynalite": + - modules/dynalite/* +"modules/elasticsearch": + - modules/elasticsearch/* +"modules/gcloud": + - modules/gcloud/* +"modules/hivemq": + - modules/hivemq/* +"modules/influx": + - modules/influxdb/* +"modules/jdbc": + - modules/jdbc/* +"modules/jupiter": + - modules/junit-jupiter/* +"modules/k3s": + - modules/k3s/* +"modules/kafka": + - modules/kafka/* +"modules/localstack": + - modules/localstack/* +"modules/mariadb": + - modules/mariadb/* +"modules/mockserver": + - modules/mockserver/* +"modules/mongodb": + - modules/mongodb/* +"modules/sql-server": + - modules/mssqlserver/* +"modules/mysql": + - modules/mysql/* +"modules/neo4j": + - modules/neo4j/* +"modules/nginx": + - modules/nginx/* +"modules/oracle": + - modules/oracle-xe/* +"modules/orientdb": + - modules/orientdb/* +"modules/postgres": + - modules/postgresql/* +"modules/presto": + - modules/presto/* +"modules/pulsar": + - modules/pulsar/* +"modules/r2dbc": + - modules/r2dbc/* +"modules/rabbitmq": + - modules/rabbitmq/* +"modules/selenium": + - modules/selenium/* +"modules/solr": + - modules/solr/* +"modules/spock": + - modules/spock/* +"modules/toxiproxy": + - modules/toxiproxy/* +"modules/trino": + - modules/trino/* +"modules/vault": + - modules/vault/* +"type/docs": docs/**/* diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 00000000000..057208eda32 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,14 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" From c562080f1ce487dfedf19e76f7d890e9871ddd03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 29 Jun 2022 03:51:47 -0500 Subject: [PATCH 1987/4969] Update latest version in mkdocs.yml --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index f6daad68155..21e157969e5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -102,4 +102,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.17.2 + latest_version: 1.17.3 From fbc5fe4935fd97747a1f7e18dade3132d474045f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 29 Jun 2022 03:52:58 -0500 Subject: [PATCH 1988/4969] Upgrade testcontainers version to 1.17.3 in japicmp --- gradle/japicmp.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/japicmp.gradle b/gradle/japicmp.gradle index fe3f8881b1c..3c438d340f0 100644 --- a/gradle/japicmp.gradle +++ b/gradle/japicmp.gradle @@ -3,7 +3,7 @@ configurations { } dependencies { - baseline "org.testcontainers:${project.name}:1.17.2", { + baseline "org.testcontainers:${project.name}:1.17.3", { exclude group: "*", module: "*" } } From 1fe0ef23f4851506b56b355a134fb60203554631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 29 Jun 2022 11:40:49 -0500 Subject: [PATCH 1989/4969] Improve docs (#5522) Add additional steps for linux and colima --- docs/supported_docker_environment/index.md | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/supported_docker_environment/index.md b/docs/supported_docker_environment/index.md index 3b82cea2165..aa6c7b1b867 100644 --- a/docs/supported_docker_environment/index.md +++ b/docs/supported_docker_environment/index.md @@ -2,16 +2,25 @@ ## Overview -| Host Operating System / Environment | Minimum recommended docker versions | Known issues / tips | -|-------------------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Linux - general | Docker v17.09 | | -| Linux - CircleCI (LXC driver) | Docker v17.09 | The `exec` feature is not compatible with CircleCI. See CircleCI configuration [example](./continuous_integration/circle_ci.md) | -| Linux - within a Docker container | Docker v17.09 | See [Running inside Docker](continuous_integration/dind_patterns.md) for Docker-in-Docker and Docker wormhole patterns | -| Mac OS X - Docker Toolbox | Docker Machine v0.8.0 | | +| Host Operating System / Environment | Minimum recommended docker versions | Known issues / tips | +|-------------------------------------|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Linux - general | Docker v17.09 | After docker installation, follow [post-installation steps](https://docs.docker.com/engine/install/linux-postinstall/). | +| Linux - CircleCI (LXC driver) | Docker v17.09 | The `exec` feature is not compatible with CircleCI. See CircleCI configuration [example](./continuous_integration/circle_ci.md) | +| Linux - within a Docker container | Docker v17.09 | See [Running inside Docker](continuous_integration/dind_patterns.md) for Docker-in-Docker and Docker wormhole patterns | +| Mac OS X - Docker Toolbox | Docker Machine v0.8.0 | | | Mac OS X - Docker for Mac | v17.09 | *Support is best-efforts at present*. `getTestHostIpAddress()` is [not currently supported](https://github.com/testcontainers/testcontainers-java/issues/166) due to limitations in Docker for Mac. | -| Windows - Docker Toolbox | | *Support is limited at present and this is not currently tested on a regular basis*. | -| Windows - Docker for Windows | | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md) | -| Windows - Windows Subsystem for Linux (WSL) | Docker v17.09 | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md). | +| Windows - Docker Toolbox | | *Support is limited at present and this is not currently tested on a regular basis*. | +| Windows - Docker for Windows | | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md) | +| Windows - Windows Subsystem for Linux (WSL) | Docker v17.09 | *Support is best-efforts at present.* Only Linux Containers (LCOW) are supported at the moment. See [Windows Support](windows.md). | + +## Using Colima? + +In order to run testcontainers against [colima](https://github.com/abiosoft/colima) the env vars bellow should be set + +``` +export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock +export DOCKER_HOST="unix://${HOME}/.colima/docker.sock" +``` ## Docker environment discovery From a2bf452bb5851a9278315b26741984038c66cd1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 1 Jul 2022 14:48:52 -0500 Subject: [PATCH 1990/4969] Add host os and arch in bug report template (#5525) Co-authored-by: Kevin Wittek --- .github/ISSUE_TEMPLATE/bug_report.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 80e0b47741d..dc86b416e46 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -65,6 +65,22 @@ body: - 'No' validations: required: true + - type: input + id: host-os + attributes: + label: Host OS + description: Which Operating System are you using? + placeholder: e.g. Linux, Windows + validations: + required: true + - type: input + id: host-arch + attributes: + label: Host Arch + description: Which architecture are you using? + placeholder: e.g. x86, ARM + validations: + required: true - type: textarea id: docker-version attributes: From 0fc238075546f56e22b0fd44ba985c2fcc2f8424 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:03:51 +0000 Subject: [PATCH 1991/4969] Bump neo4j-java-driver from 4.4.5 to 4.4.6 in /modules/neo4j Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 4.4.5 to 4.4.6. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/4.4.5...4.4.6) --- updated-dependencies: - dependency-name: org.neo4j.driver:neo4j-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index e0a51ea783e..feff7329185 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -33,6 +33,6 @@ dependencies { api project(":testcontainers") - testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.5' + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.6' testImplementation 'org.assertj:assertj-core:3.23.1' } From 9d63e7fa477e050d2fe1998b6f8824768b667397 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:03:53 +0000 Subject: [PATCH 1992/4969] Bump neo4j from 3.5.33 to 3.5.34 in /modules/neo4j Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.33 to 3.5.34. - [Release notes](https://github.com/neo4j/neo4j/releases) - [Commits](https://github.com/neo4j/neo4j/compare/3.5.33...3.5.34) --- updated-dependencies: - dependency-name: org.neo4j:neo4j dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index e0a51ea783e..779aab2bde8 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -29,7 +29,7 @@ task customNeo4jPluginJar(type: Jar) { processTestResources.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.33" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.34" api project(":testcontainers") From 1748c8ed29ccaf6964614bb97ff0d326675bab31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:04:32 +0000 Subject: [PATCH 1993/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.232 to 1.12.253. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.232...1.12.253) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 09cb51e10a4..acf379cda79 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.232' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.210' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.253' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.253' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 80695194043f8824a28c0aae44659b2f4f5051fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:04:34 +0000 Subject: [PATCH 1994/4969] Bump mariadb-java-client from 3.0.5 to 3.0.6 in /modules/mariadb Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 3.0.5 to 3.0.6. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.0.5...3.0.6) --- updated-dependencies: - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index fd534915ba1..ed7f428ba3e 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:1.0.3' testImplementation project(':jdbc-test') - testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.5' + testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.6' testImplementation testFixtures(project(':r2dbc')) testImplementation 'org.mariadb:r2dbc-mariadb:1.0.2' From 37afe8e054c764ce2898ce3e7525b56c44fee4a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:04:43 +0000 Subject: [PATCH 1995/4969] Bump transport from 7.17.4 to 7.17.5 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.17.4 to 7.17.5. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/master/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.17.4...v7.17.5) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 6d2b5b8a667..29e6591034d 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.2.2" - testImplementation "org.elasticsearch.client:transport:7.17.4" + testImplementation "org.elasticsearch.client:transport:7.17.5" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 72846fdf802e5d4a6c6bf11bd8a741049e480253 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:12 +0000 Subject: [PATCH 1996/4969] Bump java-client from 3.3.0 to 3.3.1 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.3.0...java-client-3.3.1) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 71844a30d20..df7f4cbc221 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:3.14.9' - testImplementation 'com.couchbase.client:java-client:3.3.0' + testImplementation 'com.couchbase.client:java-client:3.3.1' testImplementation 'org.awaitility:awaitility:4.2.0' } From 602d11d68f4b8e225e6d5635b85a640c3fcde92a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:32 +0000 Subject: [PATCH 1997/4969] Bump rest-assured from 5.1.0 to 5.1.1 in /modules/vault Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 5.1.0 to 5.1.1. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-5.1.0...rest-assured-5.1.1) --- updated-dependencies: - dependency-name: io.rest-assured:rest-assured dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 1ffc366987c..499286ae72a 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.bettercloud:vault-java-driver:5.1.0' - testImplementation 'io.rest-assured:rest-assured:5.1.0' + testImplementation 'io.rest-assured:rest-assured:5.1.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From 49f680ead43656a758d03441254bc42448c89fa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:36 +0000 Subject: [PATCH 1998/4969] Bump tomcat-jdbc from 10.0.21 to 10.0.22 in /modules/jdbc Bumps tomcat-jdbc from 10.0.21 to 10.0.22. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 043c2774d6c..012e9f410ec 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.21' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.22' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 81e19bf43be0927fb1ac598ad09a645eef59f415 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:38 +0000 Subject: [PATCH 1999/4969] Bump pulsar-client from 2.10.0 to 2.10.1 in /modules/pulsar Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.10.0 to 2.10.1. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.10.0...v2.10.1) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index a1b24efba37..31524211f63 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { api project(':testcontainers') - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.10.0' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.10.1' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.23.1' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.10.0' } From c4aa3db14fdbc189de6b368069f9871ab456891f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:39 +0000 Subject: [PATCH 2000/4969] Bump mssql-jdbc in /modules/mssqlserver Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 11.1.1.jre8-preview to 11.1.2.jre8-preview. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) --- updated-dependencies: - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index e7a654e12f1..30b9af2bd77 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.9.0.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.1.1.jre8-preview' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.1.2.jre8-preview' testImplementation project(':r2dbc') testImplementation 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' From b1c4fb664fa8d8b42c0e44b3a30555c3138994ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:43 +0000 Subject: [PATCH 2001/4969] Bump pulsar-client-admin from 2.10.0 to 2.10.1 in /modules/pulsar Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.10.0 to 2.10.1. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.10.0...v2.10.1) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client-admin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index a1b24efba37..e49b46a85ed 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.10.0' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.23.1' - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.10.0' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.10.1' } From d20ddfbecc1d82ce3bda4f441d18d82fc7070290 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:45 +0000 Subject: [PATCH 2002/4969] Bump amqp-client from 5.14.2 to 5.15.0 in /core Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.14.2 to 5.15.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.14.2...v5.15.0) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index ebfd4f36bcb..b4c6d7ad4a2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -88,7 +88,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:4.2.3' - testImplementation 'com.rabbitmq:amqp-client:5.14.2' + testImplementation 'com.rabbitmq:amqp-client:5.15.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.11' testImplementation ('org.mockito:mockito-core:4.6.0') { From f3fdbf6a94c5cf7082c2ea452ab93610044e2af6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:45 +0000 Subject: [PATCH 2003/4969] Bump aws-java-sdk-sqs from 1.12.233 to 1.12.253 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.233 to 1.12.253. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.233...1.12.253) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index b6fb4fd3111..e73bf61c19d 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.231' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.233' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.253' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.232' testImplementation 'software.amazon.awssdk:s3:2.17.204' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 17086e24c6fe00f93fbec6f7653df62c78f3cc34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:05:46 +0000 Subject: [PATCH 2004/4969] Bump s3 from 2.17.204 to 2.17.224 in /modules/localstack Bumps s3 from 2.17.204 to 2.17.224. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index b6fb4fd3111..4a191afd82a 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.233' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.232' - testImplementation 'software.amazon.awssdk:s3:2.17.204' + testImplementation 'software.amazon.awssdk:s3:2.17.224' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 183500e91eb6cbb79e9e7b29bedea3664556b1af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:06:14 +0000 Subject: [PATCH 2005/4969] Bump peter-evans/create-pull-request from 4.0.3 to 4.0.4 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.0.3 to 4.0.4. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/f094b77505fb89581e68a1163fbd2fffece39da1...923ad837f191474af6b1721408744feb989a4c27) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index b4d4d250346..ed21bca4670 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -17,7 +17,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@f094b77505fb89581e68a1163fbd2fffece39da1 # v3.10.1 + uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27 # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From d3ea1fca61c21e46f243b744e06ec78d73d9294f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:06:16 +0000 Subject: [PATCH 2006/4969] Bump gradle-update/update-gradle-wrapper-action from 1.0.17 to 1.0.18 Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 1.0.17 to 1.0.18. - [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases) - [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/5b865a8b4d09fdf6afaaa20397ba68455bb48f0d...981c551b17dbcf1940b1b4435afdb79babb7c13a) --- updated-dependencies: - dependency-name: gradle-update/update-gradle-wrapper-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-gradle-wrapper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index e2013d0f1b7..5855e609fce 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v3 - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@5b865a8b4d09fdf6afaaa20397ba68455bb48f0d # v1.0.13 + uses: gradle-update/update-gradle-wrapper-action@981c551b17dbcf1940b1b4435afdb79babb7c13a # v1.0.13 with: repo-token: ${{ secrets.GITHUB_TOKEN }} labels: dependencies From 82cf76073948a2e278a28fc8fd1d42fb41b49c9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:06:20 +0000 Subject: [PATCH 2007/4969] Bump actions/cache from 3.0.3 to 3.0.4 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.3 to 3.0.4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.3...v3.0.4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 9a7b314c67f..b1466ba8621 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -22,7 +22,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.3 + uses: actions/cache@v3.0.4 continue-on-error: true with: path: ~/.gradle/caches @@ -50,7 +50,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.3 + uses: actions/cache@v3.0.4 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56bb4e0799d..70ee552b798 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.3 + uses: actions/cache@v3.0.4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -56,7 +56,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.3 + uses: actions/cache@v3.0.4 continue-on-error: true with: path: ~/.gradle/caches From 92c087da00e3c67a861601c7c15d490ac2ed3390 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:07:07 +0000 Subject: [PATCH 2008/4969] Bump cucumber-java from 7.2.3 to 7.4.1 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 7.2.3 to 7.4.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.2.3...v7.4.1) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index f23a2d9b7af..3e03e776ac4 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:7.2.3' + testImplementation 'io.cucumber:cucumber-java:7.4.1' testImplementation 'io.cucumber:cucumber-junit:7.3.4' testImplementation 'org.testcontainers:selenium' } From 87e734d9c5af84bd34838e8f2f84cccf5210a078 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:07:18 +0000 Subject: [PATCH 2009/4969] Bump assertj-core from 3.22.0 to 3.23.1 in /examples Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.22.0 to 3.23.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- examples/neo4j-container/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index db89b4335fe..79e91ec5a68 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -11,7 +11,7 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:1.18.24" testImplementation 'org.testcontainers:kafka' testImplementation 'org.apache.kafka:kafka-clients:3.1.0' - testImplementation 'org.assertj:assertj-core:3.22.0' + testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' } diff --git a/examples/neo4j-container/build.gradle b/examples/neo4j-container/build.gradle index 745d3206953..e937bd2954b 100644 --- a/examples/neo4j-container/build.gradle +++ b/examples/neo4j-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - testImplementation 'org.assertj:assertj-core:3.22.0' + testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.6' testImplementation 'org.testcontainers:neo4j' testImplementation 'org.testcontainers:junit-jupiter' From 76a7c3b24c754519ccd622e42d84118a864482d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:07:25 +0000 Subject: [PATCH 2010/4969] Bump postgresql from 42.3.6 to 42.4.0 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.6 to 42.4.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.6...REL42.4.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index f25127f75eb..4bb216e6fb7 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'org.json:json:20220320' - testImplementation 'org.postgresql:postgresql:42.3.6' + testImplementation 'org.postgresql:postgresql:42.4.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:postgresql' } From cae5491705e415e9369eda6ce61a2224aae1631f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:07:27 +0000 Subject: [PATCH 2011/4969] Bump com.gradle.enterprise.gradle.plugin in /examples Bumps com.gradle.enterprise.gradle.plugin from 3.10 to 3.10.2. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index b9fb73f86c1..5a4ae8c0d2e 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.2" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" } } From 010ca107405a11d1e9674c635dfc965830fcfba9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:09:12 +0000 Subject: [PATCH 2012/4969] Bump reactor-core from 3.4.18 to 3.4.19 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.18 to 3.4.19. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.18...v3.4.19) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 51199c9a53c..692b5ac9ce5 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.18' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.19' testFixturesImplementation 'org.assertj:assertj-core:3.23.1' } From 7ca244e24d036c64d957905580aee5ae818fff5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:09:21 +0000 Subject: [PATCH 2013/4969] Bump hivemq-extension-sdk from 4.8.1 to 4.8.2 in /modules/hivemq Bumps [hivemq-extension-sdk](https://github.com/hivemq/hivemq-extension-sdk) from 4.8.1 to 4.8.2. - [Release notes](https://github.com/hivemq/hivemq-extension-sdk/releases) - [Commits](https://github.com/hivemq/hivemq-extension-sdk/compare/4.8.1...4.8.2) --- updated-dependencies: - dependency-name: com.hivemq:hivemq-extension-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 7add9af67ea..aa566381d0c 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -13,7 +13,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") testImplementation(project(":junit-jupiter")) - testImplementation("com.hivemq:hivemq-extension-sdk:4.8.1") + testImplementation("com.hivemq:hivemq-extension-sdk:4.8.2") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.11") From c130082dee8f2e3de1b48022ffc6675df5a9435e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:09:26 +0000 Subject: [PATCH 2014/4969] Bump trino-jdbc from 382 to 388 in /modules/trino Bumps trino-jdbc from 382 to 388. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index 8305e8e0629..caf1f322c12 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:382' + testImplementation 'io.trino:trino-jdbc:388' compileOnly 'org.jetbrains:annotations:23.0.0' } From 30508fe29ed6aab8160efa17c5f67f3f8ecb9fe2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:09:36 +0000 Subject: [PATCH 2015/4969] Bump google-cloud-datastore from 2.7.0 to 2.10.0 in /modules/gcloud Bumps [google-cloud-datastore](https://github.com/googleapis/java-datastore) from 2.7.0 to 2.10.0. - [Release notes](https://github.com/googleapis/java-datastore/releases) - [Changelog](https://github.com/googleapis/java-datastore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-datastore/compare/v2.7.0...v2.10.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-datastore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index cdea13f5fac..ddb634fbd79 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:2.7.0' + testImplementation 'com.google.cloud:google-cloud-datastore:2.10.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.25.5' From c0cc90ffc90d3d324e767d63ad0f1388cc8435ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:09:37 +0000 Subject: [PATCH 2016/4969] Bump client-java from 15.0.1 to 16.0.0 in /modules/k3s Bumps [client-java](https://github.com/kubernetes-client/java) from 15.0.1 to 16.0.0. - [Release notes](https://github.com/kubernetes-client/java/releases) - [Changelog](https://github.com/kubernetes-client/java/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes-client/java/compare/v15.0.1...v16.0.0) --- updated-dependencies: - dependency-name: io.kubernetes:client-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index bf51cbfefa9..2223909f051 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -9,6 +9,6 @@ dependencies { shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' testImplementation 'io.fabric8:kubernetes-client:5.12.2' - testImplementation 'io.kubernetes:client-java:15.0.1' + testImplementation 'io.kubernetes:client-java:16.0.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From d6dfc0b544c3cada52c8827d83d4851e782f25b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:09:40 +0000 Subject: [PATCH 2017/4969] Bump google-cloud-bigtable from 2.8.0 to 2.9.0 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.8.0 to 2.9.0. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.8.0...v2.9.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index cdea13f5fac..3debc0391cf 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.25.5' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.8.0' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.9.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From 183fce7a00e383de48e95ff672d8a0372a6c61d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:09:45 +0000 Subject: [PATCH 2018/4969] Bump google-cloud-pubsub from 1.119.0 to 1.120.0 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.119.0 to 1.120.0. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.119.0...v1.120.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index cdea13f5fac..1369d741f1d 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.7.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.119.0' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.25.5' testImplementation 'com.google.cloud:google-cloud-bigtable:2.8.0' testImplementation 'org.assertj:assertj-core:3.23.1' From 1e7ed80c8be857bb80a1bd3e158221ff97269516 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:10:03 +0000 Subject: [PATCH 2019/4969] Bump amqp-client from 5.14.2 to 5.15.0 in /modules/rabbitmq Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.14.2 to 5.15.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.14.2...v5.15.0) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/rabbitmq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 6c2953909bb..9825a27a499 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: RabbitMQ" dependencies { api project(":testcontainers") - testImplementation 'com.rabbitmq:amqp-client:5.14.2' + testImplementation 'com.rabbitmq:amqp-client:5.15.0' testImplementation 'org.assertj:assertj-core:3.23.1' compileOnly 'org.jetbrains:annotations:23.0.0' } From 889b990fb7dc7ae31a370c1bd28d6d7265c3fa6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:10:09 +0000 Subject: [PATCH 2020/4969] Bump mongodb-driver-sync from 4.6.0 to 4.6.1 in /modules/mongodb Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.6.0 to 4.6.1. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.6.0...r4.6.1) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mongodb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index d8ef34fbb40..297bcd21f3b 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: MongoDB" dependencies { api project(':testcontainers') - testImplementation("org.mongodb:mongodb-driver-sync:4.6.0") + testImplementation("org.mongodb:mongodb-driver-sync:4.6.1") } From 10e5c4936911629cc805a8b9085e79cfa957cf27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:10:14 +0000 Subject: [PATCH 2021/4969] Bump azure-cosmos from 4.30.0 to 4.32.1 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.30.0 to 4.32.1. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.30.0...azure-cosmos_4.32.1) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 6656445af09..5f8c6837d79 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:3.14.9' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'com.azure:azure-cosmos:4.30.0' + testImplementation 'com.azure:azure-cosmos:4.32.1' } From 267df8d0bc5a2a8b16513b0b59b3a8ebe6c22150 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:10:32 +0000 Subject: [PATCH 2022/4969] Bump postgresql from 42.3.6 to 42.4.0 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.6 to 42.4.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.6...REL42.4.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index 490b2d7fb11..fb9f53189d9 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.3.6' + testImplementation 'org.postgresql:postgresql:42.4.0' } From d5d78d0f471462612ac080284423871d0808ec2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 22:11:53 +0000 Subject: [PATCH 2023/4969] Bump com.gradle.enterprise.gradle.plugin from 3.10.1 to 3.10.2 Bumps com.gradle.enterprise.gradle.plugin from 3.10.1 to 3.10.2. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 16b3fcdf98a..73cd6b977fd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.1" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.2" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7" } } From c8daeb689cf4b1f500869a8565ebe4cbcf35390a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:34 +0000 Subject: [PATCH 2024/4969] Bump postgresql from 42.3.6 to 42.4.0 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.6 to 42.4.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.6...REL42.4.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 9a74389e8a9..73a8897800c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' - testRuntimeOnly 'org.postgresql:postgresql:42.3.6' + testRuntimeOnly 'org.postgresql:postgresql:42.4.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.29' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' } From ea4f953dc06ea7e0751f0b2ac23230af3eef41f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:34 +0000 Subject: [PATCH 2025/4969] Bump postgresql from 42.3.6 to 42.4.0 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.6 to 42.4.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.6...REL42.4.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index e609733d398..a9e3b7d09b1 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.3.6' + testRuntimeOnly 'org.postgresql:postgresql:42.4.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.29' testCompileClasspath 'org.jetbrains:annotations:23.0.0' From 7066793701465e01ecf4734a9fccb7b900995228 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:35 +0000 Subject: [PATCH 2026/4969] Bump postgresql from 42.3.6 to 42.4.0 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.6 to 42.4.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.6...REL42.4.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index f083d4ed949..87705f77d5d 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.3.6' + testImplementation 'org.postgresql:postgresql:42.4.0' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' From 1dec0ec57754e4ba2d201cd09f979a3d93b8519c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:39 +0000 Subject: [PATCH 2027/4969] Bump org.jetbrains.kotlin.jvm from 1.6.21 to 1.7.0 in /examples Bumps [org.jetbrains.kotlin.jvm](https://github.com/JetBrains/kotlin) from 1.6.21 to 1.7.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.6.21...v1.7.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 4f3a50de21a..c0bd965ab79 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.6.4" - id("org.jetbrains.kotlin.jvm") version "1.6.21" + id("org.jetbrains.kotlin.jvm") version "1.7.0" id("org.jetbrains.kotlin.plugin.spring") version "1.6.21" } From 770a9d86a721dc8fda92fe883bd4f97d49d20069 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:39 +0000 Subject: [PATCH 2028/4969] Bump tomcat-jdbc from 10.0.21 to 10.0.22 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.21 to 10.0.22. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 5674f235c7f..3649396773d 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.21' + api 'org.apache.tomcat:tomcat-jdbc:10.0.22' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.29' } From 799f1dd49bbe835b65bc1f543df9a5d459fbee3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:39 +0000 Subject: [PATCH 2029/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 8.2.2 to 8.3.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/master/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v8.2.2...v8.3.1) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 29e6591034d..a4a277596fc 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.2.2" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.3.1" testImplementation "org.elasticsearch.client:transport:7.17.5" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From f14382d24fb349d370a18c185100f27ba603e80d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:43 +0000 Subject: [PATCH 2030/4969] Bump mockito-core from 4.6.0 to 4.6.1 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 4.6.0 to 4.6.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.6.0...v4.6.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b4c6d7ad4a2..d32e2fc43b2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -91,7 +91,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.15.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.11' - testImplementation ('org.mockito:mockito-core:4.6.0') { + testImplementation ('org.mockito:mockito-core:4.6.1') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 4ce0ab4a855a81a0267d2a64ec3805633b0643ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:46 +0000 Subject: [PATCH 2031/4969] Bump cucumber-junit from 7.3.4 to 7.4.1 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.3.4 to 7.4.1. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.3.4...v7.4.1) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 3e03e776ac4..1bf4e1f72cb 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.4.1' - testImplementation 'io.cucumber:cucumber-junit:7.3.4' + testImplementation 'io.cucumber:cucumber-junit:7.4.1' testImplementation 'org.testcontainers:selenium' } From cd03ce9275d6f6a1289c91196bf21f23ba81f6c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:48 +0000 Subject: [PATCH 2032/4969] Bump aws-java-sdk-s3 from 1.12.231 to 1.12.253 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.231 to 1.12.253. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.231...1.12.253) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d6bd9781720..4ff9066b4c4 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.231' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.253' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.253' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.232' From 3e9202d8411bf077f617403e99b0c6c312e73041 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:22:51 +0000 Subject: [PATCH 2033/4969] Bump aws-java-sdk-logs from 1.12.232 to 1.12.253 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.232 to 1.12.253. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.232...1.12.253) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d6bd9781720..17e63142882 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.231' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.253' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.232' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.253' testImplementation 'software.amazon.awssdk:s3:2.17.224' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 69948b3600aa71f9e1ffd8c7e73acbc4a5dd0f49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:23:01 +0000 Subject: [PATCH 2034/4969] Bump okhttp from 4.9.3 to 4.10.0 in /examples Bumps [okhttp](https://github.com/square/okhttp) from 4.9.3 to 4.10.0. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.9.3...parent-4.10.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 4bb216e6fb7..c6272fc7522 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' - implementation 'com.squareup.okhttp3:okhttp:4.9.3' + implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220320' testImplementation 'org.postgresql:postgresql:42.4.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' From 5eed792d4679811cf84c1e58887dac7bb1b13901 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:23:03 +0000 Subject: [PATCH 2035/4969] Bump google-cloud-spanner from 6.25.5 to 6.25.7 in /modules/gcloud Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.25.5 to 6.25.7. - [Release notes](https://github.com/googleapis/java-spanner/releases) - [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-spanner/compare/v6.25.5...v6.25.7) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-spanner dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 4af736c6cb8..2cabbc4cf30 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.10.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.0' - testImplementation 'com.google.cloud:google-cloud-spanner:6.25.5' + testImplementation 'com.google.cloud:google-cloud-spanner:6.25.7' testImplementation 'com.google.cloud:google-cloud-bigtable:2.9.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From 2c0a004b5208edc57aed7c65d5241325b08b9cd9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:23:15 +0000 Subject: [PATCH 2036/4969] Bump common-custom-user-data-gradle-plugin from 1.7 to 1.7.2 Bumps common-custom-user-data-gradle-plugin from 1.7 to 1.7.2. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 73cd6b977fd..d4605c2ad84 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.2" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" } } From 0060e2b11ce5602f0b000d3deb9ce74b49c91b97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 20:43:23 +0000 Subject: [PATCH 2037/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps [org.jetbrains.kotlin.plugin.spring](https://github.com/JetBrains/kotlin) from 1.6.21 to 1.7.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.6.21...v1.7.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index c0bd965ab79..90338ff9959 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.6.4" id("org.jetbrains.kotlin.jvm") version "1.7.0" - id("org.jetbrains.kotlin.plugin.spring") version "1.6.21" + id("org.jetbrains.kotlin.plugin.spring") version "1.7.0" } apply plugin: 'io.spring.dependency-management' From 46b48e60fc2685ceefe7384e3b95f5d8183cbbd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 20:43:33 +0000 Subject: [PATCH 2038/4969] Bump kafka-clients from 3.1.0 to 3.2.0 in /examples Bumps kafka-clients from 3.1.0 to 3.2.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 79e91ec5a68..d69af5ceb68 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompileOnly "org.projectlombok:lombok:1.18.24" testAnnotationProcessor "org.projectlombok:lombok:1.18.24" testImplementation 'org.testcontainers:kafka' - testImplementation 'org.apache.kafka:kafka-clients:3.1.0' + testImplementation 'org.apache.kafka:kafka-clients:3.2.0' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' From 364111407464cf4b50bf45f1d8638b1a49ed38e0 Mon Sep 17 00:00:00 2001 From: Naveen <172697+naveensrinivasan@users.noreply.github.com> Date: Thu, 7 Jul 2022 18:47:42 -0500 Subject: [PATCH 2039/4969] chore: Set permissions for GitHub actions (#5523) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much. - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> --- .github/workflows/ci-docker-wormhole.yml | 3 +++ .github/workflows/ci-examples.yml | 3 +++ .github/workflows/ci-rootless.yml | 3 +++ .github/workflows/release-drafter.yml | 6 ++++++ .github/workflows/release.yml | 3 +++ .github/workflows/update-docs-version.yml | 6 ++++++ 6 files changed, 24 insertions(+) diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index 6d0df9a3c21..e27e4d8d611 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -4,6 +4,9 @@ on: pull_request: {} push: { branches: [ master ] } +permissions: + contents: read + jobs: in-docker_test: runs-on: ubuntu-18.04 diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index b1466ba8621..f24fd6f6916 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -10,6 +10,9 @@ env: GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} +permissions: + contents: read + jobs: find_gradle_jobs: runs-on: ubuntu-18.04 diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index 45c58c5e2d0..348cf5aaaf7 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -4,6 +4,9 @@ on: pull_request: {} push: { branches: [ master ] } +permissions: + contents: read + jobs: test: runs-on: ubuntu-18.04 diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 132b5ffd0a5..fb0780d781f 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -7,8 +7,14 @@ on: pull_request: types: [opened, reopened, synchronize] +permissions: + contents: read + jobs: update_release_draft: + permissions: + contents: write # for release-drafter/release-drafter to create a github release + pull-requests: write # for release-drafter/release-drafter to add label to PR if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c786d440c5..29a0b920922 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,9 @@ env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} +permissions: + contents: read + jobs: release: runs-on: ubuntu-18.04 diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index ed21bca4670..b2736c42590 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -4,8 +4,14 @@ on: release: types: [ published ] +permissions: + contents: read + jobs: build: + permissions: + contents: write # for peter-evans/create-pull-request to create branch + pull-requests: write # for peter-evans/create-pull-request to create a PR if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-18.04 steps: From 2f3178d04fb19dbdaa9d686380c6894e443b2377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 7 Jul 2022 18:49:12 -0500 Subject: [PATCH 2040/4969] Add read permission to ci.yml --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70ee552b798..3287499c2fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,9 @@ on: pull_request: {} push: { branches: [ master ] } +permissions: + contents: read + env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} From 84d3444600aaeeac6813505fe5bfbf9ffce760ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 7 Jul 2022 19:44:03 -0500 Subject: [PATCH 2041/4969] Add test-retry plugin (#5586) * Enable the plugin only in CI environment * Every test will retry up to 2 times. 3 runs per test in general * Disable retry if 5 tests (no retries are count) fail --- build.gradle | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build.gradle b/build.gradle index 1458b3db027..8c956133b03 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ plugins { id 'com.github.johnrengelman.shadow' version '7.0.0' id 'me.champeau.gradle.japicmp' version '0.2.9' apply false id 'com.diffplug.spotless' version '6.3.0' apply false + id 'org.gradle.test-retry' version '1.4.0' } apply from: "$rootDir/gradle/ci-support.gradle" @@ -33,6 +34,7 @@ subprojects { apply from: "$rootDir/gradle/shading.gradle" apply plugin: 'com.diffplug.spotless' apply plugin: 'checkstyle' + apply plugin: 'org.gradle.test-retry' group = "org.testcontainers" @@ -86,6 +88,14 @@ subprojects { exceptionFormat = 'full' events "STARTED", "PASSED", "FAILED", "SKIPPED" } + ext.isCI = System.getenv("CI") != null + if (isCI) { + retry { + maxRetries = 2 + maxFailures = 5 + failOnPassedAfterRetry = false + } + } } tasks.withType(Test).all { From d1b13d716616ae359cb9c9b99bd097493d691da1 Mon Sep 17 00:00:00 2001 From: Josef Cacek Date: Tue, 12 Jul 2022 14:08:29 +0200 Subject: [PATCH 2042/4969] Fix javadoc comment in ToxiproxyContainer#getProxy(GenericContainer, int) (#5591) --- .../java/org/testcontainers/containers/ToxiproxyContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java index 9850d7a0918..5f496a38873 100644 --- a/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java +++ b/modules/toxiproxy/src/main/java/org/testcontainers/containers/ToxiproxyContainer.java @@ -79,7 +79,7 @@ public int getControlPort() { /** * Obtain a {@link ContainerProxy} instance for target container that is managed by Testcontainers. The target - * container should be routable from this from this {@link ToxiproxyContainer} instance (e.g. on the same + * container should be routable from this {@link ToxiproxyContainer} instance (e.g. on the same * Docker {@link Network}). * * @param container target container From a76a7f52513426692f8d41cb01369f2aa10a3160 Mon Sep 17 00:00:00 2001 From: Quinn Bast Date: Wed, 13 Jul 2022 17:17:15 -0600 Subject: [PATCH 2043/4969] Add documentation for DependsOn (#5597) --- .../src/test/java/generic/DependsOnTest.java | 25 +++++++++++++++++++ docs/features/startup_and_waits.md | 8 ++++++ 2 files changed, 33 insertions(+) create mode 100644 docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java diff --git a/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java b/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java new file mode 100644 index 00000000000..6534a35a00f --- /dev/null +++ b/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java @@ -0,0 +1,25 @@ +package generic; + +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; + +import static org.junit.Assert.assertTrue; + +public class DependsOnTest { + + @Rule + // dependsOn { + public GenericContainer redis = new GenericContainer<>("redis:3.0.2").withExposedPorts(6379); + + @Rule + public GenericContainer nginx = new GenericContainer<>("nginx:1.9.4").dependsOn(redis).withExposedPorts(80); + + // } + + @Test + public void testContainersAllStarted() { + assertTrue(redis.isRunning()); + assertTrue(nginx.isRunning()); + } +} diff --git a/docs/features/startup_and_waits.md b/docs/features/startup_and_waits.md index 3cbec97af0d..e092919d496 100644 --- a/docs/features/startup_and_waits.md +++ b/docs/features/startup_and_waits.md @@ -123,3 +123,11 @@ If none of these options meet your requirements, you can create your own subclas /startupcheck/StartupCheckStrategy.html) with an appropriate startup check mechanism in `waitUntilStartupSuccessful()`. Or you can leave it as is and just implement the `checkStartupState(DockerClient dockerClient, String containerId)` if you still want to check state periodically. + +## Depending on another container + +Sometimes, a container relies on another container to be ready before it should start itself. An example of this might be a database that needs to be started before your application container can link to it. You can tell a container that it depends on another container by using the `dependsOn` method: + + +[Depending on another container](../examples/junit4/generic/src/test/java/generic/DependsOnTest.java) inside_block:dependsOn + From 7e364891eed1eda2fdc1cdfea7e5facaccc7b025 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 19:31:32 -0500 Subject: [PATCH 2044/4969] Update Gradle Wrapper to 7.5 (#5598) Signed-off-by: gradle-update-robot Co-authored-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 60756 bytes .../gradle/wrapper/gradle-wrapper.properties | 4 ++-- examples/gradlew | 6 ++++++ examples/gradlew.bat | 14 ++++++++------ gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 60756 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 6 ++++++ gradlew.bat | 14 ++++++++------ 8 files changed, 32 insertions(+), 16 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.jar b/examples/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d4fb3f96a785543079b8df6723c946b..249e5832f090a2944b7473328c07c9755baa3196 100644 GIT binary patch delta 10197 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 diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 5c51a4acc9d..012d6d90445 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionSha256Sum=cb87f222c5585bd46838ad4db78463a5c5f3d336e5e2b98dc7c0c586527351c2 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/gradlew b/examples/gradlew index 1b6c787337f..a69d9cb6c20 100755 --- a/examples/gradlew +++ b/examples/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/examples/gradlew.bat b/examples/gradlew.bat index ac1b06f9382..53a6b238d41 100644 --- a/examples/gradlew.bat +++ b/examples/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d4fb3f96a785543079b8df6723c946b..249e5832f090a2944b7473328c07c9755baa3196 100644 GIT binary patch delta 10197 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e1e0c8dc42b..ef80eb5051f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=e6d864e3b5bc05cc62041842b306383fc1fefcec359e70cebb1d470a6094ca82 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +distributionSha256Sum=97a52d145762adc241bad7fd18289bf7f6801e08ece6badf80402fe2b9f250b1 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787337f..a69d9cb6c20 100755 --- a/gradlew +++ b/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f9382..53a6b238d41 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal From 55ec5f1c5311f7fbc959ae56a4b1e546915c87fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Tue, 19 Jul 2022 16:50:55 -0500 Subject: [PATCH 2045/4969] Use host instead of containerIpAddress for Kotlin sample --- .../test/kotlin/com/example/redis/AbstractIntegrationTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt index 6350ace9bd9..98f56192087 100644 --- a/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt +++ b/examples/spring-boot-kotlin-redis/src/test/kotlin/com/example/redis/AbstractIntegrationTest.kt @@ -26,7 +26,7 @@ abstract class AbstractIntegrationTest { redisContainer.start() TestPropertyValues.of( - "spring.redis.host=${redisContainer.containerIpAddress}", + "spring.redis.host=${redisContainer.host}", "spring.redis.port=${redisContainer.firstMappedPort}" ).applyTo(configurableApplicationContext.environment) } From 8c8bf2a818da7bbe1ae3dca2171eebef89746a2b Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 20 Jul 2022 19:11:35 +0200 Subject: [PATCH 2046/4969] Enable JUnitPlatform in Gradle for JUnit5 examples (#4130) --- docs/examples/junit5/redis/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/examples/junit5/redis/build.gradle b/docs/examples/junit5/redis/build.gradle index 348f4788555..16f0d5bc598 100644 --- a/docs/examples/junit5/redis/build.gradle +++ b/docs/examples/junit5/redis/build.gradle @@ -9,3 +9,7 @@ dependencies { testImplementation project(":testcontainers") testImplementation project(":junit-jupiter") } + +test { + useJUnitPlatform() +} From c654018f93f5259897762c2c6a662b542a765fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 21 Jul 2022 03:16:53 -0500 Subject: [PATCH 2047/4969] Update spotless version to 6.8.0 (#5605) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8c956133b03..0ded70ad71a 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ plugins { id 'io.franzbecker.gradle-lombok' version '5.0.0' id 'com.github.johnrengelman.shadow' version '7.0.0' id 'me.champeau.gradle.japicmp' version '0.2.9' apply false - id 'com.diffplug.spotless' version '6.3.0' apply false + id 'com.diffplug.spotless' version '6.8.0' apply false id 'org.gradle.test-retry' version '1.4.0' } From d387d8518cf0976618c6580c09f68b53c4008283 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Thu, 21 Jul 2022 16:51:50 +0200 Subject: [PATCH 2048/4969] Update Oracle-XE docs and use code example from tests (#4385) Co-authored-by: Sergei Egorov --- docs/modules/databases/oraclexe.md | 25 +++---------------- .../junit/oracle/SimpleOracleTest.java | 4 ++- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/docs/modules/databases/oraclexe.md b/docs/modules/databases/oraclexe.md index 583d68f3c3d..bfc06d9a106 100644 --- a/docs/modules/databases/oraclexe.md +++ b/docs/modules/databases/oraclexe.md @@ -4,27 +4,10 @@ See [Database containers](./index.md) for documentation and usage that is common ## Usage example -Running Oracle XE as a stand-in for in a test: - -```java -public class SomeTest { - - @Rule - public OracleContainer oracle = new OracleContainer("name_of_your_oracle_xe_image"); - - @Test - public void someTestMethod() { - String url = oracle.getJdbcUrl(); - - ... create a connection and run test as normal -``` - -## Specifying a docker image name via config - -If you do not pass an image name to the `OracleContainer` constructor, a suitable image name should be placed in -configuration instead. -To do this, please place a file on the classpath named `testcontainers.properties`, -containing `oracle.container.image=IMAGE`, where IMAGE is a suitable image name and tag. +You can use `OracleContainer` like any other JDBC container: + +[Container creation](../../../modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java) inside_block:constructor + ## Adding this module to your project dependencies diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java index 2c514062415..b48bd67efc9 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java @@ -52,10 +52,12 @@ public void testPluggableDatabase() throws SQLException { @Test public void testPluggableDatabaseAndCustomUser() throws SQLException { try ( - OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) + // constructor { + OracleContainer oracle = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim") .withDatabaseName("testDB") .withUsername("testUser") .withPassword("testPassword") + // } ) { runTest(oracle, "testDB", "testUser", "testPassword"); } From 29aa84d19739f3d20c485275180e0619dd4145b1 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Thu, 21 Jul 2022 16:54:40 +0200 Subject: [PATCH 2049/4969] Update alpine image to 3.16 (#4698) --- .../main/java/org/testcontainers/DockerClientFactory.java | 2 +- core/src/test/java/org/testcontainers/TestImages.java | 4 ++-- .../testcontainers/containers/DockerComposeFilesTest.java | 2 +- .../containers/ParsedDockerComposeFileValidationTest.java | 8 ++++---- .../containers/output/ToStringConsumerTest.java | 8 ++++---- .../org/testcontainers/dockerclient/ImagePullTest.java | 2 +- .../java/org/testcontainers/junit/DockerfileTest.java | 6 +++--- .../testcontainers/junit/FixedHostPortContainerTest.java | 2 +- .../junit/ParameterizedDockerfileContainerTest.java | 2 ++ .../testcontainers/utility/DirectoryTarResourceTest.java | 6 +++--- core/src/test/resources/compose-dockerfile/Dockerfile | 2 +- .../resources/compose-scaling-multiple-containers.yml | 2 +- .../test/resources/dockerfile-build-invalid/Dockerfile | 2 +- core/src/test/resources/dockerfile-build-test/Dockerfile | 2 +- .../test/resources/dockerfile-build-test/Dockerfile-alt | 2 +- .../resources/dockerfile-build-test/Dockerfile-buildarg | 2 +- .../resources/dockerfile-build-test/Dockerfile-currentdir | 2 +- .../resources/health-wait-strategy-dockerfile/Dockerfile | 2 +- core/src/test/resources/mappable-dockerfile/Dockerfile | 2 +- .../src/test/java/generic/ContainerCreationTest.java | 2 +- .../generic/src/test/java/generic/ContainerLabelTest.java | 4 ++-- .../junit4/generic/src/test/java/generic/ExecTest.java | 2 +- docs/features/configuration.md | 2 +- docs/features/creating_images.md | 2 +- .../org/testcontainers/spock/SpockTestImages.groovy | 2 +- 25 files changed, 38 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 04c20236763..d4b40193ca2 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -60,7 +60,7 @@ public class DockerClientFactory { public static final Map DEFAULT_LABELS = ImmutableMap.of(TESTCONTAINERS_LABEL, "true"); - private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14"); + private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.16"); private static DockerClientFactory instance; diff --git a/core/src/test/java/org/testcontainers/TestImages.java b/core/src/test/java/org/testcontainers/TestImages.java index 3798f42af0d..5308f341100 100644 --- a/core/src/test/java/org/testcontainers/TestImages.java +++ b/core/src/test/java/org/testcontainers/TestImages.java @@ -6,7 +6,7 @@ public interface TestImages { DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:3.0.2"); DockerImageName RABBITMQ_IMAGE = DockerImageName.parse("rabbitmq:3.5.3"); DockerImageName MONGODB_IMAGE = DockerImageName.parse("mongo:3.1.5"); - DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.14"); + DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.16"); DockerImageName DOCKER_REGISTRY_IMAGE = DockerImageName.parse("registry:2.7.0"); - DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14"); + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.16"); } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java index 6e1630f005f..612d249449b 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java @@ -28,6 +28,6 @@ public void shouldGetDependencyImagesWhenOverriding() { ); Assertions .assertThat(dockerComposeFiles.getDependencyImages()) - .containsExactlyInAnyOrder("alpine:3.14", "redis:b", "mysql:b", "aservice:latest"); + .containsExactlyInAnyOrder("alpine:3.16", "redis:b", "mysql:b", "aservice:latest"); } } diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java index 61955de98ba..f374018a8ef 100644 --- a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -98,9 +98,9 @@ public void shouldObtainImageFromDockerfileBuild() { .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.14")) + entry("custom", Sets.newHashSet("alpine:3.16")) ) - .as("all defined images are found"); // r/ redis, mysql from compose file, alpine:3.14 from Dockerfile build + .as("all defined images are found"); // r/ redis, mysql from compose file, alpine:3.16 from Dockerfile build } @Test @@ -112,8 +112,8 @@ public void shouldObtainImageFromDockerfileBuildWithContext() { .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.14")) + entry("custom", Sets.newHashSet("alpine:3.16")) ) - .as("all defined images are found"); // redis, mysql from compose file, alpine:3.14 from Dockerfile build + .as("all defined images are found"); // redis, mysql from compose file, alpine:3.16 from Dockerfile build } } diff --git a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java index 08973f2d601..211b12080a0 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java @@ -24,7 +24,7 @@ public class ToStringConsumerTest { @Test public void newlines_are_not_added_to_exec_output() throws Exception { - try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { container.withCommand("sleep", "2m"); container.start(); @@ -35,7 +35,7 @@ public void newlines_are_not_added_to_exec_output() throws Exception { @Test(timeout = 60_000L) public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { - try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { container.withCreateContainerCmdModifier(cmd -> { cmd.withAttachStdin(true).withStdinOpen(true).withTty(true); }); @@ -49,7 +49,7 @@ public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { @Test public void newlines_are_not_added_to_container_output() { - try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { container.withCommand("echo", "-n", LARGE_PAYLOAD); container.setStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); @@ -62,7 +62,7 @@ public void newlines_are_not_added_to_container_output() { @Test public void newlines_are_not_added_to_container_output_with_tty() { - try (GenericContainer container = new GenericContainer<>("alpine:3.14")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { container.withCreateContainerCmdModifier(cmd -> { cmd.withTty(true); }); diff --git a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java index 730208c553f..e1c2a56e8a9 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java @@ -16,7 +16,7 @@ public class ImagePullTest { public static String[] parameters() { return new String[] { "alpine:latest", - "alpine:3.14", + "alpine:3.16", "alpine", // omitting the tag should work and default to latest "alpine@sha256:1775bebec23e1f3ce486989bfc9ff3c4e951690df84aa9f926497d82f2ffca9d", "quay.io/testcontainers/ryuk:latest", diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java index e121e7db5a4..df7bc417688 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java @@ -40,7 +40,7 @@ protected void configure(BuildImageCmd buildImageCmd) { super.configure(buildImageCmd); List dockerfile = Arrays.asList( - "FROM alpine:3.14", + "FROM alpine:3.16", "RUN echo 'hello from Docker build process'", "CMD yes" ); @@ -60,7 +60,7 @@ public void dockerfileBuilderWorks() { .withFileFromString("folder/someFile.txt", "hello") .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.14") + .from("alpine:3.16") .workDir("/app") .add("test.txt", "test file.txt") .run("ls", "-la", "/app/test file.txt") @@ -103,7 +103,7 @@ public int getFileMode() { ) .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.14") // + .from("alpine:3.16") // .copy("someFile.txt", "/someFile.txt") .cmd("stat -c \"%a\" /someFile.txt"); }); diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index a6bb13d160c..08545535e6b 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -24,7 +24,7 @@ */ public class FixedHostPortContainerTest { - private static final String TEST_IMAGE = "alpine:3.14"; + private static final String TEST_IMAGE = "alpine:3.16"; /** * Default http server port (just something different from default) diff --git a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java index 62eccc2000c..7c176f14a1a 100644 --- a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java @@ -43,6 +43,8 @@ public static Object[][] data() { { "alpine:3.12", "3.12" }, { "alpine:3.13", "3.13" }, { "alpine:3.14", "3.14" }, + { "alpine:3.15", "3.15" }, + { "alpine:3.16", "3.16" }, }; } diff --git a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java index cbd35a62b52..46fd6894a02 100644 --- a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java +++ b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java @@ -27,7 +27,7 @@ public void simpleRecursiveFileTest() { new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.14") + .from("alpine:3.16") .copy("/tmp/foo", "/foo") .cmd("cat /foo/test/resources/test-recursive-file.txt") .build(); @@ -52,7 +52,7 @@ public void simpleRecursiveFileWithPermissionTest() { new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.14") // + .from("alpine:3.16") // .copy("/tmp/foo", "/foo") .cmd("ls", "-al", "/") .build(); @@ -79,7 +79,7 @@ public void simpleRecursiveClasspathResourceTest() { new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.14") // + .from("alpine:3.16") // .copy("/tmp/foo", "/foo") .cmd("ls -lRt /foo") .build(); diff --git a/core/src/test/resources/compose-dockerfile/Dockerfile b/core/src/test/resources/compose-dockerfile/Dockerfile index 7252932b104..566428fa97f 100644 --- a/core/src/test/resources/compose-dockerfile/Dockerfile +++ b/core/src/test/resources/compose-dockerfile/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.14 +FROM alpine:3.16 ADD passthrough.sh /passthrough.sh diff --git a/core/src/test/resources/compose-scaling-multiple-containers.yml b/core/src/test/resources/compose-scaling-multiple-containers.yml index 3ea528d4574..fc498a9fd42 100644 --- a/core/src/test/resources/compose-scaling-multiple-containers.yml +++ b/core/src/test/resources/compose-scaling-multiple-containers.yml @@ -3,5 +3,5 @@ services: redis: image: redis other: - image: alpine:3.14 + image: alpine:3.16 command: sleep 10000 diff --git a/core/src/test/resources/dockerfile-build-invalid/Dockerfile b/core/src/test/resources/dockerfile-build-invalid/Dockerfile index b0198eb3e02..66663986d13 100644 --- a/core/src/test/resources/dockerfile-build-invalid/Dockerfile +++ b/core/src/test/resources/dockerfile-build-invalid/Dockerfile @@ -1 +1 @@ -FROM alpine:3.14 +FROM alpine:3.16 diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile b/core/src/test/resources/dockerfile-build-test/Dockerfile index 9ae7dba8658..3f341034fef 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile @@ -1,2 +1,2 @@ -FROM alpine:3.14 +FROM alpine:3.16 COPY localfile.txt /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-alt b/core/src/test/resources/dockerfile-build-test/Dockerfile-alt index 43e5c556fe9..fe36516c397 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile-alt +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-alt @@ -1,2 +1,2 @@ -FROM alpine:3.14 +FROM alpine:3.16 RUN echo "test4567" > /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg b/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg index b37f4193643..f137d39f0d2 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-buildarg @@ -1,3 +1,3 @@ -FROM alpine:3.14 +FROM alpine:3.16 ARG CUSTOM_ARG RUN echo "${CUSTOM_ARG}" > /test.txt diff --git a/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir b/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir index e8456e1bc1f..3a6bfd62f02 100644 --- a/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir +++ b/core/src/test/resources/dockerfile-build-test/Dockerfile-currentdir @@ -1,2 +1,2 @@ -FROM alpine:3.14 +FROM alpine:3.16 COPY . / diff --git a/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile b/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile index c0abb7bb597..ed404c1f0d8 100644 --- a/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile +++ b/core/src/test/resources/health-wait-strategy-dockerfile/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.14 +FROM alpine:3.16 HEALTHCHECK --interval=1s CMD test -e /testfile diff --git a/core/src/test/resources/mappable-dockerfile/Dockerfile b/core/src/test/resources/mappable-dockerfile/Dockerfile index df186f6579c..5b9f6a02783 100644 --- a/core/src/test/resources/mappable-dockerfile/Dockerfile +++ b/core/src/test/resources/mappable-dockerfile/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.14 +FROM alpine:3.16 ADD folder/someFile.txt /someFile.txt RUN cat /someFile.txt ADD test.txt /test.txt diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java index bdd82968191..0f6269968dd 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java @@ -20,7 +20,7 @@ public class ContainerCreationTest { // } // spotless:on - public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.14"); + public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.16"); // spotless:off // withOptions { diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java index 64618ad25a9..868b8ec44f7 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java @@ -9,7 +9,7 @@ public class ContainerLabelTest { // single_label { - public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.14")) + public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.16")) .withLabel("key", "value"); // } @@ -17,7 +17,7 @@ public class ContainerLabelTest { private Map mapOfLabels = new HashMap<>(); // populate map, e.g. mapOfLabels.put("key1", "value1"); - public GenericContainer containerWithMultipleLabels = new GenericContainer(DockerImageName.parse("alpine:3.14")) + public GenericContainer containerWithMultipleLabels = new GenericContainer(DockerImageName.parse("alpine:3.16")) .withLabels(mapOfLabels); // } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java index 2530cadb410..7548ae4a613 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java @@ -13,7 +13,7 @@ public class ExecTest { @Rule - public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.14")) + public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.16")) .withCommand("top"); @Test diff --git a/docs/features/configuration.md b/docs/features/configuration.md index fbb369fe6a6..f93d0807d01 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -49,7 +49,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **ryuk.container.image = testcontainers/ryuk:0.3.3** > Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) -> **tinyimage.container.image = alpine:3.14** +> **tinyimage.container.image = alpine:3.16** > Used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](#disabling-the-startup-checks)) > **sshd.container.image = testcontainers/sshd:1.1.0** diff --git a/docs/features/creating_images.md b/docs/features/creating_images.md index 6a06627efa0..e4e6315a405 100644 --- a/docs/features/creating_images.md +++ b/docs/features/creating_images.md @@ -51,7 +51,7 @@ new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> builder - .from("alpine:3.14") + .from("alpine:3.16") .run("apk add --update nginx") .cmd("nginx", "-g", "daemon off;") .build())) diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy index 41432e5e514..bea0a974c89 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy @@ -6,5 +6,5 @@ interface SpockTestImages { DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:5.7.34") DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") - DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.14") + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.16") } From 6aab4d92aeaef5d1e6174f52267bf48edc3aaf8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 25 Jul 2022 03:05:10 -0500 Subject: [PATCH 2050/4969] Add pr label for area/docker-compose (#5610) --- .github/labeler.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index 9293237182e..84e21af744a 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,3 +1,6 @@ +"area/docker-compose": + - core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java + - core/src/main/java/org/testcontainers/containers/DockerComposeFiles.java "github_actions": - .github/workflows/* "gradle-wrapper": From d3cb25ec7d66332d124ad1a8fa36771a7090412d Mon Sep 17 00:00:00 2001 From: Erik Pragt <91307175+epragtbeamtree@users.noreply.github.com> Date: Wed, 27 Jul 2022 16:47:04 +1000 Subject: [PATCH 2051/4969] Update CircleCI docs for current Cloud/v2/v3 configuration (#5611) Co-authored-by: Kevin Wittek --- .../continuous_integration/circle_ci.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/supported_docker_environment/continuous_integration/circle_ci.md b/docs/supported_docker_environment/continuous_integration/circle_ci.md index 64e7ea131f2..05f0776f6c1 100644 --- a/docs/supported_docker_environment/continuous_integration/circle_ci.md +++ b/docs/supported_docker_environment/continuous_integration/circle_ci.md @@ -1,19 +1,16 @@ -# CircleCI 2.0 +# CircleCI (Cloud, Server v2.x, and Server v3.x) -Your CircleCI configuration should use a dedicated VM for testcontainers to work. You can achieve this by specifying the -executor type in your `.circleci/config.yml` to be `machine` instead of the default `docker` executor ( see [Choosing an Executor Type](https://circleci.com/docs/2.0/executor-types/) for more info ). +Your CircleCI configuration should use a dedicated VM for Testcontainers to work. You can achieve this by specifying the +executor type in your `.circleci/config.yml` to be `machine` instead of the default `docker` executor (see [Choosing an Executor Type](https://circleci.com/docs/2.0/executor-types/) for more info). -Here is a sample CircleCI configuration that does a checkout of a project and runs maven: +Here is a sample CircleCI configuration that does a checkout of a project and runs Maven: ```yml -# Check https://circleci.com/docs/2.0/language-java/ for more details -# -version: 2 -machine: true jobs: build: + # Check https://circleci.com/docs/executor-intro#linux-vm for more details + machine: true steps: - checkout - - run: mvn -B clean install ``` From fd97b769a8b083a8e3a208d119377176fe88cb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 27 Jul 2022 19:57:31 -0500 Subject: [PATCH 2052/4969] Add docs for AWS CodeBuild and Tekton (#5614) --- .../continuous_integration/aws_codebuild.md | 18 ++++ .../continuous_integration/tekton.md | 94 +++++++++++++++++++ mkdocs.yml | 2 + 3 files changed, 114 insertions(+) create mode 100644 docs/supported_docker_environment/continuous_integration/aws_codebuild.md create mode 100644 docs/supported_docker_environment/continuous_integration/tekton.md diff --git a/docs/supported_docker_environment/continuous_integration/aws_codebuild.md b/docs/supported_docker_environment/continuous_integration/aws_codebuild.md new file mode 100644 index 00000000000..c28854d9e0e --- /dev/null +++ b/docs/supported_docker_environment/continuous_integration/aws_codebuild.md @@ -0,0 +1,18 @@ +# AWS CodeBuild + +To enable access to Docker in AWS CodeBuild, go to `Privileged` section and check +`Enable this flag if you want to build Docker images or want your builds to get elevated privileges`. + +This is a sample `buildspec.yml` config: + +```yaml +version: 0.2 + +phases: + install: + runtime-versions: + java: corretto17 + build: + commands: + - ./mvnw test +``` diff --git a/docs/supported_docker_environment/continuous_integration/tekton.md b/docs/supported_docker_environment/continuous_integration/tekton.md new file mode 100644 index 00000000000..f8c6fb96adc --- /dev/null +++ b/docs/supported_docker_environment/continuous_integration/tekton.md @@ -0,0 +1,94 @@ +# Tekton + +o enable access to Docker in Tekton, a dind sidecar needs to be added. An example of it can be found +[here](https://github.com/tektoncd/pipeline/blob/main/examples/v1beta1/taskruns/dind-sidecar.yaml) + +This is an example + +```yaml +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: run-tests + description: Run Tests +spec: + workspaces: + - name: source + steps: + - name: read + image: eclipse-temurin:17.0.3_7-jdk-alpine + workingDir: $(workspaces.source.path) + script: ./mvnw test + volumeMounts: + - mountPath: /var/run/ + name: dind-socket + sidecars: + - image: docker:20.10-dind + name: docker + securityContext: + privileged: true + volumeMounts: + - mountPath: /var/lib/docker + name: dind-storage + - mountPath: /var/run/ + name: dind-socket + volumes: + - name: dind-storage + emptyDir: { } + - name: dind-socket + emptyDir: { } +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: testcontainers-demo +spec: + description: | + This pipeline clones a git repo, run testcontainers. + params: + - name: repo-url + type: string + description: The git repo URL to clone from. + workspaces: + - name: shared-data + description: | + This workspace contains the cloned repo files, so they can be read by the + next task. + tasks: + - name: fetch-source + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-data + params: + - name: url + value: $(params.repo-url) + - name: run-tests + runAfter: ["fetch-source"] + taskRef: + name: run-tests + workspaces: + - name: source + workspace: shared-data +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: testcontainers-demo-run +spec: + pipelineRef: + name: testcontainers-demo + workspaces: + - name: shared-data + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + params: + - name: repo-url + value: https://github.com/testcontainers/testcontainers-java-repro.git +``` diff --git a/mkdocs.yml b/mkdocs.yml index 21e157969e5..396986a955b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,11 +88,13 @@ nav: - System Requirements: - supported_docker_environment/index.md - Continuous Integration: + - supported_docker_environment/continuous_integration/aws_codebuild.md - supported_docker_environment/continuous_integration/dind_patterns.md - supported_docker_environment/continuous_integration/circle_ci.md - supported_docker_environment/continuous_integration/drone.md - supported_docker_environment/continuous_integration/gitlab_ci.md - supported_docker_environment/continuous_integration/bitbucket_pipelines.md + - supported_docker_environment/continuous_integration/tekton.md - supported_docker_environment/windows.md - supported_docker_environment/logging_config.md - supported_docker_environment/image_registry_rate_limiting.md From fca585db3920b127dae56600772d889e509a5dca Mon Sep 17 00:00:00 2001 From: Sergei Egorov Date: Thu, 28 Jul 2022 03:10:56 -0400 Subject: [PATCH 2053/4969] Link to the docs on environment discovery failure (#5615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez --- .../dockerclient/DockerClientProviderStrategy.java | 9 ++++----- docs/_redirects | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java index 0d2aa3d08ed..01fb60e4b5d 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java @@ -246,12 +246,11 @@ public boolean test(DockerClientProviderStrategy dockerClientProviderStrategy) { .findFirst() .orElseThrow(() -> { log.error( - "Could not find a valid Docker environment. Please check configuration. Attempted configurations were:" + "Could not find a valid Docker environment. Please check configuration. Attempted configurations were:\n" + + configurationFailures.stream().map(it -> "\t" + it).collect(Collectors.joining("\n")) + + "As no valid configuration was found, execution cannot continue.\n" + + "See https://www.testcontainers.org/on_failure.html for more details." ); - for (String failureMessage : configurationFailures) { - log.error(" " + failureMessage); - } - log.error("As no valid configuration was found, execution cannot continue"); FAIL_FAST_ALWAYS.set(true); return new IllegalStateException( diff --git a/docs/_redirects b/docs/_redirects index 99fe10d6900..5918fb853f2 100644 --- a/docs/_redirects +++ b/docs/_redirects @@ -12,6 +12,7 @@ /usage/database_containers.html /modules/databases/ /usage/neo4j_container.html /modules/databases/neo4j/ /compatibility.html /supported_docker_environment/ +/on_failure.html /supported_docker_environment/ # No great 1:1 mapping exists for the following, so redirect to somewhere where at least a sensible sidebar will be shown From 1419cf24eea3e145ab86f4fd17356143a5f9e9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 28 Jul 2022 10:26:59 -0500 Subject: [PATCH 2054/4969] Improve Pulsar's wait strategy to rely on clusterName (#5613) `PulsarContainer` allow to override configuration using env vars, using `PULSAR_PREFIX_clusterName" will override the default's value "standalone". The endpoint response should adapt accordingly. --- .../testcontainers/containers/PulsarContainer.java | 8 ++++---- .../containers/PulsarContainerTest.java | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 30c36db01d8..10dc35dc4c8 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -96,13 +96,13 @@ protected void setupCommandAndEnv() { withCommand("/bin/bash", "-c", standaloneBaseCommand); + final String clusterName = getEnvMap().getOrDefault("PULSAR_PREFIX_clusterName", "standalone"); + final String response = String.format("[\"%s\"]", clusterName); + List waitStrategies = new ArrayList<>(); waitStrategies.add(Wait.defaultWaitStrategy()); waitStrategies.add( - Wait - .forHttp(ADMIN_CLUSTERS_ENDPOINT) - .forPort(BROKER_HTTP_PORT) - .forResponsePredicate("[\"standalone\"]"::equals) + Wait.forHttp(ADMIN_CLUSTERS_ENDPOINT).forPort(BROKER_HTTP_PORT).forResponsePredicate(response::equals) ); if (transactionsEnabled) { withEnv("PULSAR_PREFIX_transactionCoordinatorEnabled", "true"); diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index 29de6c4c872..bf9f3d2201f 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -54,6 +54,17 @@ public void envVarsUsage() throws Exception { } } + @Test + public void customClusterName() throws Exception { + try ( + PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE) + .withEnv("PULSAR_PREFIX_clusterName", "tc-cluster"); + ) { + pulsar.start(); + testPulsarFunctionality(pulsar.getPulsarBrokerUrl()); + } + } + @Test public void shouldNotEnableFunctionsWorkerByDefault() throws Exception { try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE)) { From bac4dfea7994c2f4993a98b02d50104825a6953e Mon Sep 17 00:00:00 2001 From: Henri Tremblay Date: Fri, 29 Jul 2022 06:33:04 -0400 Subject: [PATCH 2055/4969] Make outer maximum startup timeout in DockerComposeContainer configurable (#5588) --- .../containers/DockerComposeContainer.java | 16 ++++++++++++++-- ...DockerComposeContainerWithServicesTest.java | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 86a98586c7f..14124d88c28 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -103,6 +103,8 @@ public class DockerComposeContainer> private final Map waitStrategyMap = new ConcurrentHashMap<>(); + private Duration startupTimeout = Duration.ofMinutes(30); + private final SocatContainer ambassadorContainer = new SocatContainer(); private final Map>> logConsumers = new ConcurrentHashMap<>(); @@ -433,14 +435,14 @@ private String getServiceInstanceName(String serviceName) { /* * can have multiple wait strategies for a single container, e.g. if waiting on several ports * if no wait strategy is defined, the WaitAllStrategy will return immediately. - * The WaitAllStrategy uses an long timeout, because timeouts should be handled by the inner strategies. + * The WaitAllStrategy uses the startup timeout for everything as a global maximum, but we expect timeouts to be handled by the inner strategies. */ private void addWaitStrategy(String serviceInstanceName, @NonNull WaitStrategy waitStrategy) { final WaitAllStrategy waitAllStrategy = waitStrategyMap.computeIfAbsent( serviceInstanceName, __ -> { return new WaitAllStrategy(WaitAllStrategy.Mode.WITH_MAXIMUM_OUTER_TIMEOUT) - .withStartupTimeout(Duration.ofMinutes(30)); + .withStartupTimeout(startupTimeout); } ); waitAllStrategy.withStrategy(waitStrategy); @@ -598,6 +600,16 @@ public SELF withRemoveImages(RemoveImages removeImages) { return self(); } + /** + * Set the maximum startup timeout all the waits set are bounded to. + * + * @return this instance. for chaining + */ + public SELF withStartupTimeout(Duration startupTimeout) { + this.startupTimeout = startupTimeout; + return self(); + } + public Optional getContainerByServiceName(String serviceName) { return Optional.ofNullable(serviceInstanceMap.get(serviceName)); } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java index 8f056de98fa..305de496cc9 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java @@ -1,12 +1,15 @@ package org.testcontainers.containers; import org.junit.Test; +import org.testcontainers.containers.wait.strategy.Wait; import java.io.File; +import java.time.Duration; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class DockerComposeContainerWithServicesTest { @@ -87,6 +90,21 @@ public void testScaleInComposeFileIsRespected() { } } + @Test + public void testStartupTimeoutSetsTheHighestTimeout() { + assertThrows("We expect a timeout from the startup timeout", org.rnorth.ducttape.TimeoutException.class, + () -> { + try ( + DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) + .withServices("redis") + .withStartupTimeout(Duration.ofMillis(1)) + .withExposedService("redis", 80, Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(1))); + ) { + compose.start(); + } + }); + } + private void verifyStartedContainers(final DockerComposeContainer compose, final String... names) { final List containerNames = compose .listChildContainers() From 0b374b391d4aaa4ccd9c723b41e8bac9a55a5d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Fri, 29 Jul 2022 16:19:02 -0500 Subject: [PATCH 2056/4969] Fix format --- .../DockerComposeContainerWithServicesTest.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java index 305de496cc9..b7b820a3011 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java @@ -9,8 +9,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; public class DockerComposeContainerWithServicesTest { @@ -92,17 +92,24 @@ public void testScaleInComposeFileIsRespected() { @Test public void testStartupTimeoutSetsTheHighestTimeout() { - assertThrows("We expect a timeout from the startup timeout", org.rnorth.ducttape.TimeoutException.class, + assertThrows( + "We expect a timeout from the startup timeout", + org.rnorth.ducttape.TimeoutException.class, () -> { try ( DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) .withServices("redis") .withStartupTimeout(Duration.ofMillis(1)) - .withExposedService("redis", 80, Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(1))); + .withExposedService( + "redis", + 80, + Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(1)) + ); ) { compose.start(); } - }); + } + ); } private void verifyStartedContainers(final DockerComposeContainer compose, final String... names) { From edee92250a03f54d3e2908de3589b0b7efd754eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:05:48 +0000 Subject: [PATCH 2057/4969] Bump kafka-clients from 3.2.0 to 3.2.1 in /modules/kafka Bumps kafka-clients from 3.2.0 to 3.2.1. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 79264b8207f..ebd9c84120c 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { api project(':testcontainers') - testImplementation 'org.apache.kafka:kafka-clients:3.2.0' + testImplementation 'org.apache.kafka:kafka-clients:3.2.1' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' } From 8b2d5d17f503e44b2713267648938942e086b108 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:05:51 +0000 Subject: [PATCH 2058/4969] Bump tomcat-jdbc from 10.0.22 to 10.0.23 in /modules/jdbc Bumps tomcat-jdbc from 10.0.22 to 10.0.23. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 012e9f410ec..3a6681aee13 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.22' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.23' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From c83590275d4342eb10345e9a9451f3cb54c920a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:06:01 +0000 Subject: [PATCH 2059/4969] Bump neo4j-java-driver from 4.4.6 to 4.4.9 in /modules/neo4j Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 4.4.6 to 4.4.9. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/4.4.6...4.4.9) --- updated-dependencies: - dependency-name: org.neo4j.driver:neo4j-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index 355dbe3f4ee..de42bca2d5d 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -33,6 +33,6 @@ dependencies { api project(":testcontainers") - testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.6' + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.9' testImplementation 'org.assertj:assertj-core:3.23.1' } From 0d1ebaee2c19c3a2a2bc3538099b94072838ff5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:06:06 +0000 Subject: [PATCH 2060/4969] Bump java-client from 3.3.1 to 3.3.2 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.3.1...java-client-3.3.2) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index df7f4cbc221..e59e346c29f 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:3.14.9' - testImplementation 'com.couchbase.client:java-client:3.3.1' + testImplementation 'com.couchbase.client:java-client:3.3.2' testImplementation 'org.awaitility:awaitility:4.2.0' } From 699938b9a3f4675adc07452d368ef504b1fa2dd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:06:07 +0000 Subject: [PATCH 2061/4969] Bump mysql-connector-java from 8.0.29 to 8.0.30 in /modules/jdbc-test Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.29 to 8.0.30. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.29...8.0.30) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 3649396773d..a3c7dfdeefe 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -16,5 +16,5 @@ dependencies { api 'org.apache.tomcat:tomcat-jdbc:10.0.22' api 'org.vibur:vibur-dbcp:25.0' - api 'mysql:mysql-connector-java:8.0.29' + api 'mysql:mysql-connector-java:8.0.30' } From 26386e6ef2f41e0c403e24c2dcf4d87848c06d25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:06:08 +0000 Subject: [PATCH 2062/4969] Bump tomcat-jdbc from 10.0.22 to 10.0.23 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.22 to 10.0.23. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 3649396773d..038cc110a1b 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -14,7 +14,7 @@ dependencies { exclude(group: "net.java.dev.jna", module: "jna") } - api 'org.apache.tomcat:tomcat-jdbc:10.0.22' + api 'org.apache.tomcat:tomcat-jdbc:10.0.23' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.29' } From 463a5c5d48b55f882f29b046bb6e5e5ecc5ae0b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:06:12 +0000 Subject: [PATCH 2063/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.253 to 1.12.273. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.253...1.12.273) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index acf379cda79..5b9ff919da7 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.253' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.253' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 85cc40b057c9c2e740180ce92dfb980c5430c9de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:06:20 +0000 Subject: [PATCH 2064/4969] Bump mysql-connector-java from 8.0.29 to 8.0.30 in /modules/mysql Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.29 to 8.0.30. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.29...8.0.30) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index e23920eaae9..87887384973 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.29' + testImplementation 'mysql:mysql-connector-java:8.0.30' testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' From 33f08921d5996d71f41b353d5e5cc8b28494f00a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:07:10 +0000 Subject: [PATCH 2065/4969] Bump mysql-connector-java from 8.0.29 to 8.0.30 in /modules/spock Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.29 to 8.0.30. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.29...8.0.30) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index a9e3b7d09b1..3eadd33ea2a 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.4.0' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.29' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testCompileClasspath 'org.jetbrains:annotations:23.0.0' } From c43589ffb3ac30e564885df29168234ced5c6273 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:07:11 +0000 Subject: [PATCH 2066/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 8.3.1 to 8.3.3. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/main/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v8.3.1...v8.3.3) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index a4a277596fc..a3a47d11fab 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.3.1" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.3.3" testImplementation "org.elasticsearch.client:transport:7.17.5" testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 17526d7085dc1044aad98c801df407d99b5d196d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:07:16 +0000 Subject: [PATCH 2067/4969] Bump junit-jupiter-api from 5.8.2 to 5.9.0 in /modules/junit-jupiter Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.2...r5.9.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 73a8897800c..167529f9fea 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { api project(':testcontainers') - api 'org.junit.jupiter:junit-jupiter-api:5.8.2' + api 'org.junit.jupiter:junit-jupiter-api:5.9.0' testImplementation project(':mysql') testImplementation project(':postgresql') From cc10355394942be97fc22aac1c882e88386f7ccf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:07:21 +0000 Subject: [PATCH 2068/4969] Bump junit-jupiter-params from 5.8.2 to 5.9.0 in /modules/junit-jupiter Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.2...r5.9.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 73a8897800c..a7e23a2f65c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0' testRuntimeOnly 'org.postgresql:postgresql:42.4.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.29' From b9d49464dd9e0dc60643d38a11e4eeae478b9a31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:07:30 +0000 Subject: [PATCH 2069/4969] Bump junit-jupiter-engine from 5.8.2 to 5.9.0 in /modules/junit-jupiter Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.2...r5.9.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 73a8897800c..3dd6c7dd25f 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntimeOnly 'org.postgresql:postgresql:42.4.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.29' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' } test { From 8dfe6c5aaea81e6c7794acac22168ef874e9e826 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:08:21 +0000 Subject: [PATCH 2070/4969] Bump actions/cache from 3.0.4 to 3.0.5 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.4 to 3.0.5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.4...v3.0.5) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index f24fd6f6916..9fa1f78e47b 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -25,7 +25,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.4 + uses: actions/cache@v3.0.5 continue-on-error: true with: path: ~/.gradle/caches @@ -53,7 +53,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.4 + uses: actions/cache@v3.0.5 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3287499c2fc..55432b3e2c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.4 + uses: actions/cache@v3.0.5 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -59,7 +59,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.4 + uses: actions/cache@v3.0.5 continue-on-error: true with: path: ~/.gradle/caches From b687658cf70d842de21c000b5da409cf270cb1a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:08:29 +0000 Subject: [PATCH 2071/4969] Bump influxdb-java from 2.22 to 2.23 in /modules/influxdb Bumps [influxdb-java](https://github.com/influxdata/influxdb-java) from 2.22 to 2.23. - [Release notes](https://github.com/influxdata/influxdb-java/releases) - [Changelog](https://github.com/influxdata/influxdb-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-java/compare/influxdb-java-2.22...influxdb-java-2.23) --- updated-dependencies: - dependency-name: org.influxdb:influxdb-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/influxdb/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index 7a028d4a19d..a7ff4e66729 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: InfluxDB" dependencies { api project(':testcontainers') - compileOnly 'org.influxdb:influxdb-java:2.22' - testImplementation 'org.influxdb:influxdb-java:2.21' + compileOnly 'org.influxdb:influxdb-java:2.23' + testImplementation 'org.influxdb:influxdb-java:2.23' } From 5cb65abe0014e2ef0a1cb7245589e789760e7f49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:08:39 +0000 Subject: [PATCH 2072/4969] Bump s3 from 2.17.224 to 2.17.244 in /modules/localstack Bumps s3 from 2.17.224 to 2.17.244. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 56776965f8a..9a29eb0e343 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.253' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.253' - testImplementation 'software.amazon.awssdk:s3:2.17.224' + testImplementation 'software.amazon.awssdk:s3:2.17.244' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 1cf31e61d347f0e95a13729f094b719c193bf43e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:09:23 +0000 Subject: [PATCH 2073/4969] Bump neo4j-java-driver from 4.4.6 to 4.4.9 in /examples Bumps [neo4j-java-driver](https://github.com/neo4j/neo4j-java-driver) from 4.4.6 to 4.4.9. - [Release notes](https://github.com/neo4j/neo4j-java-driver/releases) - [Commits](https://github.com/neo4j/neo4j-java-driver/compare/4.4.6...4.4.9) --- updated-dependencies: - dependency-name: org.neo4j.driver:neo4j-java-driver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/neo4j-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/neo4j-container/build.gradle b/examples/neo4j-container/build.gradle index e937bd2954b..e7e42ff00bd 100644 --- a/examples/neo4j-container/build.gradle +++ b/examples/neo4j-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.6' + testImplementation 'org.neo4j.driver:neo4j-java-driver:4.4.9' testImplementation 'org.testcontainers:neo4j' testImplementation 'org.testcontainers:junit-jupiter' } From 95e917f31b8152fb84a2ebcf1dd5ef2f4e720785 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:09:23 +0000 Subject: [PATCH 2074/4969] Bump com.gradle.enterprise.gradle.plugin in /examples Bumps com.gradle.enterprise.gradle.plugin from 3.10.2 to 3.10.3. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 5a4ae8c0d2e..cfb204f4b00 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.2" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.3" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" } } From 6436b1019cec2a27c029ecc28b8b53044c9e8dce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:09:25 +0000 Subject: [PATCH 2075/4969] Bump kafka-clients from 3.2.0 to 3.2.1 in /examples Bumps kafka-clients from 3.2.0 to 3.2.1. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index d69af5ceb68..c3a79d4058f 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompileOnly "org.projectlombok:lombok:1.18.24" testAnnotationProcessor "org.projectlombok:lombok:1.18.24" testImplementation 'org.testcontainers:kafka' - testImplementation 'org.apache.kafka:kafka-clients:3.2.0' + testImplementation 'org.apache.kafka:kafka-clients:3.2.1' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' From 6fcaeefcbf1bdeb3cfb5b7ec07255e3fba39580e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:09:29 +0000 Subject: [PATCH 2076/4969] Bump cucumber-junit from 7.4.1 to 7.5.0 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.4.1 to 7.5.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.4.1...v7.5.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 1bf4e1f72cb..5cf03f419fe 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.4.1' - testImplementation 'io.cucumber:cucumber-junit:7.4.1' + testImplementation 'io.cucumber:cucumber-junit:7.5.0' testImplementation 'org.testcontainers:selenium' } From eb766900d2c12168e17e9af2fc9d667e49040207 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:09:39 +0000 Subject: [PATCH 2077/4969] Bump gson from 2.9.0 to 2.9.1 in /examples Bumps [gson](https://github.com/google/gson) from 2.9.0 to 2.9.1. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.9.0...gson-parent-2.9.1) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/disque-job-queue/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 1dc3497ec42..47bf340e2eb 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.24" annotationProcessor "org.projectlombok:lombok:1.18.24" implementation 'biz.paluch.redis:spinach:0.3' - implementation 'com.google.code.gson:gson:2.9.0' + implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.mockito:mockito-all:1.10.19' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 0c4de18f3c6..1e09fbc84f0 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'redis.clients:jedis:4.2.3' - implementation 'com.google.code.gson:gson:2.9.0' + implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.11' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 6e9d7664384..94f445f5ffe 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'redis.clients:jedis:4.2.3' - implementation 'com.google.code.gson:gson:2.9.0' + implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 7ece47a44ea..fd603d515c7 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation 'redis.clients:jedis:4.2.3' - implementation 'com.google.code.gson:gson:2.9.0' + implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.36' From 57159ae6ede175c641e3afc5b7c8cd59ae15c031 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:10:19 +0000 Subject: [PATCH 2078/4969] Bump org.jetbrains.kotlin.plugin.spring in /examples Bumps [org.jetbrains.kotlin.plugin.spring](https://github.com/JetBrains/kotlin) from 1.7.0 to 1.7.10. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v1.7.10/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.7.0...v1.7.10) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.plugin.spring dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 90338ff9959..4a48c40d8bf 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.6.4" id("org.jetbrains.kotlin.jvm") version "1.7.0" - id("org.jetbrains.kotlin.plugin.spring") version "1.7.0" + id("org.jetbrains.kotlin.plugin.spring") version "1.7.10" } apply plugin: 'io.spring.dependency-management' From 9b8d2391a3eb9f30f38d1be47eadf8b3081f528d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:11:31 +0000 Subject: [PATCH 2079/4969] Bump trino-jdbc from 388 to 391 in /modules/trino Bumps trino-jdbc from 388 to 391. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index caf1f322c12..c25007bb223 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:388' + testImplementation 'io.trino:trino-jdbc:391' compileOnly 'org.jetbrains:annotations:23.0.0' } From 89283187e0b3a047a335da9d53399ba7a6c8c5e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:11:50 +0000 Subject: [PATCH 2080/4969] Bump mongodb-driver-sync from 4.6.1 to 4.7.1 in /modules/mongodb Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.6.1 to 4.7.1. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.6.1...r4.7.1) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/mongodb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index 297bcd21f3b..7f9725bf0e8 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: MongoDB" dependencies { api project(':testcontainers') - testImplementation("org.mongodb:mongodb-driver-sync:4.6.1") + testImplementation("org.mongodb:mongodb-driver-sync:4.7.1") } From bfd82f4536195abe12dde5ee4ca2c617a923603d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:11:58 +0000 Subject: [PATCH 2081/4969] Bump reactor-core from 3.4.19 to 3.4.21 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.19 to 3.4.21. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.19...v3.4.21) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 692b5ac9ce5..f51a13b9296 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.19' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.21' testFixturesImplementation 'org.assertj:assertj-core:3.23.1' } From b303688bdedcd84e8f660993591dadcc9ea5e338 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:12:07 +0000 Subject: [PATCH 2082/4969] Bump azure-cosmos from 4.32.1 to 4.33.1 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.32.1 to 4.33.1. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.32.1...azure-cosmos_4.33.1) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 5f8c6837d79..c6707401ff6 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:3.14.9' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'com.azure:azure-cosmos:4.32.1' + testImplementation 'com.azure:azure-cosmos:4.33.1' } From 9aeb0c78803af4ef061d81c3bccbc44ddb83756d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:12:15 +0000 Subject: [PATCH 2083/4969] Bump junit-jupiter-engine from 5.8.2 to 5.9.0 in /modules/hivemq Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.2...r5.9.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index aa566381d0c..b62121ce9cc 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -17,7 +17,7 @@ dependencies { testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.11") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0") } test { From bb1769c468c9dd5ca88abd4a70bca913e60f0f9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:12:21 +0000 Subject: [PATCH 2084/4969] Bump junit-jupiter-api from 5.8.2 to 5.9.0 in /modules/hivemq Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.2...r5.9.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index aa566381d0c..a30a7d30517 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -11,7 +11,7 @@ dependencies { shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") shaded("net.lingala.zip4j:zip4j:2.10.0") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") testImplementation(project(":junit-jupiter")) testImplementation("com.hivemq:hivemq-extension-sdk:4.8.2") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") From 909404b9be70970673c6e592aec72041fff9d49a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:13:32 +0000 Subject: [PATCH 2085/4969] Bump com.gradle.enterprise.gradle.plugin from 3.10.2 to 3.10.3 Bumps com.gradle.enterprise.gradle.plugin from 3.10.2 to 3.10.3. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index d4605c2ad84..b56048c1126 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.2" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.3" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" } } From 456bdcc6a22099e743d98459ce262a0a86b98ab1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:14:19 +0000 Subject: [PATCH 2086/4969] Bump google-cloud-datastore from 2.10.0 to 2.10.1 in /modules/gcloud Bumps [google-cloud-datastore](https://github.com/googleapis/java-datastore) from 2.10.0 to 2.10.1. - [Release notes](https://github.com/googleapis/java-datastore/releases) - [Changelog](https://github.com/googleapis/java-datastore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-datastore/compare/v2.10.0...v2.10.1) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-datastore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 2cabbc4cf30..d885dc11023 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:2.10.0' + testImplementation 'com.google.cloud:google-cloud-datastore:2.10.1' testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.0' testImplementation 'com.google.cloud:google-cloud-spanner:6.25.7' From 7499443fae265f702fd15a718de25c63fbdd8d07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:14:34 +0000 Subject: [PATCH 2087/4969] Bump google-cloud-pubsub from 1.120.0 to 1.120.6 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.120.0 to 1.120.6. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.120.0...v1.120.6) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 2cabbc4cf30..9c837ff5e0e 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.10.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.0' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' testImplementation 'com.google.cloud:google-cloud-spanner:6.25.7' testImplementation 'com.google.cloud:google-cloud-bigtable:2.9.0' testImplementation 'org.assertj:assertj-core:3.23.1' From 720024f1f9244b766165782ce1c1889ce35e13c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 10:30:50 +0000 Subject: [PATCH 2088/4969] Bump mysql-connector-java in /modules/junit-jupiter Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.29 to 8.0.30. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.29...8.0.30) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5bf5aa4557a..790aa394849 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' testRuntimeOnly 'org.postgresql:postgresql:42.4.0' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.29' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' } From 521eb8d8a746531415d5043cf0a02e4ad697717f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 10:31:01 +0000 Subject: [PATCH 2089/4969] Bump aws-java-sdk-sqs from 1.12.253 to 1.12.273 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.253 to 1.12.273. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.253...1.12.273) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9a29eb0e343..d754c676320 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.253' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.253' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.253' testImplementation 'software.amazon.awssdk:s3:2.17.244' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' From 04842f1559b4f8e073ac430d7b73e9bc496f44a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 10:31:14 +0000 Subject: [PATCH 2090/4969] Bump org.jetbrains.kotlin.jvm from 1.7.0 to 1.7.10 in /examples Bumps [org.jetbrains.kotlin.jvm](https://github.com/JetBrains/kotlin) from 1.7.0 to 1.7.10. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v1.7.10/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.7.0...v1.7.10) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/spring-boot-kotlin-redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 4a48c40d8bf..383491eb32d 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,6 +1,6 @@ plugins { id("org.springframework.boot") version "2.6.4" - id("org.jetbrains.kotlin.jvm") version "1.7.0" + id("org.jetbrains.kotlin.jvm") version "1.7.10" id("org.jetbrains.kotlin.plugin.spring") version "1.7.10" } From 6805a75ce7747fc09bca48cb27f8b83c07146abb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 10:31:20 +0000 Subject: [PATCH 2091/4969] Bump google-cloud-spanner from 6.25.7 to 6.27.0 in /modules/gcloud Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.25.7 to 6.27.0. - [Release notes](https://github.com/googleapis/java-spanner/releases) - [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-spanner/compare/v6.25.7...v6.27.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-spanner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 395ef1372bf..2da6136c67b 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.10.1' testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' - testImplementation 'com.google.cloud:google-cloud-spanner:6.25.7' + testImplementation 'com.google.cloud:google-cloud-spanner:6.27.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.9.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From ada9da62207c4ffa0d04804cc6a04249d412bb2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 10:41:10 +0000 Subject: [PATCH 2092/4969] Bump cucumber-java from 7.4.1 to 7.5.0 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 7.4.1 to 7.5.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.4.1...v7.5.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 5cf03f419fe..ba51bbe0d2c 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:7.4.1' + testImplementation 'io.cucumber:cucumber-java:7.5.0' testImplementation 'io.cucumber:cucumber-junit:7.5.0' testImplementation 'org.testcontainers:selenium' } From 485a743aecc0a65733d0dc2bbbb45727cf11810a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 15:00:47 +0000 Subject: [PATCH 2093/4969] Bump aws-java-sdk-logs from 1.12.253 to 1.12.273 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.253 to 1.12.273. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.253...1.12.273) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d754c676320..2c547febfb8 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.253' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.253' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.273' testImplementation 'software.amazon.awssdk:s3:2.17.244' testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } From 87265750993592ebe617be1ec885ed2e9d0580a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 15:00:48 +0000 Subject: [PATCH 2094/4969] Bump google-cloud-firestore from 3.2.0 to 3.3.0 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.2.0...v3.3.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 2da6136c67b..eeca4d49fde 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.10.1' - testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' + testImplementation 'com.google.cloud:google-cloud-firestore:3.3.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' testImplementation 'com.google.cloud:google-cloud-spanner:6.27.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.9.0' From 290818fdb13baf7d13cd9364d470ce90852c8f67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 15:00:51 +0000 Subject: [PATCH 2095/4969] Bump aws-java-sdk-s3 from 1.12.253 to 1.12.273 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.253 to 1.12.273. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.253...1.12.273) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index d754c676320..0ff951ad1b9 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.253' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.231' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.273' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.253' testImplementation 'software.amazon.awssdk:s3:2.17.244' From 1518bebe30d028a2d69014f080d4e61221aa9caa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 15:00:52 +0000 Subject: [PATCH 2096/4969] Bump google-cloud-bigtable from 2.9.0 to 2.10.1 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.9.0 to 2.10.1. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.9.0...v2.10.1) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 2da6136c67b..b96e9e5fd94 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.2.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' testImplementation 'com.google.cloud:google-cloud-spanner:6.27.0' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.9.0' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From 7c3c00e02e8d93201b5934cd2a2803f530de404a Mon Sep 17 00:00:00 2001 From: Kishan B Date: Wed, 3 Aug 2022 21:22:33 +0530 Subject: [PATCH 2097/4969] Add syntax highlighting to colima usage doc (#5673) --- docs/supported_docker_environment/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/index.md b/docs/supported_docker_environment/index.md index aa6c7b1b867..debca47e574 100644 --- a/docs/supported_docker_environment/index.md +++ b/docs/supported_docker_environment/index.md @@ -17,7 +17,7 @@ In order to run testcontainers against [colima](https://github.com/abiosoft/colima) the env vars bellow should be set -``` +```bash export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock export DOCKER_HOST="unix://${HOME}/.colima/docker.sock" ``` From c38ba11e9bd018edcd2896e234cc277552ab2c7d Mon Sep 17 00:00:00 2001 From: Erik Merkle Date: Thu, 4 Aug 2022 07:37:49 -0500 Subject: [PATCH 2098/4969] Update Cassandra driver to 4.x (#2830) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also, deprecate Driver 3.x methods and remove some driver coupling. Co-authored-by: Kevin Wittek Co-authored-by: Eddú Meléndez --- docs/modules/databases/cassandra.md | 35 +++--------------- modules/cassandra/build.gradle | 9 ++++- .../containers/CassandraContainer.java | 34 +++++++++++++++++ .../containers/CassandraContainerTest.java | 13 +++---- .../containers/CassandraDriver3Test.java | 37 +++++++++++++++++++ .../containers/CassandraDriver4Test.java | 35 ++++++++++++++++++ 6 files changed, 126 insertions(+), 37 deletions(-) create mode 100644 modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java create mode 100644 modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java diff --git a/docs/modules/databases/cassandra.md b/docs/modules/databases/cassandra.md index f7ed3094886..73f93bf203a 100644 --- a/docs/modules/databases/cassandra.md +++ b/docs/modules/databases/cassandra.md @@ -4,35 +4,12 @@ This example connects to the Cassandra Cluster, creates a keyspaces and asserts that is has been created. -=== "JUnit 4 example" - ```java - public class SomeTest { - - @Rule - public CassandraContainer cassandra = new CassandraContainer(); - - - @Test - public void test(){ - Cluster cluster = cassandra.getCluster(); - - try(Session session = cluster.connect()) { - - session.execute("CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + - "{'class':'SimpleStrategy','replication_factor':'1'};"); - - List keyspaces = session.getCluster().getMetadata().getKeyspaces(); - List filteredKeyspaces = keyspaces - .stream() - .filter(km -> km.getName().equals("test")) - .collect(Collectors.toList()); - - assertEquals(1, filteredKeyspaces.size()); - } - } - - } - ``` + +[Building CqlSession](../../../modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java) inside_block:cassandra + + +!!! warning + All methods returning instances of the Cassandra Driver's Cluster object in `CassandraContainer` have been deprecated. Providing these methods unnecessarily couples the Container to the Driver and creates potential breaking changes if the driver is updated. ## Adding this module to your project dependencies diff --git a/modules/cassandra/build.gradle b/modules/cassandra/build.gradle index a5427aaea07..b00740d09fd 100644 --- a/modules/cassandra/build.gradle +++ b/modules/cassandra/build.gradle @@ -1,6 +1,13 @@ description = "TestContainers :: Cassandra" +configurations.all { + resolutionStrategy { + force 'io.dropwizard.metrics:metrics-core:3.2.4' + } +} + dependencies { api project(":database-commons") - api "com.datastax.cassandra:cassandra-driver-core:3.7.1" + api "com.datastax.cassandra:cassandra-driver-core:3.10.0" + testImplementation 'com.datastax.oss:java-driver-core:4.8.0' } diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index 3c78743fb62..a12ac03f18d 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -11,6 +11,7 @@ import org.testcontainers.utility.MountableFile; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Optional; @@ -35,6 +36,8 @@ public class CassandraContainer> extends G public static final Integer CQL_PORT = 9042; + private static final String DEFAULT_LOCAL_DATACENTER = "datacenter1"; + private static final String CONTAINER_CONFIG_LOCATION = "/etc/cassandra"; private static final String USERNAME = "cassandra"; @@ -70,6 +73,8 @@ public CassandraContainer(DockerImageName dockerImageName) { withEnv("JVM_OPTS", "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0"); withEnv("HEAP_NEWSIZE", "128M"); withEnv("MAX_HEAP_SIZE", "1024M"); + withEnv("CASSANDRA_ENDPOINT_SNITCH", "GossipingPropertyFileSnitch"); + withEnv("CASSANDRA_DC", DEFAULT_LOCAL_DATACENTER); } @Override @@ -187,11 +192,20 @@ public String getPassword() { * Get configured Cluster * * Can be used to obtain connections to Cassandra in the container + * + * @deprecated For Cassandra driver 3.x, use {@link #getHost()} and {@link #getMappedPort(int)} with + * the driver's {@link Cluster#builder() Cluster.Builder} {@code addContactPoint(String)} and + * {@code withPort(int)} methods to create a Cluster object. For Cassandra driver 4.x, use + * {@link #getContactPoint()} and {@link #getLocalDatacenter()} with the driver's {@code CqlSession.builder()} + * {@code addContactPoint(InetSocketAddress)} and {@code withLocalDatacenter(String)} methods to create + * a Session Object. See https://docs.datastax.com/en/developer/java-driver/ for more on the driver. */ + @Deprecated public Cluster getCluster() { return getCluster(this, enableJmxReporting); } + @Deprecated public static Cluster getCluster(ContainerState containerState, boolean enableJmxReporting) { final Cluster.Builder builder = Cluster .builder() @@ -203,10 +217,30 @@ public static Cluster getCluster(ContainerState containerState, boolean enableJm return builder.build(); } + @Deprecated public static Cluster getCluster(ContainerState containerState) { return getCluster(containerState, false); } + /** + * Retrieve an {@link InetSocketAddress} for connecting to the Cassandra container via the driver. + * + * @return A InetSocketAddrss representation of this Cassandra container's host and port. + */ + public InetSocketAddress getContactPoint() { + return new InetSocketAddress(getHost(), getMappedPort(CQL_PORT)); + } + + /** + * Retrieve the Local Datacenter for connecting to the Cassandra container via the driver. + * + * @return The configured local Datacenter name. + */ + public String getLocalDatacenter() { + return getEnvMap().getOrDefault("CASSANDRA_DC", DEFAULT_LOCAL_DATACENTER); + } + + @Deprecated private DatabaseDelegate getDatabaseDelegate() { return new CassandraDatabaseDelegate(this); } diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java index 45cbba0abc7..d1ad581bcc0 100644 --- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java @@ -23,11 +23,13 @@ public class CassandraContainerTest { private static final String TEST_CLUSTER_NAME_IN_CONF = "Test Cluster Integration Test"; + private static final String BASIC_QUERY = "SELECT release_version FROM system.local"; + @Test public void testSimple() { try (CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE)) { cassandraContainer.start(); - ResultSet resultSet = performQuery(cassandraContainer, "SELECT release_version FROM system.local"); + ResultSet resultSet = performQuery(cassandraContainer, BASIC_QUERY); assertTrue("Query was not applied", resultSet.wasApplied()); assertNotNull("Result set has no release_version", resultSet.one().getString(0)); } @@ -42,7 +44,7 @@ public void testSpecificVersion() { ) ) { cassandraContainer.start(); - ResultSet resultSet = performQuery(cassandraContainer, "SELECT release_version FROM system.local"); + ResultSet resultSet = performQuery(cassandraContainer, BASIC_QUERY); assertTrue("Query was not applied", resultSet.wasApplied()); assertEquals("Cassandra has wrong version", cassandraVersion, resultSet.one().getString(0)); } @@ -107,7 +109,7 @@ public void testCassandraQueryWaitStrategy() { .waitingFor(new CassandraQueryWaitStrategy()) ) { cassandraContainer.start(); - ResultSet resultSet = performQuery(cassandraContainer, "SELECT release_version FROM system.local"); + ResultSet resultSet = performQuery(cassandraContainer, BASIC_QUERY); assertTrue("Query was not applied", resultSet.wasApplied()); } } @@ -117,10 +119,7 @@ public void testCassandraQueryWaitStrategy() { public void testCassandraGetCluster() { try (CassandraContainer cassandraContainer = new CassandraContainer<>()) { cassandraContainer.start(); - ResultSet resultSet = performQuery( - cassandraContainer.getCluster(), - "SELECT release_version FROM system.local" - ); + ResultSet resultSet = performQuery(cassandraContainer.getCluster(), BASIC_QUERY); assertTrue("Query was not applied", resultSet.wasApplied()); assertNotNull("Result set has no release_version", resultSet.one().getString(0)); } diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java new file mode 100644 index 00000000000..78f3fd2a664 --- /dev/null +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java @@ -0,0 +1,37 @@ +package org.testcontainers.containers; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import org.junit.Rule; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +public class CassandraDriver3Test { + + @Rule + public CassandraContainer cassandra = new CassandraContainer<>("cassandra:3.11.2"); + + @Test + public void testCassandraGetContactPoint() { + try ( + // cassandra { + CqlSession session = CqlSession + .builder() + .addContactPoint(this.cassandra.getContactPoint()) + .withLocalDatacenter(this.cassandra.getLocalDatacenter()) + .build() + // } + ) { + session.execute( + "CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};" + ); + + KeyspaceMetadata keyspace = session.getMetadata().getKeyspaces().get(CqlIdentifier.fromCql("test")); + + assertNotNull("Failed to create test keyspace", keyspace); + } + } +} diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java new file mode 100644 index 00000000000..3a05bc723bc --- /dev/null +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java @@ -0,0 +1,35 @@ +package org.testcontainers.containers; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import org.junit.Rule; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +public class CassandraDriver4Test { + + @Rule + public CassandraContainer cassandra = new CassandraContainer<>("cassandra:3.11.2"); + + @Test + public void testCassandraGetContactPoint() { + try ( + CqlSession session = CqlSession + .builder() + .addContactPoint(this.cassandra.getContactPoint()) + .withLocalDatacenter(this.cassandra.getLocalDatacenter()) + .build() + ) { + session.execute( + "CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};" + ); + + KeyspaceMetadata keyspace = session.getMetadata().getKeyspaces().get(CqlIdentifier.fromCql("test")); + + assertNotNull("Failed to create test keyspace", keyspace); + } + } +} From 4d2b98fca08f13f4b847776aee104e94249f52d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 4 Aug 2022 22:40:06 -0500 Subject: [PATCH 2099/4969] Add cockroachdb to issue's template --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index dc86b416e46..686086d076c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -17,6 +17,7 @@ body: - Azure - Cassandra - Clickhouse + - CockroachDB - Couchbase - DB2 - Dynalite diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index f06ea99c8ba..9ef8eafaab2 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -17,6 +17,7 @@ body: - Azure - Cassandra - Clickhouse + - CockroachDB - Couchbase - DB2 - Dynalite diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 9e79553d357..1ab2693f210 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -17,6 +17,7 @@ body: - Azure - Cassandra - Clickhouse + - CockroachDB - Couchbase - DB2 - Dynalite From ef50721d86f83c7a1c0769001f004673b12c11c2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 19:28:53 -0500 Subject: [PATCH 2100/4969] Update Gradle Wrapper to 7.5.1 (#5676) Signed-off-by: gradle-update-robot --- examples/gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 012d6d90445..b916c04dbb2 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=cb87f222c5585bd46838ad4db78463a5c5f3d336e5e2b98dc7c0c586527351c2 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ef80eb5051f..f7189a776c1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=97a52d145762adc241bad7fd18289bf7f6801e08ece6badf80402fe2b9f250b1 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionSha256Sum=db9c8211ed63f61f60292c69e80d89196f9eb36665e369e7f00ac4cc841c2219 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From cae12726c04ca80a7049b49245b8d005ac38e95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 8 Aug 2022 08:07:13 -0500 Subject: [PATCH 2101/4969] Update ryuk version to 0.3.4 (#5619) --- .../src/main/java/org/testcontainers/utility/RyukContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/RyukContainer.java b/core/src/main/java/org/testcontainers/utility/RyukContainer.java index 511e6ccac17..beed2e92c62 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukContainer.java +++ b/core/src/main/java/org/testcontainers/utility/RyukContainer.java @@ -9,7 +9,7 @@ class RyukContainer extends GenericContainer { RyukContainer() { - super("testcontainers/ryuk:0.3.3"); + super("testcontainers/ryuk:0.3.4"); withExposedPorts(8080); withCreateContainerCmdModifier(cmd -> { cmd.withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID); From e8d737513cc0c7f16ea757a6f4f2eeea7a5e602e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 8 Aug 2022 18:06:47 -0500 Subject: [PATCH 2102/4969] Move to assertj (#5679) --- config/checkstyle/checkstyle.xml | 1 - core/build.gradle | 1 - .../java/org/testcontainers/DaemonTest.java | 14 +- .../containers/ContainerStateTest.java | 4 +- ...ockerComposeContainerWithServicesTest.java | 29 +-- .../containers/DockerComposeFilesTest.java | 9 +- .../DockerComposeOverridesTest.java | 5 - .../containers/ExposedHostTest.java | 4 +- .../containers/GenericContainerTest.java | 30 +-- .../containers/NetworkTest.java | 39 ++-- ...ParsedDockerComposeFileValidationTest.java | 30 ++- .../containers/ReusabilityUnitTests.java | 5 +- .../containers/output/ContainerLogsTest.java | 15 +- .../output/ToStringConsumerTest.java | 5 +- .../ExternalPortListeningCheckTest.java | 16 +- ...InternalCommandPortListeningCheckTest.java | 9 +- .../DockerHealthcheckWaitStrategyTest.java | 7 +- .../wait/strategy/WaitAllStrategyTest.java | 51 ++--- ...temPropertyClientProviderStrategyTest.java | 21 +-- .../images/ImagePullPolicyTest.java | 6 +- .../images/builder/DockerfileBuildTest.java | 9 +- .../images/builder/DockerignoreTest.java | 18 +- .../statement/AbstractStatementTest.java | 5 +- .../junit/BaseDockerComposeTest.java | 10 +- .../junit/CopyFileToContainerTest.java | 17 +- .../junit/DependenciesTest.java | 39 ++-- .../DockerComposeContainerScalingTest.java | 4 +- .../junit/DockerComposeContainerTest.java | 35 ++-- .../DockerComposeContainerWithBuildTest.java | 24 ++- .../junit/DockerComposeErrorHandlingTest.java | 16 +- .../junit/DockerComposePassthroughTest.java | 18 +- .../junit/DockerComposeServiceTest.java | 4 +- .../junit/DockerComposeWaitStrategyTest.java | 28 +-- .../junit/DockerNetworkModeTest.java | 11 +- .../junit/DockerfileContainerTest.java | 20 +- .../testcontainers/junit/DockerfileTest.java | 4 - .../junit/FileOperationsTest.java | 19 +- .../junit/GenericContainerRuleTest.java | 134 ++++++-------- .../junit/NonExistentImagePullTest.java | 15 +- .../junit/OutputStreamTest.java | 24 ++- .../junit/OutputStreamWithTTYTest.java | 34 ++-- .../ParameterizedDockerfileContainerTest.java | 4 +- .../junit/WorkingDirectoryTest.java | 8 +- .../strategy/AbstractWaitStrategyTest.java | 11 +- .../strategy/HostPortWaitStrategyTest.java | 6 +- .../utility/AuthenticatedImagePullTest.java | 13 +- .../utility/ClasspathScannerTest.java | 16 +- .../utility/DirectoryTarResourceTest.java | 132 +++++-------- .../DockerImageNameCompatibilityTest.java | 52 ++++-- .../utility/DockerImageNameTest.java | 62 +++---- .../utility/ImageNameSubstitutorTest.java | 18 +- .../utility/LazyFutureTest.java | 22 ++- .../utility/MountableFileTest.java | 37 ++-- .../PrefixingImageNameSubstitutorTest.java | 60 +++--- .../utility/RegistryAuthLocatorTest.java | 114 +++++++----- .../utility/TestEnvironmentTest.java | 18 +- .../TestcontainersConfigurationTest.java | 174 +++++++----------- docs/examples/junit5/redis/build.gradle | 1 + .../quickstart/RedisBackedCacheIntTest.java | 4 +- .../RedisBackedCacheIntTestStep0.java | 4 +- examples/disque-job-queue/build.gradle | 2 +- .../test/java/DisqueBackedMailSenderTest.java | 26 +-- .../test/java/SingleDisqueInstanceTest.java | 31 +--- .../redis-backed-cache-testng/build.gradle | 2 +- .../src/test/java/RedisBackedCacheTest.java | 14 +- examples/redis-backed-cache/build.gradle | 2 +- .../src/test/java/RedisBackedCacheTest.java | 14 +- examples/selenium-container/build.gradle | 2 +- .../src/test/java/SeleniumContainerTest.java | 4 +- examples/settings.gradle | 1 - examples/singleton-container/build.gradle | 2 +- .../com/example/BarConcreteTestClass.java | 7 +- .../com/example/FooConcreteTestClass.java | 9 +- examples/solr-container/build.gradle | 2 +- .../test/java/com/example/SolrQueryTest.java | 12 +- examples/spring-boot/build.gradle | 1 - .../java/com/example/DemoControllerTest.java | 8 +- .../CosmosDBEmulatorContainerTest.java | 7 +- modules/clickhouse/build.gradle | 1 + .../clickhouse/SimpleClickhouseTest.java | 4 +- modules/cockroachdb/build.gradle | 1 + .../cockroachdb/SimpleCockroachDBTest.java | 16 +- .../ext/ScriptSplittingTest.java | 6 +- modules/db2/build.gradle | 1 + .../junit/db2/SimpleDb2Test.java | 8 +- modules/dynalite/build.gradle | 3 +- .../dynamodb/DynaliteContainerTest.java | 15 +- modules/elasticsearch/build.gradle | 2 +- .../ElasticsearchContainerTest.java | 96 +++++----- modules/hivemq/build.gradle | 1 + .../hivemq/ContainerWithCustomConfigIT.java | 10 +- .../ContainerWithoutPlatformExtensionsIT.java | 23 ++- .../hivemq/CreateFileInCopiedDirectoryIT.java | 6 +- ...DisableEnableExtensionFromDirectoryIT.java | 8 +- .../hivemq/DisableEnableExtensionIT.java | 14 +- .../hivemq/HiveMQExtensionTest.java | 8 +- .../hivemq/HiveMQTestContainerCore.java | 43 +++-- .../testcontainers/hivemq/PathUtilTest.java | 16 +- modules/jdbc-test/build.gradle | 5 +- .../jdbc/AbstractJDBCDriverTest.java | 48 +++-- modules/jdbc/build.gradle | 1 - .../jdbc/ConnectionUrlDriversTests.java | 10 +- .../jdbc/ConnectionUrlTest.java | 102 +++++----- .../jdbc/MissingJdbcDriverTest.java | 13 +- .../junit/jupiter/ComposeContainerTests.java | 4 +- .../junit/jupiter/MixedLifecycleTests.java | 6 +- .../jupiter/TestcontainersExtensionTests.java | 11 +- ...ntainersNestedRestartedContainerTests.java | 19 +- ...tcontainersNestedSharedContainerTests.java | 9 +- .../TestcontainersRestartBetweenTests.java | 6 +- .../TestcontainersSharedContainerTests.java | 9 +- .../jupiter/inheritance/InheritedTests.java | 14 +- .../k3s/OfficialClientK3sContainerTest.java | 5 +- modules/localstack/build.gradle | 2 +- .../containers/localstack/LegacyModeTest.java | 60 +++--- .../localstack/LocalstackContainerTest.java | 94 +++++----- .../junit/mariadb/SimpleMariaDBTest.java | 26 ++- modules/mockserver/build.gradle | 2 +- .../MockServerContainerRuleTest.java | 11 +- .../containers/MockServerContainerTest.java | 14 +- .../src/test/resources/logback-test.xml | 16 ++ .../CustomPasswordMSSQLServerTest.java | 2 +- .../CustomizableMSSQLServerTest.java | 4 +- .../mssqlserver/SimpleMSSQLServerTest.java | 10 +- .../jdbc/mysql/JDBCDriverWithPoolTest.java | 6 +- .../junit/mysql/CustomizableMysqlTest.java | 4 +- .../junit/mysql/MultiVersionMySQLTest.java | 10 +- .../junit/mysql/SimpleMySQLTest.java | 36 ++-- .../containers/Neo4jContainerTest.java | 13 +- modules/nginx/build.gradle | 2 +- .../testcontainers/junit/SimpleNginxTest.java | 11 +- .../containers/jdbc/OracleJDBCDriverTest.java | 4 +- .../containers/OrientDBContainerTest.java | 2 +- .../PostgreSQLConnectionURLTest.java | 42 ++--- .../containers/TimescaleDBContainerTest.java | 11 +- .../jdbc/DatabaseDriverShutdownTest.java | 12 +- .../jdbc/DatabaseDriverTmpfsTest.java | 9 +- .../CustomizablePostgreSQLTest.java | 4 +- .../postgresql/SimplePostgreSQLTest.java | 19 +- ...tcontainersR2DBCConnectionFactoryTest.java | 8 +- modules/selenium/build.gradle | 2 +- .../junit/BaseWebDriverContainerTest.java | 9 +- .../junit/BrowserWebDriverContainerTest.java | 18 +- .../LocalServerWebDriverContainerTest.java | 10 +- .../junit/SeleniumUtilsTest.java | 6 +- modules/toxiproxy/build.gradle | 2 +- .../containers/ToxiproxyTest.java | 93 +++++----- 147 files changed, 1265 insertions(+), 1544 deletions(-) create mode 100644 modules/mockserver/src/test/resources/logback-test.xml diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index ccb8367404c..6e73f4da4aa 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -39,7 +39,6 @@ org.mockserver.model.HttpRequest.*, org.mockserver.model.HttpResponse.*, org.rnorth.ducttape.unreliables.Unreliables.*, - org.rnorth.visibleassertions.VisibleAssertions.*, " /> diff --git a/core/build.gradle b/core/build.gradle index d32e2fc43b2..9febf2802e9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -97,7 +97,6 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation project(':test-support') diff --git a/core/src/test/java/org/testcontainers/DaemonTest.java b/core/src/test/java/org/testcontainers/DaemonTest.java index c1a1c20d60a..dd35112f781 100644 --- a/core/src/test/java/org/testcontainers/DaemonTest.java +++ b/core/src/test/java/org/testcontainers/DaemonTest.java @@ -1,7 +1,6 @@ package org.testcontainers; import org.junit.Test; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.containers.GenericContainer; import java.io.File; @@ -9,7 +8,8 @@ import java.util.Set; import java.util.stream.Collectors; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; /** * This test forks a new JVM, otherwise it's not possible to reliably diff the threads @@ -30,17 +30,13 @@ public static void main(String[] args) { Set nonDaemonThreads = threads.stream().filter(it -> !it.isDaemon()).collect(Collectors.toSet()); - if (nonDaemonThreads.isEmpty()) { - VisibleAssertions.pass("All threads marked as daemon"); - } else { + if (!nonDaemonThreads.isEmpty()) { String nonDaemonThreadNames = nonDaemonThreads .stream() .map(Thread::getName) .collect(Collectors.joining("\n", "\n", "")); - VisibleAssertions.fail( - "Expected all threads to be daemons but the following are not:\n" + nonDaemonThreadNames - ); + fail("Expected all threads to be daemons but the following are not:\n" + nonDaemonThreadNames); } } finally { if (genericContainer != null) { @@ -59,6 +55,6 @@ public void testThatAllThreadsAreDaemons() throws Exception { DaemonTest.class.getCanonicalName() ); - assertEquals(0, processBuilder.inheritIO().start().waitFor()); + assertThat(processBuilder.inheritIO().start().waitFor()).isZero(); } } diff --git a/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java index 4909e908713..d3cedc11464 100644 --- a/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java +++ b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java @@ -1,6 +1,5 @@ package org.testcontainers.containers; -import org.assertj.core.api.Assertions; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -8,6 +7,7 @@ import java.util.Collections; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,6 +44,6 @@ public void test() { when(containerState.getPortBindings()).thenReturn(Collections.singletonList(testSet)); List result = containerState.getBoundPortNumbers(); - Assertions.assertThat(result).hasSameElementsAs(expectedResult); + assertThat(result).hasSameElementsAs(expectedResult); } } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java index b7b820a3011..029e8447a81 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeContainerWithServicesTest.java @@ -1,6 +1,7 @@ package org.testcontainers.containers; import org.junit.Test; +import org.rnorth.ducttape.TimeoutException; import org.testcontainers.containers.wait.strategy.Wait; import java.io.File; @@ -9,8 +10,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; public class DockerComposeContainerWithServicesTest { @@ -92,10 +93,8 @@ public void testScaleInComposeFileIsRespected() { @Test public void testStartupTimeoutSetsTheHighestTimeout() { - assertThrows( - "We expect a timeout from the startup timeout", - org.rnorth.ducttape.TimeoutException.class, - () -> { + assertThat( + catchThrowable(() -> { try ( DockerComposeContainer compose = new DockerComposeContainer<>(SIMPLE_COMPOSE_FILE) .withServices("redis") @@ -108,8 +107,10 @@ public void testStartupTimeoutSetsTheHighestTimeout() { ) { compose.start(); } - } - ); + }) + ) + .as("We expect a timeout from the startup timeout") + .isInstanceOf(TimeoutException.class); } private void verifyStartedContainers(final DockerComposeContainer compose, final String... names) { @@ -119,16 +120,16 @@ private void verifyStartedContainers(final DockerComposeContainer compose, fi .flatMap(container -> Stream.of(container.getNames())) .collect(Collectors.toList()); - assertEquals( - "number of running services of docker-compose is the same as length of listOfServices", - names.length, - containerNames.size() - ); + assertThat(containerNames) + .as("number of running services of docker-compose is the same as length of listOfServices") + .hasSize(names.length); for (final String expectedName : names) { final long matches = containerNames.stream().filter(foundName -> foundName.endsWith(expectedName)).count(); - assertEquals("container with name starting '" + expectedName + "' should be running", 1L, matches); + assertThat(matches) + .as("container with name starting '" + expectedName + "' should be running") + .isEqualTo(1L); } } } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java index 612d249449b..41870eb593d 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java @@ -1,11 +1,12 @@ package org.testcontainers.containers; import com.google.common.collect.Lists; -import org.assertj.core.api.Assertions; import org.junit.Test; import java.io.File; +import static org.assertj.core.api.Assertions.assertThat; + public class DockerComposeFilesTest { @Test @@ -13,8 +14,7 @@ public void shouldGetDependencyImages() { DockerComposeFiles dockerComposeFiles = new DockerComposeFiles( Lists.newArrayList(new File("src/test/resources/docker-compose-imagename-parsing-v2.yml")) ); - Assertions - .assertThat(dockerComposeFiles.getDependencyImages()) + assertThat(dockerComposeFiles.getDependencyImages()) .containsExactlyInAnyOrder("postgres:latest", "redis:latest", "mysql:latest"); } @@ -26,8 +26,7 @@ public void shouldGetDependencyImagesWhenOverriding() { new File("src/test/resources/docker-compose-imagename-overriding-b.yml") ) ); - Assertions - .assertThat(dockerComposeFiles.getDependencyImages()) + assertThat(dockerComposeFiles.getDependencyImages()) .containsExactlyInAnyOrder("alpine:3.16", "redis:b", "mysql:b", "aservice:latest"); } } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java index 6207ae5ff45..50fedd3cf0f 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeOverridesTest.java @@ -16,9 +16,6 @@ import java.util.Arrays; import java.util.concurrent.TimeUnit; -import static org.rnorth.visibleassertions.VisibleAssertions.info; -import static org.rnorth.visibleassertions.VisibleAssertions.pass; - @RunWith(Parameterized.class) public class DockerComposeOverridesTest { @@ -100,11 +97,9 @@ public void test() { while (br.ready()) { String line = br.readLine(); if (line.contains(expectedEnvVar)) { - pass("Mapped environment variable was found"); return true; } } - info("Mapped environment variable was not found yet - process probably not ready"); Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); return false; } diff --git a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java index 4afddeaa5dd..5f88be90ad8 100644 --- a/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java +++ b/core/src/test/java/org/testcontainers/containers/ExposedHostTest.java @@ -13,7 +13,7 @@ import java.io.OutputStream; import java.net.InetSocketAddress; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class ExposedHostTest { @@ -95,7 +95,7 @@ protected void assertResponse(GenericContainer container, int port) { .execInContainer("wget", "-O", "-", "http://host.testcontainers.internal:" + port) .getStdout(); - assertEquals("received response", "Hello World!", response); + assertThat(response).as("received response").isEqualTo("Hello World!"); } finally { container.stop(); } diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index fdd8ac1b146..1967ad95135 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -6,7 +6,6 @@ import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Ports; -import com.google.common.primitives.Ints; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -30,10 +29,9 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.catchThrowable; public class GenericContainerTest { @@ -119,28 +117,20 @@ public void shouldOnlyPublishExposedPorts() { .map(ExposedPort::getPort) .collect(Collectors.toList()); - assertEquals( - "the exposed ports are all of those EXPOSEd by the image", - Ints.asList(8080, 8081), - exposedPorts - ); + assertThat(exposedPorts).as("the exposed ports are all of those EXPOSEd by the image").contains(8080, 8081); Map hostBindings = inspectedContainer .getHostConfig() .getPortBindings() .getBindings(); - assertEquals("only 1 port is bound on the host (published)", 1, hostBindings.size()); + assertThat(hostBindings).as("only 1 port is bound on the host (published)").hasSize(1); Integer mappedPort = container.getMappedPort(8080); - assertTrue("port 8080 is bound to a different port on the host", mappedPort != 8080); + assertThat(mappedPort != 8080).as("port 8080 is bound to a different port on the host").isTrue(); - assertThrows( - "trying to get a non-bound port mapping fails", - IllegalArgumentException.class, - () -> { - container.getMappedPort(8081); - } - ); + assertThat(catchThrowable(() -> container.getMappedPort(8081))) + .as("trying to get a non-bound port mapping fails") + .isInstanceOf(IllegalArgumentException.class); } } @@ -161,8 +151,8 @@ public void shouldWaitUntilExposedPortIsMapped() { ) { container.start(); - assertEquals("Only withExposedPort should be exposed", 1, container.getExposedPorts().size()); - assertTrue("withExposedPort should be exposed", container.getExposedPorts().contains(8080)); + assertThat(container.getExposedPorts()).as("Only withExposedPort should be exposed").hasSize(1); + assertThat(container.getExposedPorts()).as("withExposedPort should be exposed").contains(8080); } } diff --git a/core/src/test/java/org/testcontainers/containers/NetworkTest.java b/core/src/test/java/org/testcontainers/containers/NetworkTest.java index d783f95e6d1..099bef20ed7 100644 --- a/core/src/test/java/org/testcontainers/containers/NetworkTest.java +++ b/core/src/test/java/org/testcontainers/containers/NetworkTest.java @@ -7,9 +7,7 @@ import org.testcontainers.DockerClientFactory; import org.testcontainers.TestImages; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Enclosed.class) public class NetworkTest { @@ -33,7 +31,7 @@ public static class WithRules { @Test public void testNetworkSupport() throws Exception { String response = bar.execInContainer("wget", "-O", "-", "http://foo:8080").getStdout(); - assertEquals("received response", "yay", response); + assertThat(response).as("received response").isEqualTo("yay"); } } @@ -60,7 +58,7 @@ public void testNetworkSupport() throws Exception { bar.start(); String response = bar.execInContainer("wget", "-O", "-", "http://foo:8080").getStdout(); - assertEquals("received response", "yay", response); + assertThat(response).as("received response").isEqualTo("yay"); } // } } @@ -69,11 +67,11 @@ public void testNetworkSupport() throws Exception { public void testBuilder() { try (Network network = Network.builder().driver("macvlan").build()) { String id = network.getId(); - assertEquals( - "Flag is set", - "macvlan", + assertThat( DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() - ); + ) + .as("Flag is set") + .isEqualTo("macvlan"); } } @@ -83,11 +81,11 @@ public void testModifiers() { Network network = Network.builder().createNetworkCmdModifier(cmd -> cmd.withDriver("macvlan")).build() ) { String id = network.getId(); - assertEquals( - "Flag is set", - "macvlan", + assertThat( DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() - ); + ) + .as("Flag is set") + .isEqualTo("macvlan"); } } @@ -95,16 +93,13 @@ public void testModifiers() { public void testReusability() { try (Network network = Network.newNetwork()) { String firstId = network.getId(); - assertNotNull( - "Network exists", - DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(firstId).exec() - ); + assertThat(DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(firstId).exec()) + .as("Network exists") + .isNotNull(); network.close(); - assertNotEquals( - "New network created", - firstId, + assertThat( DockerClientFactory .instance() .client() @@ -112,7 +107,9 @@ public void testReusability() { .withNetworkId(network.getId()) .exec() .getId() - ); + ) + .as("New network created") + .isNotEqualTo(firstId); } } } diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java index f374018a8ef..8a41ac8d8a4 100644 --- a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -2,12 +2,12 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; -import org.assertj.core.api.Assertions; import org.junit.Test; import java.io.File; import java.util.Collections; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.entry; @@ -65,55 +65,51 @@ public void shouldIgnoreUnknownStructure() { public void shouldObtainImageNamesV1() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v1.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions - .assertThat(parsedFile.getServiceNameToImageNames()) + assertThat(parsedFile.getServiceNameToImageNames()) + .as("all defined images are found") .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), entry("custom", Sets.newHashSet("postgres")) - ) - .as("all defined images are found"); // redis, mysql from compose file, postgres from Dockerfile build + ); // redis, mysql from compose file, postgres from Dockerfile build } @Test public void shouldObtainImageNamesV2() { File file = new File("src/test/resources/docker-compose-imagename-parsing-v2.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions - .assertThat(parsedFile.getServiceNameToImageNames()) + assertThat(parsedFile.getServiceNameToImageNames()) + .as("all defined images are found") .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), entry("custom", Sets.newHashSet("postgres")) - ) - .as("all defined images are found"); + ); } @Test public void shouldObtainImageFromDockerfileBuild() { File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions - .assertThat(parsedFile.getServiceNameToImageNames()) + assertThat(parsedFile.getServiceNameToImageNames()) + .as("all defined images are found") .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), entry("custom", Sets.newHashSet("alpine:3.16")) - ) - .as("all defined images are found"); // r/ redis, mysql from compose file, alpine:3.16 from Dockerfile build + ); // r/ redis, mysql from compose file, alpine:3.16 from Dockerfile build } @Test public void shouldObtainImageFromDockerfileBuildWithContext() { File file = new File("src/test/resources/docker-compose-imagename-parsing-dockerfile-with-context.yml"); ParsedDockerComposeFile parsedFile = new ParsedDockerComposeFile(file); - Assertions - .assertThat(parsedFile.getServiceNameToImageNames()) + assertThat(parsedFile.getServiceNameToImageNames()) + .as("all defined images are found") .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), entry("custom", Sets.newHashSet("alpine:3.16")) - ) - .as("all defined images are found"); // redis, mysql from compose file, alpine:3.16 from Dockerfile build + ); // redis, mysql from compose file, alpine:3.16 from Dockerfile build } } diff --git a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java index 7aafb0149bd..04f97fef514 100644 --- a/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java +++ b/core/src/test/java/org/testcontainers/containers/ReusabilityUnitTests.java @@ -25,7 +25,6 @@ import org.mockito.Answers; import org.mockito.Mockito; import org.mockito.stubbing.Answer; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory; import org.testcontainers.TestImages; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; @@ -82,9 +81,9 @@ public static Object[][] data() { @Test public void shouldBeReusable() { if (reusable) { - VisibleAssertions.assertTrue("Is reusable", container.canBeReused()); + assertThat(container.canBeReused()).as("Is reusable").isTrue(); } else { - VisibleAssertions.assertFalse("Is not reusable", container.canBeReused()); + assertThat(container.canBeReused()).as("Is not reusable").isFalse(); } } diff --git a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java index a860b7802ec..cc3a98dba47 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ContainerLogsTest.java @@ -6,8 +6,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class ContainerLogsTest { @@ -18,7 +17,7 @@ public void getLogsReturnsAllLogsToDate() { container.start(); final String logs = container.getLogs(); - assertEquals("stdout and stderr are reflected in the returned logs", "stdout\nstderr", logs); + assertThat(logs).as("stdout and stderr are reflected in the returned logs").isEqualTo("stdout\nstderr"); } } @@ -30,8 +29,8 @@ public void getLogsContainsBothOutputTypes() { // docsGetAllLogs { final String logs = container.getLogs(); // } - assertTrue("stdout is reflected in the returned logs", logs.contains("stdout")); - assertTrue("stderr is reflected in the returned logs", logs.contains("stderr")); + assertThat(logs).as("stdout is reflected in the returned logs").contains("stdout"); + assertThat(logs).as("stderr is reflected in the returned logs").contains("stderr"); } } @@ -43,7 +42,7 @@ public void getLogsReturnsStdOutToDate() { // docsGetStdOut { final String logs = container.getLogs(OutputFrame.OutputType.STDOUT); // } - assertTrue("stdout is reflected in the returned logs", logs.contains("stdout")); + assertThat(logs).as("stdout is reflected in the returned logs").contains("stdout"); } } @@ -55,7 +54,7 @@ public void getLogsReturnsStdErrToDate() { // docsGetStdErr { final String logs = container.getLogs(OutputFrame.OutputType.STDERR); // } - assertTrue("stderr is reflected in the returned logs", logs.contains("stderr")); + assertThat(logs).as("stderr is reflected in the returned logs").contains("stderr"); } } @@ -67,7 +66,7 @@ public void getLogsForLongRunningContainer() throws InterruptedException { Thread.sleep(1000L); final String logs = container.getLogs(OutputFrame.OutputType.STDOUT); - assertTrue("stdout is reflected in the returned logs for a running container", logs.contains("seq=0")); + assertThat(logs).as("stdout is reflected in the returned logs for a running container").contains("seq=0"); } } diff --git a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java index 211b12080a0..2755f4142d4 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java @@ -1,7 +1,6 @@ package org.testcontainers.containers.output; import org.apache.commons.lang3.RandomStringUtils; -import org.assertj.core.api.Assertions; import org.junit.Test; import org.testcontainers.containers.Container.ExecResult; import org.testcontainers.containers.GenericContainer; @@ -19,7 +18,7 @@ public class ToStringConsumerTest { builder.append(' ').append(i).append(RandomStringUtils.randomAlphabetic(10000)); } LARGE_PAYLOAD = builder.toString(); - Assertions.assertThat(LARGE_PAYLOAD).doesNotContain("\n"); + assertThat(LARGE_PAYLOAD).doesNotContain("\n"); } @Test @@ -29,7 +28,7 @@ public void newlines_are_not_added_to_exec_output() throws Exception { container.start(); ExecResult build = container.execInContainer("echo", "-n", LARGE_PAYLOAD); - Assertions.assertThat(build.getStdout()).doesNotContain("\n").isEqualTo(LARGE_PAYLOAD); + assertThat(build.getStdout()).doesNotContain("\n").isEqualTo(LARGE_PAYLOAD); } } diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java index c76d2481c7c..b7d9fd5a6fa 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/ExternalPortListeningCheckTest.java @@ -4,14 +4,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; import java.net.ServerSocket; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; public class ExternalPortListeningCheckTest { @@ -44,7 +44,7 @@ public void singleListening() { final Boolean result = check.call(); - VisibleAssertions.assertTrue("ExternalPortListeningCheck identifies a single listening port", result); + assertThat(result).as("ExternalPortListeningCheck identifies a single listening port").isTrue(); } @Test @@ -56,7 +56,7 @@ public void multipleListening() { final Boolean result = check.call(); - VisibleAssertions.assertTrue("ExternalPortListeningCheck identifies multiple listening port", result); + assertThat(result).as("ExternalPortListeningCheck identifies multiple listening port").isTrue(); } @Test @@ -66,11 +66,9 @@ public void oneNotListening() { ImmutableSet.of(listeningSocket1.getLocalPort(), nonListeningSocket.getLocalPort()) ); - assertThrows( - "ExternalPortListeningCheck detects a non-listening port among many", - IllegalStateException.class, - (Runnable) check::call - ); + assertThat(catchThrowable(check::call)) + .as("ExternalPortListeningCheck detects a non-listening port among many") + .isInstanceOf(IllegalStateException.class); } @After diff --git a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java index 6f2a5d3158c..d93eb90c339 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheckTest.java @@ -7,13 +7,14 @@ import org.junit.runners.Parameterized; import org.rnorth.ducttape.TimeoutException; import org.rnorth.ducttape.unreliables.Unreliables; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.containers.GenericContainer; import org.testcontainers.images.builder.ImageFromDockerfile; import java.util.Arrays; import java.util.concurrent.TimeUnit; +import static org.assertj.core.api.Assertions.fail; + @RunWith(Parameterized.class) public class InternalCommandPortListeningCheckTest { @@ -48,8 +49,6 @@ public void singleListening() { ); Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); - - VisibleAssertions.pass("InternalCommandPortListeningCheck identifies a single listening port"); } @Test @@ -61,7 +60,7 @@ public void nonListening() { try { Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); - VisibleAssertions.fail("expected to fail"); + fail("expected to fail"); } catch (TimeoutException e) {} } @@ -73,7 +72,5 @@ public void lowAndHighPortListening() { ); Unreliables.retryUntilTrue(5, TimeUnit.SECONDS, check); - - VisibleAssertions.pass("InternalCommandPortListeningCheck identifies a low and a high port"); } } diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java index 0d102def5a9..0cbf257e9b5 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java @@ -8,7 +8,8 @@ import java.time.Duration; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; public class DockerHealthcheckWaitStrategyTest { @@ -37,6 +38,8 @@ public void startsOnceHealthy() { @Test public void containerStartFailsIfContainerIsUnhealthy() { container.withCommand("tail", "-f", "/dev/null"); - assertThrows("Container launch fails when unhealthy", ContainerLaunchException.class, container::start); + assertThat(catchThrowable(container::start)) + .as("Container launch fails when unhealthy") + .isInstanceOf(ContainerLaunchException.class); } } diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java index 2b8ba7c33ec..36facd92329 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/WaitAllStrategyTest.java @@ -10,10 +10,11 @@ import java.time.Duration; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; -import static org.rnorth.visibleassertions.VisibleAssertions.*; public class WaitAllStrategyTest { @@ -42,11 +43,11 @@ public void parentTimeoutApplies() { DummyStrategy child1 = new DummyStrategy(Duration.ofMillis(10)); child1.withStartupTimeout(Duration.ofMillis(20)); - assertEquals("withStartupTimeout directly sets the timeout", 20L, child1.startupTimeout.toMillis()); + assertThat(child1.startupTimeout.toMillis()).as("withStartupTimeout directly sets the timeout").isEqualTo(20L); new WaitAllStrategy().withStrategy(child1).withStartupTimeout(Duration.ofMillis(30)); - assertEquals("WaitAllStrategy overrides a child's timeout", 30L, child1.startupTimeout.toMillis()); + assertThat(child1.startupTimeout.toMillis()).as("WaitAllStrategy overrides a child's timeout").isEqualTo(30L); } @Test @@ -59,8 +60,12 @@ public void parentTimeoutAppliesToMultipleChildren() { new WaitAllStrategy().withStrategy(child1).withStrategy(child2).withStartupTimeout(outerWait); - assertEquals("WaitAllStrategy overrides a child's timeout (1st)", 6L, child1.startupTimeout.toMillis()); - assertEquals("WaitAllStrategy overrides a child's timeout (2nd)", 6L, child2.startupTimeout.toMillis()); + assertThat(child1.startupTimeout.toMillis()) + .as("WaitAllStrategy overrides a child's timeout (1st)") + .isEqualTo(6L); + assertThat(child2.startupTimeout.toMillis()) + .as("WaitAllStrategy overrides a child's timeout (2nd)") + .isEqualTo(6L); } @Test @@ -73,12 +78,12 @@ public void parentTimeoutAppliesToAdditionalChildren() { new WaitAllStrategy().withStrategy(child1).withStartupTimeout(outerWait).withStrategy(child2); - assertEquals("WaitAllStrategy overrides a child's timeout (1st)", 20L, child1.startupTimeout.toMillis()); - assertEquals( - "WaitAllStrategy overrides a child's timeout (2nd, additional)", - 20L, - child2.startupTimeout.toMillis() - ); + assertThat(child1.startupTimeout.toMillis()) + .as("WaitAllStrategy overrides a child's timeout (1st)") + .isEqualTo(20L); + assertThat(child2.startupTimeout.toMillis()) + .as("WaitAllStrategy overrides a child's timeout (2nd, additional)") + .isEqualTo(20L); } /* @@ -108,13 +113,13 @@ public void withoutOuterTimeoutShouldRelyOnInnerStrategies() { doNothing().when(strategy1).waitUntilReady(eq(container)); doThrow(TimeoutException.class).when(strategy2).waitUntilReady(eq(container)); - assertThrows( - "The outer strategy timeout applies", - TimeoutException.class, - () -> { + assertThat( + catchThrowable(() -> { underTest.waitUntilReady(container); - } - ); + }) + ) + .as("The outer strategy timeout applies") + .isInstanceOf(TimeoutException.class); InOrder inOrder = inOrder(strategy1, strategy2, strategy3); inOrder.verify(strategy1).waitUntilReady(any()); @@ -126,13 +131,13 @@ public void withoutOuterTimeoutShouldRelyOnInnerStrategies() { public void timeoutChangeShouldNotBePossibleWithIndividualTimeoutMode() { final WaitStrategy underTest = new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY); - assertThrows( - "Cannot change timeout for individual timeouts", - IllegalStateException.class, - () -> { + assertThat( + catchThrowable(() -> { underTest.withStartupTimeout(Duration.ofSeconds(42)); - } - ); + }) + ) + .as("Cannot change timeout for individual timeouts") + .isInstanceOf(IllegalStateException.class); } @Test diff --git a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java index b2ab27aad27..062c3d793a5 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategyTest.java @@ -2,7 +2,6 @@ import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.transport.SSLConfig; -import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -18,9 +17,7 @@ import java.nio.file.Path; import java.util.Properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -69,8 +66,8 @@ public void testWhenConfigAbsent() { EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); TransportConfig transportConfig = strategy.getTransportConfig(); - assertEquals(defaultDockerHost, transportConfig.getDockerHost()); - assertEquals(defaultSSLConfig, transportConfig.getSslConfig()); + assertThat(transportConfig.getDockerHost()).isEqualTo(defaultDockerHost); + assertThat(transportConfig.getSslConfig()).isEqualTo(defaultSSLConfig); } @Test @@ -95,8 +92,8 @@ public void testWhenDockerHostPresent() { EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); TransportConfig transportConfig = strategy.getTransportConfig(); - assertEquals("tcp://1.2.3.4:2375", transportConfig.getDockerHost().toString()); - assertEquals(defaultSSLConfig, transportConfig.getSslConfig()); + assertThat(transportConfig.getDockerHost().toString()).isEqualTo("tcp://1.2.3.4:2375"); + assertThat(transportConfig.getSslConfig()).isEqualTo(defaultSSLConfig); } @Test @@ -124,10 +121,10 @@ public void testWhenDockerHostAndSSLConfigPresent() throws IOException { EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); TransportConfig transportConfig = strategy.getTransportConfig(); - assertEquals("tcp://1.2.3.4:2375", transportConfig.getDockerHost().toString()); + assertThat(transportConfig.getDockerHost().toString()).isEqualTo("tcp://1.2.3.4:2375"); SSLConfig sslConfig = transportConfig.getSslConfig(); - Assertions.assertThat(sslConfig).extracting("dockerCertPath").isEqualTo(tempDirPath); + assertThat(sslConfig).extracting("dockerCertPath").isEqualTo(tempDirPath); } @Test @@ -142,7 +139,7 @@ public void applicableWhenIgnoringUserPropertiesAndConfigured() { System.setProperty("DOCKER_HOST", "tcp://1.2.3.4:2375"); EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); - assertTrue(strategy.isApplicable()); + assertThat(strategy.isApplicable()).isTrue(); } finally { System.setProperties(oldProperties); } @@ -157,6 +154,6 @@ public void notApplicableWhenIgnoringUserPropertiesAndNotConfigured() { EnvironmentAndSystemPropertyClientProviderStrategy strategy = new EnvironmentAndSystemPropertyClientProviderStrategy(); - assertFalse(strategy.isApplicable()); + assertThat(strategy.isApplicable()).isFalse(); } } diff --git a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java index 0b0ee5f1b70..a885c035e5c 100644 --- a/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java @@ -4,7 +4,6 @@ import org.junit.ClassRule; import org.junit.Test; import org.mockito.Mockito; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.DockerClientFactory; import org.testcontainers.DockerRegistryContainer; import org.testcontainers.containers.ContainerLaunchException; @@ -12,7 +11,7 @@ import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; public class ImagePullPolicyTest { @@ -113,11 +112,10 @@ private void expectToFailWithNotFoundException(GenericContainer container) { while (throwable.getCause() != null) { throwable = throwable.getCause(); if (throwable.getCause() instanceof NotFoundException) { - VisibleAssertions.pass("Caused by NotFoundException"); return; } } - VisibleAssertions.fail("Caused by NotFoundException"); + fail("Caused by NotFoundException"); } } diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java index 29cf4fcf6a7..c45233ea390 100644 --- a/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java @@ -9,7 +9,7 @@ import java.nio.file.Path; import java.nio.file.Paths; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Parameterized.class) public class DockerfileBuildTest { @@ -71,10 +71,9 @@ public void performTest() { container.start(); final String logs = container.getLogs(); - assertTrue( - "expected file content indicates that dockerfile build steps have been run", - logs.contains(expectedFileContent) - ); + assertThat(logs) + .as("expected file content indicates that dockerfile build steps have been run") + .contains(expectedFileContent); } } } diff --git a/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java index 513b1ce1784..8c6d288da99 100644 --- a/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/DockerignoreTest.java @@ -9,8 +9,8 @@ import java.nio.file.Path; import java.nio.file.Paths; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.rnorth.visibleassertions.VisibleAssertions.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class DockerignoreTest { @@ -45,14 +45,12 @@ public void testValidDockerignore() throws Exception { container.start(); final String logs = container.getLogs(); - assertTrue( - "Files in the container indicated the .dockerignore was not applied. Output was: " + logs, - logs.contains("should_not_be_ignored.txt") - ); - assertTrue( - "Files in the container indicated the .dockerignore was not applied. Output was: " + logs, - !logs.contains("should_be_ignored.txt") - ); + assertThat(logs) + .as("Files in the container indicated the .dockerignore was not applied. Output was: " + logs) + .contains("should_not_be_ignored.txt"); + assertThat(logs) + .as("Files in the container indicated the .dockerignore was not applied. Output was: " + logs) + .doesNotContain("should_be_ignored.txt"); } } } diff --git a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java index 69d9a1b6840..0c47d556137 100644 --- a/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java +++ b/core/src/test/java/org/testcontainers/images/builder/dockerfile/statement/AbstractStatementTest.java @@ -10,8 +10,7 @@ import java.io.InputStream; import java.util.Arrays; -import static org.rnorth.visibleassertions.VisibleAssertions.fail; -import static org.rnorth.visibleassertions.VisibleAssertions.pass; +import static org.assertj.core.api.Assertions.fail; public abstract class AbstractStatementTest { @@ -64,7 +63,5 @@ protected void assertStatement(Statement statement) { fail(failureBuilder.toString()); } - - pass(testName.getMethodName()); } } diff --git a/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java b/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java index dd62ace1fac..c1aee4d7f2b 100644 --- a/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java +++ b/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java @@ -15,9 +15,7 @@ import java.util.List; import java.util.stream.Collectors; -import static org.hamcrest.Matchers.is; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by rnorth on 21/05/2016. @@ -46,7 +44,7 @@ public void simpleTest() { jedis.incr("test"); jedis.incr("test"); - assertEquals("A redis instance defined in compose can be used in isolation", "3", jedis.get("test")); + assertThat(jedis.get("test")).as("A redis instance defined in compose can be used in isolation").isEqualTo("3"); } @Test @@ -61,7 +59,7 @@ public void secondTest() { jedis.incr("test"); jedis.incr("test"); - assertEquals("Tests use fresh container instances", "3", jedis.get("test")); + assertThat(jedis.get("test")).as("Tests use fresh container instances").isEqualTo("3"); // if these end up using the same container one of the test methods will fail. // However, @Rule creates a separate DockerComposeContainer instance per test, so this just shouldn't happen } @@ -73,7 +71,7 @@ public void captureNetworks() { @After public void verifyNoNetworks() { - assertThat("The networks", findAllNetworks(), is(existingNetworks)); + assertThat(findAllNetworks()).as("The networks").isEqualTo(existingNetworks); } private List findAllNetworks() { diff --git a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java index 7041e74912a..b139ece5410 100644 --- a/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/CopyFileToContainerTest.java @@ -10,8 +10,7 @@ import java.io.IOException; import java.util.Map; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class CopyFileToContainerTest { @@ -28,7 +27,7 @@ public void checkFileCopied() throws IOException, InterruptedException { ) { container.start(); String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); - assertTrue("file list contains the file", filesList.contains(fileName)); + assertThat(filesList).as("file list contains the file").contains(fileName); } } @@ -41,7 +40,7 @@ public void shouldUseCopyForReadOnlyClasspathResources() throws Exception { ) { container.start(); String filesList = container.execInContainer("ls", "/tmp/mappable-resource").getStdout(); - assertTrue("file list contains the file", filesList.contains(fileName)); + assertThat(filesList).as("file list contains the file").contains(fileName); } } @@ -55,11 +54,11 @@ public void shouldUseCopyOnlyWithReadOnlyClasspathResources() { .withClasspathResourceMapping(resource, "/readWrite", BindMode.READ_WRITE); Map copyMap = container.getCopyToFileContainerPathMap(); - assertTrue("uses copy for read-only", copyMap.containsValue("/readOnly")); - assertTrue("uses copy for read-only and no Selinux", copyMap.containsValue("/readOnlyNoSelinux")); + assertThat(copyMap).as("uses copy for read-only").containsValue("/readOnly"); + assertThat(copyMap).as("uses copy for read-only and no Selinux").containsValue("/readOnlyNoSelinux"); - assertFalse("uses mount for read-only with Selinux", copyMap.containsValue("/readOnlyShared")); - assertFalse("uses mount for read-write", copyMap.containsValue("/readWrite")); + assertThat(copyMap).as("uses mount for read-only with Selinux").doesNotContainValue("/readOnlyShared"); + assertThat(copyMap).as("uses mount for read-write").doesNotContainValue("/readWrite"); } @Test @@ -72,7 +71,7 @@ public void shouldCreateFoldersStructureWithCopy() throws Exception { ) { container.start(); String filesList = container.execInContainer("ls", "/a/b/c/").getStdout(); - assertTrue("file list contains the file", filesList.contains("file")); + assertThat(filesList).as("file list contains the file").contains("file"); } } } diff --git a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java index 78e55335d9a..fd58dc4335f 100644 --- a/core/src/test/java/org/testcontainers/junit/DependenciesTest.java +++ b/core/src/test/java/org/testcontainers/junit/DependenciesTest.java @@ -2,7 +2,6 @@ import lombok.Getter; import org.junit.Test; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.TestImages; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; @@ -17,6 +16,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.assertj.core.api.Assertions.assertThat; + public class DependenciesTest { @Test @@ -31,8 +32,8 @@ public void shouldWorkWithSimpleDependency() { container.start(); } - VisibleAssertions.assertEquals("Started once", 1, startable.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("Does not trigger .stop()", 0, startable.getStopInvocationCount().intValue()); + assertThat(startable.getStartInvocationCount().intValue()).as("Started once").isEqualTo(1); + assertThat(startable.getStopInvocationCount().intValue()).as("Does not trigger .stop()").isZero(); } @Test @@ -48,8 +49,8 @@ public void shouldWorkWithMutlipleDependencies() { container.start(); } - VisibleAssertions.assertEquals("Startable1 started once", 1, startable1.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("Startable2 started once", 1, startable2.getStartInvocationCount().intValue()); + assertThat(startable1.getStartInvocationCount().intValue()).as("Startable1 started once").isEqualTo(1); + assertThat(startable2.getStartInvocationCount().intValue()).as("Startable2 started once").isEqualTo(1); } @Test @@ -70,8 +71,8 @@ public void shouldStartEveryTime() { container.start(); } - VisibleAssertions.assertEquals("Started multiple times", 3, startable.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("Does not trigger .stop()", 0, startable.getStopInvocationCount().intValue()); + assertThat(startable.getStartInvocationCount().intValue()).as("Started multiple times").isEqualTo(3); + assertThat(startable.getStopInvocationCount().intValue()).as("Does not trigger .stop()").isZero(); } @Test @@ -92,17 +93,11 @@ public void shouldStartTransitiveDependencies() { container.stop(); } - VisibleAssertions.assertEquals("Root started", 1, startable.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals( - "Transitive started", - 1, - transitiveStartable.getStartInvocationCount().intValue() - ); - VisibleAssertions.assertEquals( - "Transitive of transitive started", - 1, - transitiveOfTransitiveStartable.getStartInvocationCount().intValue() - ); + assertThat(startable.getStartInvocationCount().intValue()).as("Root started").isEqualTo(1); + assertThat(transitiveStartable.getStartInvocationCount().intValue()).as("Transitive started").isEqualTo(1); + assertThat(transitiveOfTransitiveStartable.getStartInvocationCount().intValue()) + .as("Transitive of transitive started") + .isEqualTo(1); } @Test @@ -122,10 +117,10 @@ public void shouldHandleDiamondDependencies() throws Exception { Startables.deepStart(Stream.of(d)).get(1, TimeUnit.SECONDS); - VisibleAssertions.assertEquals("A started", 1, a.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("B started", 1, b.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("C started", 1, c.getStartInvocationCount().intValue()); - VisibleAssertions.assertEquals("D started", 1, d.getStartInvocationCount().intValue()); + assertThat(a.getStartInvocationCount().intValue()).as("A started").isEqualTo(1); + assertThat(b.getStartInvocationCount().intValue()).as("B started").isEqualTo(1); + assertThat(c.getStartInvocationCount().intValue()).as("C started").isEqualTo(1); + assertThat(d.getStartInvocationCount().intValue()).as("D started").isEqualTo(1); } @Test diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java index 651696696c7..dc0187f5251 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerScalingTest.java @@ -7,7 +7,7 @@ import java.io.File; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by rnorth on 08/08/2015. @@ -47,7 +47,7 @@ public void simpleTest() { for (int i = 0; i < 3; i++) { clients[i].incr("somekey"); - assertEquals("Each redis instance is separate", "1", clients[i].get("somekey")); + assertThat(clients[i].get("somekey")).as("Each redis instance is separate").isEqualTo("1"); } } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java index c49663a4e35..c610fc584af 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java @@ -12,10 +12,7 @@ import java.util.Collections; import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by rnorth on 08/08/2015. @@ -37,35 +34,31 @@ protected DockerComposeContainer getEnvironment() { @Test public void testGetServicePort() { int serviceWithInstancePort = environment.getServicePort("redis_1", REDIS_PORT); - assertNotNull("Port is set for service with instance number", serviceWithInstancePort); + assertThat(serviceWithInstancePort).as("Port is set for service with instance number").isNotNull(); int serviceWithoutInstancePort = environment.getServicePort("redis", REDIS_PORT); - assertNotNull("Port is set for service with instance number", serviceWithoutInstancePort); - assertEquals("Service ports are the same", serviceWithInstancePort, serviceWithoutInstancePort); + assertThat(serviceWithoutInstancePort).as("Port is set for service with instance number").isNotNull(); + assertThat(serviceWithoutInstancePort).as("Service ports are the same").isEqualTo(serviceWithInstancePort); } @Test public void shouldRetrieveContainerByServiceName() { String existingServiceName = "db_1"; Optional result = environment.getContainerByServiceName(existingServiceName); - assertTrue( - String.format("Container should be found by service name %s", existingServiceName), - result.isPresent() - ); - assertEquals( - "Mapped port for result container was wrong, probably wrong container found", - result.get().getExposedPorts(), - Collections.singletonList(3306) - ); + assertThat(result) + .as(String.format("Container should be found by service name %s", existingServiceName)) + .isPresent(); + assertThat(Collections.singletonList(3306)) + .as("Mapped port for result container was wrong, probably wrong container found") + .isEqualTo(result.get().getExposedPorts()); } @Test public void shouldReturnEmptyResultOnNoneExistingService() { String notExistingServiceName = "db_256"; Optional result = environment.getContainerByServiceName(notExistingServiceName); - assertFalse( - String.format("No container should be found under service name %s", notExistingServiceName), - result.isPresent() - ); + assertThat(result) + .as(String.format("No container should be found under service name %s", notExistingServiceName)) + .isNotPresent(); } @Test @@ -87,6 +80,6 @@ public void shouldCreateContainerWhenFileNotPrefixedWithPath() throws IOExceptio final DockerComposeContainer dockerComposeContainer = new DockerComposeContainer<>( filePathNotStartWithDotSlash ); - assertNotNull("Container could not be created using docker compose file", dockerComposeContainer); + assertThat(dockerComposeContainer).as("Container could not be created using docker compose file").isNotNull(); } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java index e0705a2c73b..ea7e35689d0 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerWithBuildTest.java @@ -13,7 +13,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Parameterized.class) public class DockerComposeContainerWithBuildTest { @@ -59,11 +59,13 @@ public void performTest() { builtImageName.set(imageNameForRunningContainer("_customredis_1")); final boolean isBuiltImagePresentWhileRunning = isImagePresent(builtImageName.get()); - assertEquals("the built image is present while running", true, isBuiltImagePresentWhileRunning); + assertThat(isBuiltImagePresentWhileRunning).as("the built image is present while running").isEqualTo(true); pulledImageName.set(imageNameForRunningContainer("_normalredis_1")); final boolean isPulledImagePresentWhileRunning = isImagePresent(pulledImageName.get()); - assertEquals("the pulled image is present while running", true, isPulledImagePresentWhileRunning); + assertThat(isPulledImagePresentWhileRunning) + .as("the pulled image is present while running") + .isEqualTo(true); } Unreliables.retryUntilSuccess( @@ -71,11 +73,9 @@ public void performTest() { TimeUnit.SECONDS, () -> { final boolean isBuiltImagePresentAfterRunning = isImagePresent(builtImageName.get()); - assertEquals( - "the built image is not present after running", - shouldBuiltImageBePresentAfterRunning, - isBuiltImagePresentAfterRunning - ); + assertThat(isBuiltImagePresentAfterRunning) + .as("the built image is not present after running") + .isEqualTo(shouldBuiltImageBePresentAfterRunning); return null; } ); @@ -85,11 +85,9 @@ public void performTest() { TimeUnit.SECONDS, () -> { final boolean isPulledImagePresentAfterRunning = isImagePresent(pulledImageName.get()); - assertEquals( - "the pulled image is present after running", - shouldPulledImageBePresentAfterRunning, - isPulledImagePresentAfterRunning - ); + assertThat(isPulledImagePresentAfterRunning) + .as("the pulled image is present after running") + .isEqualTo(shouldPulledImageBePresentAfterRunning); return null; } ); diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java index 51f09bdb095..63383bb7175 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeErrorHandlingTest.java @@ -1,24 +1,26 @@ package org.testcontainers.junit; import org.junit.Test; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.containers.DockerComposeContainer; import java.io.File; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + public class DockerComposeErrorHandlingTest { @Test public void simpleTest() { - VisibleAssertions.assertThrows( - "starting with an invalid docker-compose file throws an exception", - IllegalArgumentException.class, - () -> { + assertThat( + catchThrowable(() -> { DockerComposeContainer environment = new DockerComposeContainer( new File("src/test/resources/invalid-compose.yml") ) .withExposedService("something", 123); - } - ); + }) + ) + .as("starting with an invalid docker-compose file throws an exception") + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java index c026bcaa741..10a26306248 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposePassthroughTest.java @@ -13,9 +13,7 @@ import java.util.Arrays; import java.util.Objects; -import static org.hamcrest.Matchers.hasItem; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by rnorth on 11/06/2016. @@ -41,16 +39,14 @@ public void testContainerInstanceProperties() { final ContainerState container = waitStrategy.getContainer(); //check environment variable was set - assertThat( - "Environment variable set correctly", - Arrays.asList(Objects.requireNonNull(container.getContainerInfo().getConfig().getEnv())), - hasItem("bar=bar") - ); + assertThat(Arrays.asList(Objects.requireNonNull(container.getContainerInfo().getConfig().getEnv()))) + .as("Environment variable set correctly") + .containsOnlyOnce("bar=bar"); //check other container properties - assertNotNull("Container id is not null", container.getContainerId()); - assertNotNull("Port mapped", container.getMappedPort(3000)); - assertThat("Exposed Ports", container.getExposedPorts(), hasItem(3000)); + assertThat(container.getContainerId()).as("Container id is not null").isNotNull(); + assertThat(container.getMappedPort(3000)).as("Port mapped").isNotNull(); + assertThat(container.getExposedPorts()).containsExactly(3000); } /* diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java index 5e6ba4cc30f..ccca85407f3 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeServiceTest.java @@ -6,7 +6,7 @@ import java.io.File; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; public class DockerComposeServiceTest extends BaseDockerComposeTest { @@ -29,6 +29,6 @@ public void testDbIsNotStarting() { @Test public void testRedisIsStarting() { - assertNotNull("Redis server started", environment.getServicePort("redis_1", REDIS_PORT)); + assertThat(environment.getServicePort("redis_1", REDIS_PORT)).as("Redis server started").isNotNull(); } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java index a30c716964e..b110e776285 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeWaitStrategyTest.java @@ -5,7 +5,6 @@ import org.junit.Test; import org.junit.runner.Description; import org.mockito.Mockito; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitStrategy; @@ -15,6 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; +import static org.assertj.core.api.Assertions.fail; public class DockerComposeWaitStrategyTest { @@ -38,11 +38,8 @@ public void testWaitOnListeningPort() { try { environment.starting(Description.createTestDescription(Object.class, "name")); - VisibleAssertions.pass("Docker compose should start after waiting for listening port"); } catch (RuntimeException e) { - VisibleAssertions.fail( - "Docker compose should start after waiting for listening port with failed with: " + e - ); + fail("Docker compose should start after waiting for listening port with failed with: " + e); } } @@ -55,11 +52,8 @@ public void testWaitOnMultipleStrategiesPassing() { try { environment.starting(Description.createTestDescription(Object.class, "name")); - VisibleAssertions.pass("Docker compose should start after waiting for listening port"); } catch (RuntimeException e) { - VisibleAssertions.fail( - "Docker compose should start after waiting for listening port with failed with: " + e - ); + fail("Docker compose should start after waiting for listening port with failed with: " + e); } } @@ -70,11 +64,9 @@ public void testWaitingFails() { REDIS_PORT, Wait.forHttp("/test").withStartupTimeout(Duration.ofSeconds(10)) ); - VisibleAssertions.assertThrows( - "waiting on an invalid http path times out", - RuntimeException.class, - () -> environment.starting(Description.createTestDescription(Object.class, "name")) - ); + assertThat(catchThrowable(() -> environment.starting(Description.createTestDescription(Object.class, "name")))) + .as("waiting on an invalid http path times out") + .isInstanceOf(RuntimeException.class); } @Test @@ -91,11 +83,9 @@ public void testWaitOnOneOfMultipleStrategiesFailing() { ) .withTailChildContainers(true); - VisibleAssertions.assertThrows( - "waiting on one failing strategy to time out", - RuntimeException.class, - () -> environment.starting(Description.createTestDescription(Object.class, "name")) - ); + assertThat(catchThrowable(() -> environment.starting(Description.createTestDescription(Object.class, "name")))) + .as("waiting on one failing strategy to time out") + .isInstanceOf(RuntimeException.class); } @Test diff --git a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java index 7962b87e157..b048e4716fd 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java @@ -7,8 +7,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Simple tests of named network modes - more may be possible, but may not be reproducible @@ -28,8 +27,8 @@ public void testNoNetworkContainer() { container.start(); NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); - assertEquals("only one network is set", 1, networkSettings.getNetworks().size()); - assertTrue("network is 'none'", networkSettings.getNetworks().containsKey("none")); + assertThat(networkSettings.getNetworks()).as("only one network is set").hasSize(1); + assertThat(networkSettings.getNetworks()).as("network is 'none'").containsKey("none"); } } @@ -44,8 +43,8 @@ public void testHostNetworkContainer() { container.start(); NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); - assertEquals("only one network is set", 1, networkSettings.getNetworks().size()); - assertTrue("network is 'host'", networkSettings.getNetworks().containsKey("host")); + assertThat(networkSettings.getNetworks()).as("only one network is set").hasSize(1); + assertThat(networkSettings.getNetworks()).as("network is 'host'").containsKey("host"); } } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java index 715ba3f64a1..9ed143aca9c 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileContainerTest.java @@ -11,8 +11,7 @@ import java.io.IOException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Simple test case / demonstration of creating a fresh container image from a Dockerfile DSL @@ -40,15 +39,14 @@ public void simpleDslTest() throws IOException { HttpGet get = new HttpGet(address); try (CloseableHttpResponse response = httpClient.execute(get)) { - assertEquals( - "A container built from a dockerfile can run nginx as expected, and returns a good status code", - 200, - response.getStatusLine().getStatusCode() - ); - assertTrue( - "A container built from a dockerfile can run nginx as expected, and returns an expected Server header", - response.getHeaders("Server")[0].getValue().contains("nginx") - ); + assertThat(response.getStatusLine().getStatusCode()) + .as("A container built from a dockerfile can run nginx as expected, and returns a good status code") + .isEqualTo(200); + assertThat(response.getHeaders("Server")[0].getValue()) + .as( + "A container built from a dockerfile can run nginx as expected, and returns an expected Server header" + ) + .contains("nginx"); } } } diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java index df7bc417688..86292bcf9ac 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java @@ -16,8 +16,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.rnorth.visibleassertions.VisibleAssertions.pass; - public class DockerfileTest { private static final Logger LOGGER = LoggerFactory.getLogger(DockerfileTest.class); @@ -130,8 +128,6 @@ protected void verifyImage(ImageFromDockerfile image) { try { container.start(); - - pass("Should start from Dockerfile"); } finally { container.stop(); } diff --git a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java index e61721f80c4..d9655443480 100644 --- a/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java +++ b/core/src/test/java/org/testcontainers/junit/FileOperationsTest.java @@ -3,7 +3,6 @@ import com.github.dockerjava.api.exception.NotFoundException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -16,7 +15,7 @@ import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class FileOperationsTest { @@ -37,7 +36,7 @@ public void copyFileToContainerFileTest() throws Exception { alpineCopyToContainer.copyFileFromContainer("/test.txt", actualFile.getPath()); File expectedFile = new File(mountableFile.getResolvedPath()); - assertTrue("Files aren't same ", FileUtils.contentEquals(expectedFile, actualFile)); + assertThat(FileUtils.contentEquals(expectedFile, actualFile)).as("Files aren't same ").isTrue(); } } @@ -55,7 +54,7 @@ public void copyFileToContainerFolderTest() throws Exception { alpineCopyToContainer.copyFileFromContainer("/home/test_copy_to_container.txt", actualFile.getPath()); File expectedFile = new File(mountableFile.getResolvedPath()); - assertTrue("Files aren't same ", FileUtils.contentEquals(expectedFile, actualFile)); + assertThat(FileUtils.contentEquals(expectedFile, actualFile)).as("Files aren't same ").isTrue(); } } @@ -73,7 +72,7 @@ public void copyFolderToContainerFolderTest() throws Exception { alpineCopyToContainer.copyFileFromContainer("/home/test/test-resource.txt", actualFile.getPath()); File expectedFile = new File(mountableFile.getResolvedPath() + "/test-resource.txt"); - assertTrue("Files aren't same ", FileUtils.contentEquals(expectedFile, actualFile)); + assertThat(FileUtils.contentEquals(expectedFile, actualFile)).as("Files aren't same ").isTrue(); } } @@ -102,23 +101,21 @@ public void shouldCopyFileFromContainerTest() throws IOException { alpineCopyToContainer.copyFileFromContainer("/home/test_copy_to_container.txt", actualFile.getPath()); File expectedFile = new File(mountableFile.getResolvedPath()); - assertTrue("Files aren't same ", FileUtils.contentEquals(expectedFile, actualFile)); + assertThat(FileUtils.contentEquals(expectedFile, actualFile)).as("Files aren't same ").isTrue(); } } @Test public void copyFileOperationsShouldFailWhenNotStartedTest() { try (GenericContainer container = new GenericContainer<>(TestImages.ALPINE_IMAGE).withCommand("top")) { - Assertions - .assertThatThrownBy(() -> { + assertThatThrownBy(() -> { MountableFile mountableFile = MountableFile.forClasspathResource("test_copy_to_container.txt"); container.copyFileToContainer(mountableFile, "/home/test.txt"); }) .isInstanceOf(IllegalStateException.class) .hasMessageContaining("can only be used with created / running container"); - Assertions - .assertThatThrownBy(() -> { + assertThatThrownBy(() -> { container.copyFileFromContainer("/home/test_copy_to_container.txt", IOUtils::toByteArray); }) .isInstanceOf(IllegalStateException.class) @@ -137,7 +134,7 @@ public void shouldCopyFileFromExitedContainerTest() throws IOException { assertThat( container.getDockerClient().waitContainerCmd(container.getContainerId()).start().awaitStatusCode() ) - .isEqualTo(0); + .isZero(); container.copyFileFromContainer("/home/file_in_container.txt", IOUtils::toByteArray); diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index 8c696585902..4ba491d83fd 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -47,12 +47,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static org.hamcrest.Matchers.equalTo; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; /** * Tests for GenericContainerRules @@ -158,9 +154,9 @@ public static void setupContent() throws FileNotFoundException { @Test public void testIsRunning() { try (GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE).withCommand("top")) { - assertFalse("Container is not started and not running", container.isRunning()); + assertThat(container.isRunning()).as("Container is not started and not running").isFalse(); container.start(); - assertTrue("Container is started and running", container.isRunning()); + assertThat(container.isRunning()).as("Container is started and running").isTrue(); } } @@ -175,15 +171,13 @@ public void withTmpFsTest() throws Exception { // check file doesn't exist String path = "/testtmpfs/test.file"; Container.ExecResult execResult = container.execInContainer("ls", path); - assertEquals( - "tmpfs inside container works fine", - execResult.getStderr(), - "ls: /testtmpfs/test.file: No such file or directory\n" - ); + assertThat(execResult.getStderr()) + .as("tmpfs inside container works fine") + .isEqualTo("ls: /testtmpfs/test.file: No such file or directory\n"); // touch && check file does exist container.execInContainer("touch", path); execResult = container.execInContainer("ls", path); - assertEquals("tmpfs inside container works fine", execResult.getStdout(), path + "\n"); + assertThat(execResult.getStdout()).as("tmpfs inside container works fine").isEqualTo(path + "\n"); } } @@ -221,8 +215,7 @@ public void handleDelivery( channel.basicPublish(RABBIQMQ_TEST_EXCHANGE, RABBITMQ_TEST_ROUTING_KEY, null, RABBITMQ_TEST_MESSAGE.getBytes()); // check the message was received - assertTrue( - "The message was received", + assertThat( Unreliables.retryUntilSuccess( 5, TimeUnit.SECONDS, @@ -233,7 +226,9 @@ public void handleDelivery( return true; } ) - ); + ) + .as("The message was received") + .isTrue(); } @Test @@ -246,21 +241,21 @@ public void simpleMongoDbTest() { collection.insertOne(doc); Document doc2 = collection.find(new Document("name", "foo")).first(); - assertEquals("A record can be inserted into and retrieved from MongoDB", 1, doc2.get("value")); + assertThat(doc2.get("value")).as("A record can be inserted into and retrieved from MongoDB").isEqualTo(1); } @Test public void environmentAndCustomCommandTest() throws IOException { String line = getReaderForContainerPort80(alpineEnvVar).readLine(); - assertEquals("An environment variable can be passed into a command", "42", line); + assertThat(line).as("An environment variable can be passed into a command").isEqualTo("42"); } @Test public void environmentFromMapTest() throws IOException { String line = getReaderForContainerPort80(alpineEnvVarFromMap).readLine(); - assertEquals("Environment variables can be passed into a command from a map", "42 and 50", line); + assertThat(line).as("Environment variables can be passed into a command from a map").isEqualTo("42 and 50"); } @Test @@ -273,21 +268,21 @@ public void customLabelTest() { alpineCustomLabel.start(); Map labels = alpineCustomLabel.getCurrentContainerInfo().getConfig().getLabels(); - assertTrue("org.testcontainers label is present", labels.containsKey("org.testcontainers")); - assertTrue("our.custom label is present", labels.containsKey("our.custom")); - assertEquals("our.custom label value is label", labels.get("our.custom"), "label"); + assertThat(labels).as("org.testcontainers label is present").containsKey("org.testcontainers"); + assertThat(labels).as("our.custom label is present").containsKey("our.custom"); + assertThat(labels).as("our.custom label value is label").containsEntry("our.custom", "label"); } } @Test public void exceptionThrownWhenTryingToOverrideTestcontainersLabels() { - assertThrows( - "When trying to overwrite an 'org.testcontainers' label, withLabel() throws an exception", - IllegalArgumentException.class, - () -> { + assertThat( + catchThrowable(() -> { new GenericContainer<>(TestImages.ALPINE_IMAGE).withLabel("org.testcontainers.foo", "false"); - } - ); + }) + ) + .as("When trying to overwrite an 'org.testcontainers' label, withLabel() throws an exception") + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -296,32 +291,24 @@ public void customClasspathResourceMappingTest() throws IOException { // in that case this test will fail. String line = getReaderForContainerPort80(alpineClasspathResource).readLine(); - assertEquals( - "Resource on the classpath can be mapped using calls to withClasspathResourceMapping", - "FOOBAR", - line - ); + assertThat(line) + .as("Resource on the classpath can be mapped using calls to withClasspathResourceMapping") + .isEqualTo("FOOBAR"); } @Test public void customClasspathResourceMappingWithSelinuxTest() throws IOException { String line = getReaderForContainerPort80(alpineClasspathResourceSelinux).readLine(); - assertEquals( - "Resource on the classpath can be mapped using calls to withClasspathResourceMappingSelinux", - "FOOBAR", - line - ); + assertThat(line) + .as("Resource on the classpath can be mapped using calls to withClasspathResourceMappingSelinux") + .isEqualTo("FOOBAR"); } @Test public void exceptionThrownWhenMappedPortNotFound() { - assertThrows( - "When the requested port is not mapped, getMappedPort() throws an exception", - IllegalArgumentException.class, - () -> { - return redis.getMappedPort(666); - } - ); + assertThat(catchThrowable(() -> redis.getMappedPort(666))) + .as("When the requested port is not mapped, getMappedPort() throws an exception") + .isInstanceOf(IllegalArgumentException.class); } protected static void writeStringToFile(File contentFolder, String filename, String string) @@ -342,14 +329,9 @@ public void failFastWhenContainerHaltsImmediately() { .withMinimumRunningDuration(Duration.ofMillis(100)); try { - assertThrows( - "When we start a container that halts immediately, an exception is thrown", - RetryCountExceededException.class, - () -> { - failsImmediately.start(); - return null; - } - ); + assertThat(catchThrowable(failsImmediately::start)) + .as("When we start a container that halts immediately, an exception is thrown") + .isInstanceOf(RetryCountExceededException.class); // Check how long it took, to verify that we ARE bailing out early. // Want to strike a balance here; too short and this test will fail intermittently @@ -357,10 +339,9 @@ public void failFastWhenContainerHaltsImmediately() { // what we're intending to test. int allowedSecondsToFailure = GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC / 2; long completedTimeMs = System.currentTimeMillis(); - assertTrue( - "container should not take long to start up", - completedTimeMs - startingTimeMs < 1000L * allowedSecondsToFailure - ); + assertThat(completedTimeMs - startingTimeMs < 1000L * allowedSecondsToFailure) + .as("container should not take long to start up") + .isTrue(); } finally { failsImmediately.stop(); } @@ -374,11 +355,10 @@ public void testExecInContainer() throws Exception { Assume.assumeTrue(TestEnvironment.dockerExecutionDriverSupportsExec()); final GenericContainer.ExecResult result = redis.execInContainer("redis-cli", "role"); - assertTrue( - "Output for \"redis-cli role\" command should start with \"master\"", - result.getStdout().startsWith("master") - ); - assertEquals("Stderr for \"redis-cli role\" command should be empty", "", result.getStderr()); + assertThat(result.getStdout()) + .as("Output for \"redis-cli role\" command should start with \"master\"") + .startsWith("master"); + assertThat(result.getStderr()).as("Stderr for \"redis-cli role\" command should be empty").isEmpty(); // We expect to reach this point for modern Docker versions. } @@ -396,7 +376,7 @@ public void extraHostTest() throws IOException { } Matcher matcher = Pattern.compile("^192.168.1.10\\s.*somehost", Pattern.MULTILINE).matcher(hosts.toString()); - assertTrue("The hosts file of container contains extra host", matcher.find()); + assertThat(matcher.find()).as("The hosts file of container contains extra host").isTrue(); } @Test @@ -414,12 +394,10 @@ public void createContainerCmdHookTest() { ) { container.start(); - assertEquals("Name is configured", "/" + randomName, container.getContainerInfo().getName()); - assertEquals( - "Command is configured", - "[redis-server, --port, 6379]", - Arrays.toString(container.getContainerInfo().getConfig().getCmd()) - ); + assertThat(container.getContainerInfo().getName()).as("Name is configured").isEqualTo("/" + randomName); + assertThat(Arrays.toString(container.getContainerInfo().getConfig().getCmd())) + .as("Command is configured") + .isEqualTo("[redis-server, --port, 6379]"); } } @@ -439,18 +417,18 @@ private BufferedReader getReaderForContainerPort80(GenericContainer container) { @Test public void addExposedPortAfterWithExposedPortsTest() { redis.addExposedPort(8987); - assertThat("Both ports should be exposed", redis.getExposedPorts().size(), equalTo(2)); - assertTrue("withExposedPort should be exposed", redis.getExposedPorts().contains(REDIS_PORT)); - assertTrue("addExposedPort should be exposed", redis.getExposedPorts().contains(8987)); + assertThat(redis.getExposedPorts()).as("Both ports should be exposed").hasSize(2); + assertThat(redis.getExposedPorts()).as("withExposedPort should be exposed").contains(REDIS_PORT); + assertThat(redis.getExposedPorts()).as("addExposedPort should be exposed").contains(8987); } @Test public void addingExposedPortTwiceShouldNotFail() { redis.addExposedPort(8987); redis.addExposedPort(8987); - assertThat("Both ports should be exposed", redis.getExposedPorts().size(), equalTo(2)); // 2 ports = de-duplicated port 8897 and original port 6379 - assertTrue("withExposedPort should be exposed", redis.getExposedPorts().contains(REDIS_PORT)); - assertTrue("addExposedPort should be exposed", redis.getExposedPorts().contains(8987)); + assertThat(redis.getExposedPorts()).as("Both ports should be exposed").hasSize(2); // 2 ports = de-duplicated port 8897 and original port 6379 + assertThat(redis.getExposedPorts()).as("withExposedPort should be exposed").contains(REDIS_PORT); + assertThat(redis.getExposedPorts()).as("addExposedPort should be exposed").contains(8987); } @Test @@ -463,7 +441,9 @@ public void sharedMemorySetTest() { containerWithSharedMemory.start(); HostConfig hostConfig = containerWithSharedMemory.getContainerInfo().getHostConfig(); - assertEquals("Shared memory not set on container", hostConfig.getShmSize(), 42L * FileUtils.ONE_MB); + assertThat(hostConfig.getShmSize()) + .as("Shared memory not set on container") + .isEqualTo(42L * FileUtils.ONE_MB); } } } diff --git a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java index 33909e2ed27..aff9b29cbe7 100644 --- a/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java +++ b/core/src/test/java/org/testcontainers/junit/NonExistentImagePullTest.java @@ -5,7 +5,8 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; /** * Created by rnorth on 20/03/2016. @@ -14,12 +15,12 @@ public class NonExistentImagePullTest { @Test(timeout = 60_000L) public void pullingNonExistentImageFailsGracefully() { - assertThrows( - "Pulling a nonexistent container will cause an exception to be thrown", - ContainerFetchException.class, - () -> { + assertThat( + catchThrowable(() -> { new GenericContainer<>(DockerImageName.parse("testcontainers/nonexistent:latest")).getDockerImageName(); - } - ); + }) + ) + .as("Pulling a nonexistent container will cause an exception to be thrown") + .isInstanceOf(ContainerFetchException.class); } } diff --git a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java index 104fb78fe48..17b1d247cbb 100644 --- a/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java +++ b/core/src/test/java/org/testcontainers/junit/OutputStreamTest.java @@ -15,9 +15,8 @@ import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; /** * Simple test for following container output. @@ -49,10 +48,8 @@ public void testFetchStdoutWithTimeout() { container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - assertThrows( - "a TimeoutException should be thrown", - TimeoutException.class, - () -> { + assertThat( + catchThrowable(() -> { consumer.waitUntil( frame -> { return ( @@ -62,9 +59,10 @@ public void testFetchStdoutWithTimeout() { 2, TimeUnit.SECONDS ); - return true; - } - ); + }) + ) + .as("a TimeoutException should be thrown") + .isInstanceOf(TimeoutException.class); } @Test(timeout = 60_000L) @@ -102,8 +100,8 @@ public void testToStringConsumer() throws TimeoutException { waitingConsumer.waitUntilEnd(30, TimeUnit.SECONDS); String utf8String = toStringConsumer.toUtf8String(); - assertTrue("the expected first value was found", utf8String.contains("seq=1")); - assertTrue("the expected last value was found", utf8String.contains("seq=4")); - assertFalse("a non-expected value was found", utf8String.contains("seq=42")); + assertThat(utf8String).as("the expected first value was found").contains("seq=1"); + assertThat(utf8String).as("the expected last value was found").contains("seq=4"); + assertThat(utf8String).as("a non-expected value was found").doesNotContain("seq=42"); } } diff --git a/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java b/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java index a87dbef3990..c340f26d3fb 100644 --- a/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java +++ b/core/src/test/java/org/testcontainers/junit/OutputStreamWithTTYTest.java @@ -16,9 +16,8 @@ import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; @Slf4j public class OutputStreamWithTTYTest { @@ -39,7 +38,9 @@ public void testFetchStdout() throws TimeoutException { container.followOutput(consumer, OutputFrame.OutputType.STDOUT); consumer.waitUntil( - frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("home"), + frame -> { + return frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("home"); + }, 4, TimeUnit.SECONDS ); @@ -51,18 +52,21 @@ public void testFetchStdoutWithTimeout() { container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - assertThrows( - "a TimeoutException should be thrown", - TimeoutException.class, - () -> { + assertThat( + catchThrowable(() -> { consumer.waitUntil( - frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("qqq"), + frame -> { + return ( + frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().contains("qqq") + ); + }, 1, TimeUnit.SECONDS ); - return true; - } - ); + }) + ) + .as("a TimeoutException should be thrown") + .isInstanceOf(TimeoutException.class); } @Test @@ -100,8 +104,8 @@ public void testToStringConsumer() throws TimeoutException { waitingConsumer.waitUntilEnd(4, TimeUnit.SECONDS); String utf8String = toStringConsumer.toUtf8String(); - assertTrue("the expected first value was found", utf8String.contains("home")); - assertTrue("the expected last value was found", utf8String.contains("media")); - assertFalse("a non-expected value was found", utf8String.contains("qqq")); + assertThat(utf8String).as("the expected first value was found").contains("home"); + assertThat(utf8String).as("the expected last value was found").contains("media"); + assertThat(utf8String).as("a non-expected value was found").doesNotContain("qqq"); } } diff --git a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java index 7c176f14a1a..8437123f97a 100644 --- a/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java @@ -7,7 +7,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.images.builder.ImageFromDockerfile; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Simple test case / demonstration of creating a fresh container image from a Dockerfile DSL when the test @@ -52,6 +52,6 @@ public static Object[][] data() { public void simpleTest() throws Exception { final String release = container.execInContainer("cat", "/etc/alpine-release").getStdout(); - assertTrue("/etc/alpine-release starts with " + expectedVersion, release.startsWith(expectedVersion)); + assertThat(release).as("/etc/alpine-release starts with " + expectedVersion).startsWith(expectedVersion); } } diff --git a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java index 0be4022c171..05f65e1f493 100644 --- a/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java +++ b/core/src/test/java/org/testcontainers/junit/WorkingDirectoryTest.java @@ -6,7 +6,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by rnorth on 26/07/2016. @@ -23,8 +23,8 @@ public class WorkingDirectoryTest { public void checkOutput() { String listing = container.getLogs(); - assertTrue("Directory listing contains expected /etc content", listing.contains("hostname")); - assertTrue("Directory listing contains expected /etc content", listing.contains("init.d")); - assertTrue("Directory listing contains expected /etc content", listing.contains("passwd")); + assertThat(listing).as("Directory listing contains expected /etc content").contains("hostname"); + assertThat(listing).as("Directory listing contains expected /etc content").contains("init.d"); + assertThat(listing).as("Directory listing contains expected /etc content").contains("passwd"); } } diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java index 530638f0f70..45809f95627 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java @@ -3,7 +3,6 @@ import org.jetbrains.annotations.NotNull; import org.junit.Before; import org.rnorth.ducttape.RetryCountExceededException; -import org.rnorth.visibleassertions.VisibleAssertions; import org.testcontainers.TestImages; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.GenericContainer; @@ -12,6 +11,8 @@ import java.time.Duration; import java.util.concurrent.atomic.AtomicBoolean; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.junit.Assert.assertTrue; /** @@ -109,11 +110,9 @@ protected void waitUntilReadyAndTimeout(String shellCommand) { */ protected void waitUntilReadyAndTimeout(GenericContainer container) { // start() blocks until successful or timeout - VisibleAssertions.assertThrows( - "an exception is thrown when timeout occurs (" + WAIT_TIMEOUT_MILLIS + "ms)", - ContainerLaunchException.class, - container::start - ); + assertThat(catchThrowable(container::start)) + .as("an exception is thrown when timeout occurs (" + WAIT_TIMEOUT_MILLIS + "ms)") + .isInstanceOf(ContainerLaunchException.class); } /** diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java index 4b5f43a4d4b..d5a0ba6929d 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HostPortWaitStrategyTest.java @@ -8,8 +8,6 @@ import java.time.Duration; -import static org.rnorth.visibleassertions.VisibleAssertions.pass; - /** * Test wait strategy with overloaded waitingFor methods. * Other implementations of WaitStrategy are tested through backwards compatible wait strategy tests @@ -24,7 +22,5 @@ public class HostPortWaitStrategyTest { .waitingFor(Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(10))); @Test - public void testWaiting() { - pass("Container starts after waiting"); - } + public void testWaiting() {} } diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index bcf88d7be11..0e00dd87bf7 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -19,10 +19,10 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.when; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; /** * This test checks the integration between Testcontainers and an authenticated registry, but uses @@ -91,7 +91,7 @@ public void testThatAuthLocatorIsUsedForContainerCreation() { ) { container.start(); - assertTrue("container started following an authenticated pull", container.isRunning()); + assertThat(container.isRunning()).as("container started following an authenticated pull").isTrue(); } } @@ -111,7 +111,7 @@ public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { ) { container.start(); - assertTrue("container started following an authenticated pull", container.isRunning()); + assertThat(container.isRunning()).as("container started following an authenticated pull").isTrue(); } } @@ -133,10 +133,11 @@ public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { try (final DockerComposeContainer compose = new DockerComposeContainer<>(tempFile.toFile())) { compose.start(); - assertTrue( - "container started following an authenticated pull", + assertThat( compose.getContainerByServiceName("privateservice_1").map(ContainerState::isRunning).orElse(false) - ); + ) + .as("container started following an authenticated pull") + .isTrue(); } } diff --git a/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java b/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java index 4ed86e3a8fa..e775a2cd492 100644 --- a/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java +++ b/core/src/test/java/org/testcontainers/utility/ClasspathScannerTest.java @@ -10,10 +10,10 @@ import java.util.List; import java.util.stream.Collectors; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class ClasspathScannerTest { @@ -41,7 +41,7 @@ public void realClassLoaderLookupOccurs() { // look for a resource that we know exists only once final List foundURLs = ClasspathScanner.scanFor("expectedClasspathFile.txt").collect(Collectors.toList()); - assertEquals("Exactly one resource was found", 1, foundURLs.size()); + assertThat(foundURLs).as("Exactly one resource was found").hasSize(1); } @Test @@ -53,7 +53,7 @@ public void multipleResultsOnOneClassLoaderAreFound() throws IOException { final List foundURLs = ClasspathScanner .scanFor("someName", firstMockClassLoader) .collect(Collectors.toList()); - assertEquals("The expected URLs are found", Arrays.asList(FILE_A, FILE_B), foundURLs); + assertThat(foundURLs).as("The expected URLs are found").containsExactly(FILE_A, FILE_B); } @Test @@ -65,11 +65,9 @@ public void orderIsAlphabeticalForDeterminism() throws IOException { final List foundURLs = ClasspathScanner .scanFor("someName", firstMockClassLoader) .collect(Collectors.toList()); - assertEquals( - "The expected URLs are found in the expected order", - Arrays.asList(FILE_A, FILE_B, JAR_A, JAR_B), - foundURLs - ); + assertThat(foundURLs) + .as("The expected URLs are found in the expected order") + .containsExactly(FILE_A, FILE_B, JAR_A, JAR_B); } @Test @@ -92,6 +90,6 @@ public void multipleClassLoadersAreQueried() throws IOException { .scanFor("someName", firstMockClassLoader, secondMockClassLoader) .collect(Collectors.toList()); - assertEquals("The expected URLs are found", Arrays.asList(FILE_A, FILE_B, FILE_C), foundURLs); + assertThat(foundURLs).as("The expected URLs are found").containsExactly(FILE_A, FILE_B, FILE_C); } } diff --git a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java index 46fd6894a02..6215f84520b 100644 --- a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java +++ b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java @@ -1,20 +1,15 @@ package org.testcontainers.utility; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.core.IsCollectionContaining; +import org.assertj.core.api.Condition; import org.junit.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.images.builder.ImageFromDockerfile; import java.io.File; -import java.util.Arrays; +import java.util.function.Predicate; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class DirectoryTarResourceTest { @@ -40,88 +35,63 @@ public void simpleRecursiveFileTest() { final String results = container.getLogs(); - assertTrue( - "The container has a file that was copied in via a recursive copy", - results.contains("Used for DirectoryTarResourceTest") - ); + assertThat(results) + .as("The container has a file that was copied in via a recursive copy") + .contains("Used for DirectoryTarResourceTest"); } @Test public void simpleRecursiveFileWithPermissionTest() { - GenericContainer container = new GenericContainer( - new ImageFromDockerfile() - .withDockerfileFromBuilder(builder -> { - builder - .from("alpine:3.16") // - .copy("/tmp/foo", "/foo") - .cmd("ls", "-al", "/") - .build(); - }) - .withFileFromFile("/tmp/foo", new File("/mappable-resource/test-resource.txt"), 0754) - ) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); - - container.start(); - String listing = container.getLogs(); - - assertThat( - "Listing shows that file is copied with mode requested.", - Arrays.asList(listing.split("\\n")), - exactlyNItems(1, allOf(containsString("-rwxr-xr--"), containsString("foo"))) - ); + try ( + GenericContainer container = new GenericContainer( + new ImageFromDockerfile() + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.16") // + .copy("/tmp/foo", "/foo") + .cmd("ls", "-al", "/") + .build(); + }) + .withFileFromFile("/tmp/foo", new File("/mappable-resource/test-resource.txt"), 0754) + ) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + String listing = container.getLogs(); + + Predicate condition = s -> s.contains("-rwxr-xr--") && s.contains("foo"); + assertThat(listing.split("\\n")) + .as("Listing shows that file is copied with mode requested.") + .haveAtLeastOne(new Condition<>(condition, "File not found in listing")); + } } @Test public void simpleRecursiveClasspathResourceTest() { // This test combines the copying of classpath resources from JAR files with the recursive TAR approach, to allow JARed classpath resources to be copied in to an image - GenericContainer container = new GenericContainer( - new ImageFromDockerfile() - .withDockerfileFromBuilder(builder -> { - builder - .from("alpine:3.16") // - .copy("/tmp/foo", "/foo") - .cmd("ls -lRt /foo") - .build(); - }) - .withFileFromClasspath("/tmp/foo", "/recursive/dir") - ) // here we use /org/junit as a directory that really should exist on the classpath - .withStartupCheckStrategy(new OneShotStartupCheckStrategy()); - - container.start(); - - final String results = container.getLogs(); - - // ExternalResource.class is known to exist in a subdirectory of /org/junit so should be successfully copied in - assertTrue( - "The container has a file that was copied in via a recursive copy from a JAR resource", - results.contains("content.txt") - ); - } - - public static Matcher> exactlyNItems(final int n, Matcher elementMatcher) { - return new IsCollectionContaining(elementMatcher) { - @Override - protected boolean matchesSafely(Iterable collection, Description mismatchDescription) { - int count = 0; - boolean isPastFirst = false; - - for (Object item : collection) { - if (elementMatcher.matches(item)) { - count++; - } - if (isPastFirst) { - mismatchDescription.appendText(", "); - } - elementMatcher.describeMismatch(item, mismatchDescription); - isPastFirst = true; - } - - if (count != n) { - mismatchDescription.appendText(". Expected exactly " + n + " but got " + count); - } - return count == n; - } - }; + try ( + GenericContainer container = new GenericContainer( + new ImageFromDockerfile() + .withDockerfileFromBuilder(builder -> { + builder + .from("alpine:3.16") // + .copy("/tmp/foo", "/foo") + .cmd("ls -lRt /foo") + .build(); + }) + .withFileFromClasspath("/tmp/foo", "/recursive/dir") + ) // here we use /org/junit as a directory that really should exist on the classpath + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) + ) { + container.start(); + + final String results = container.getLogs(); + + // ExternalResource.class is known to exist in a subdirectory of /org/junit so should be successfully copied in + assertThat(results) + .as("The container has a file that was copied in via a recursive copy from a JAR resource") + .contains("content.txt"); + } } } diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java index f2ca26b8947..e9aac2ed475 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java @@ -4,9 +4,8 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class DockerImageNameCompatibilityTest { @@ -17,7 +16,7 @@ public class DockerImageNameCompatibilityTest { public void testPlainImage() { DockerImageName subject = DockerImageName.parse("foo"); - assertFalse("image name foo != bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar"))).as("image name foo != bar").isFalse(); } @Test @@ -29,53 +28,66 @@ public void testNoTagTreatedAsWildcard() { The test is effectively making sure that 'no tag' is treated as a wildcard */ - assertFalse("foo:4.5.6 != foo:1.2.3", subject.isCompatibleWith(DockerImageName.parse("foo:1.2.3"))); - assertTrue("foo:4.5.6 ~= foo", subject.isCompatibleWith(DockerImageName.parse("foo"))); + assertThat(subject.isCompatibleWith(DockerImageName.parse("foo:1.2.3"))).as("foo:4.5.6 != foo:1.2.3").isFalse(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("foo"))).as("foo:4.5.6 ~= foo").isTrue(); } @Test public void testImageWithAutomaticCompatibilityForFullPath() { DockerImageName subject = DockerImageName.parse("repo/foo:1.2.3"); - assertTrue("repo/foo:1.2.3 ~= repo/foo", subject.isCompatibleWith(DockerImageName.parse("repo/foo"))); + assertThat(subject.isCompatibleWith(DockerImageName.parse("repo/foo"))) + .as("repo/foo:1.2.3 ~= repo/foo") + .isTrue(); } @Test public void testImageWithClaimedCompatibility() { DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("bar"); - assertTrue("foo(bar) ~= bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); - assertFalse("foo(bar) != fizz", subject.isCompatibleWith(DockerImageName.parse("fizz"))); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar"))).as("foo(bar) ~= bar").isTrue(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("fizz"))).as("foo(bar) != fizz").isFalse(); } @Test public void testImageWithClaimedCompatibilityAndVersion() { DockerImageName subject = DockerImageName.parse("foo:1.2.3").asCompatibleSubstituteFor("bar"); - assertTrue("foo:1.2.3(bar) ~= bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar"))).as("foo:1.2.3(bar) ~= bar").isTrue(); } @Test public void testImageWithClaimedCompatibilityForFullPath() { DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("registry/repo/bar"); - assertTrue( - "foo(registry/repo/bar) ~= registry/repo/bar", - subject.isCompatibleWith(DockerImageName.parse("registry/repo/bar")) - ); - assertFalse("foo(registry/repo/bar) != repo/bar", subject.isCompatibleWith(DockerImageName.parse("repo/bar"))); - assertFalse("foo(registry/repo/bar) != bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); + assertThat(subject.isCompatibleWith(DockerImageName.parse("registry/repo/bar"))) + .as("foo(registry/repo/bar) ~= registry/repo/bar") + .isTrue(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("repo/bar"))) + .as("foo(registry/repo/bar) != repo/bar") + .isFalse(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar"))) + .as("foo(registry/repo/bar) != bar") + .isFalse(); } @Test public void testImageWithClaimedCompatibilityForVersion() { DockerImageName subject = DockerImageName.parse("foo").asCompatibleSubstituteFor("bar:1.2.3"); - assertTrue("foo(bar:1.2.3) ~= bar", subject.isCompatibleWith(DockerImageName.parse("bar"))); - assertTrue("foo(bar:1.2.3) ~= bar:1.2.3", subject.isCompatibleWith(DockerImageName.parse("bar:1.2.3"))); - assertFalse("foo(bar:1.2.3) != bar:0.0.1", subject.isCompatibleWith(DockerImageName.parse("bar:0.0.1"))); - assertFalse("foo(bar:1.2.3) != bar:2.0.0", subject.isCompatibleWith(DockerImageName.parse("bar:2.0.0"))); - assertFalse("foo(bar:1.2.3) != bar:1.2.4", subject.isCompatibleWith(DockerImageName.parse("bar:1.2.4"))); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar"))).as("foo(bar:1.2.3) ~= bar").isTrue(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar:1.2.3"))) + .as("foo(bar:1.2.3) ~= bar:1.2.3") + .isTrue(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar:0.0.1"))) + .as("foo(bar:1.2.3) != bar:0.0.1") + .isFalse(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar:2.0.0"))) + .as("foo(bar:1.2.3) != bar:2.0.0") + .isFalse(); + assertThat(subject.isCompatibleWith(DockerImageName.parse("bar:1.2.4"))) + .as("foo(bar:1.2.3) != bar:1.2.4") + .isFalse(); } @Test diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index 98fd21064ed..b1a0cbc980f 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -4,9 +4,8 @@ import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.rnorth.visibleassertions.VisibleAssertions; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Enclosed.class) public class DockerImageNameTest { @@ -122,50 +121,35 @@ public void testParsing() { canonicalName = unversionedPart + ":latest"; } - VisibleAssertions.context("For " + combined); - VisibleAssertions.context("Using single-arg constructor:", 2); - final DockerImageName imageName = DockerImageName.parse(combined); - assertEquals(combined + " has registry address: " + registry, registry, imageName.getRegistry()); - assertEquals( - combined + " has unversioned part: " + unversionedPart, - unversionedPart, - imageName.getUnversionedPart() - ); + assertThat(imageName.getRegistry()).as(combined + " has registry address: " + registry).isEqualTo(registry); + assertThat(imageName.getUnversionedPart()) + .as(combined + " has unversioned part: " + unversionedPart) + .isEqualTo(unversionedPart); if (version != null) { - assertEquals(combined + " has version part: " + version, version, imageName.getVersionPart()); + assertThat(imageName.getVersionPart()) + .as(combined + " has version part: " + version) + .isEqualTo(version); } else { - assertEquals( - combined + " has automatic 'latest' version specified", - "latest", - imageName.getVersionPart() - ); + assertThat(imageName.getVersionPart()) + .as(combined + " has automatic 'latest' version specified") + .isEqualTo("latest"); } - assertEquals( - combined + " has canonical name: " + canonicalName, - canonicalName, - imageName.asCanonicalNameString() - ); + assertThat(imageName.asCanonicalNameString()) + .as(combined + " has canonical name: " + canonicalName) + .isEqualTo(canonicalName); if (version != null) { - VisibleAssertions.context("Using two-arg constructor:", 2); - final DockerImageName imageNameFromSecondaryConstructor = new DockerImageName(unversionedPart, version); - assertEquals( - combined + " has registry address: " + registry, - registry, - imageNameFromSecondaryConstructor.getRegistry() - ); - assertEquals( - combined + " has unversioned part: " + unversionedPart, - unversionedPart, - imageNameFromSecondaryConstructor.getUnversionedPart() - ); - assertEquals( - combined + " has version part: " + version, - version, - imageNameFromSecondaryConstructor.getVersionPart() - ); + assertThat(imageNameFromSecondaryConstructor.getRegistry()) + .as(combined + " has registry address: " + registry) + .isEqualTo(registry); + assertThat(imageNameFromSecondaryConstructor.getUnversionedPart()) + .as(combined + " has unversioned part: " + unversionedPart) + .isEqualTo(unversionedPart); + assertThat(imageNameFromSecondaryConstructor.getVersionPart()) + .as(combined + " has version part: " + version) + .isEqualTo(version); } } } diff --git a/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java index f7e319a5948..5c65d9e5841 100644 --- a/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java +++ b/core/src/test/java/org/testcontainers/utility/ImageNameSubstitutorTest.java @@ -6,8 +6,8 @@ import org.junit.Test; import org.mockito.Mockito; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class ImageNameSubstitutorTest { @@ -48,11 +48,9 @@ public void simpleConfigurationTest() { final ImageNameSubstitutor imageNameSubstitutor = ImageNameSubstitutor.instance(); DockerImageName result = imageNameSubstitutor.apply(DockerImageName.parse("original")); - assertEquals( - "the image has been substituted by default then configured implementations", - "transformed-substituted-image:latest", - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("the image has been substituted by default then configured implementations") + .isEqualTo("transformed-substituted-image:latest"); } @Test @@ -62,10 +60,8 @@ public void testWorksWithoutConfiguredImplementation() { final ImageNameSubstitutor imageNameSubstitutor = ImageNameSubstitutor.instance(); DockerImageName result = imageNameSubstitutor.apply(DockerImageName.parse("original")); - assertEquals( - "the image has been substituted by default then configured implementations", - "substituted-image:latest", - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("the image has been substituted by default then configured implementations") + .isEqualTo("substituted-image:latest"); } } diff --git a/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java b/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java index 99443221805..8631bf6de19 100644 --- a/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java +++ b/core/src/test/java/org/testcontainers/utility/LazyFutureTest.java @@ -11,7 +11,8 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; public class LazyFutureTest { @@ -26,16 +27,16 @@ protected Integer resolve() { } }; - assertEquals("No resolve() invocations before get()", 0, counter.get()); - assertEquals("get() call returns proper result", 1, lazyFuture.get()); - assertEquals("resolve() was called only once after single get() call", 1, counter.get()); + assertThat(counter).as("No resolve() invocations before get()").hasValue(0); + assertThat(lazyFuture.get()).as("get() call returns proper result").isEqualTo(1); + assertThat(counter).as("resolve() was called only once after single get() call").hasValue(1); counter.incrementAndGet(); - assertEquals("result of resolve() must be cached", 1, lazyFuture.get()); + assertThat(lazyFuture.get()).as("result of resolve() must be cached").isEqualTo(1); } @Test(timeout = 5_000) - public void timeoutWorks() throws Exception { + public void timeoutWorks() { Future lazyFuture = new LazyFuture() { @Override @SneakyThrows(InterruptedException.class) @@ -45,8 +46,9 @@ protected Void resolve() { } }; - assertThrows("Should timeout", TimeoutException.class, () -> lazyFuture.get(10, TimeUnit.MILLISECONDS)); - pass("timeout works"); + assertThat(catchThrowable(() -> lazyFuture.get(10, TimeUnit.MILLISECONDS))) + .as("Should timeout") + .isInstanceOf(TimeoutException.class); } @Test(timeout = 5_000) @@ -77,6 +79,8 @@ protected Integer resolve() { latch.countDown(); } - assertEquals("All threads receives the same result", Collections.nCopies(numOfThreads, 1), task.get()); + assertThat(task.get()) + .as("All threads receives the same result") + .isEqualTo(Collections.nCopies(numOfThreads, 1)); } } diff --git a/core/src/test/java/org/testcontainers/utility/MountableFileTest.java b/core/src/test/java/org/testcontainers/utility/MountableFileTest.java index d3ff085c5de..fbfb537ef87 100644 --- a/core/src/test/java/org/testcontainers/utility/MountableFileTest.java +++ b/core/src/test/java/org/testcontainers/utility/MountableFileTest.java @@ -15,7 +15,7 @@ import java.nio.file.Path; import java.util.function.Consumer; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.assertj.core.api.Assertions.assertThat; public class MountableFileTest { @@ -68,11 +68,10 @@ public void forHostPathWithSpaces() throws Exception { performChecks(mountableFile); - assertTrue("The resolved path contains the original space", mountableFile.getResolvedPath().contains(" ")); - assertFalse( - "The resolved path does not contain an escaped space", - mountableFile.getResolvedPath().contains("\\ ") - ); + assertThat(mountableFile.getResolvedPath()).as("The resolved path contains the original space").contains(" "); + assertThat(mountableFile.getResolvedPath()) + .as("The resolved path does not contain an escaped space") + .doesNotContain("\\ "); } @Test @@ -82,11 +81,10 @@ public void forHostPathWithPlus() throws Exception { performChecks(mountableFile); - assertTrue("The resolved path contains the original space", mountableFile.getResolvedPath().contains("+")); - assertFalse( - "The resolved path does not contain an escaped space", - mountableFile.getResolvedPath().contains(" ") - ); + assertThat(mountableFile.getResolvedPath()).as("The resolved path contains the original space").contains("+"); + assertThat(mountableFile.getResolvedPath()) + .as("The resolved path does not contain an escaped space") + .doesNotContain(" "); } @Test @@ -97,7 +95,7 @@ public void forClasspathResourceWithPermission() throws Exception { ); performChecks(mountableFile); - assertEquals("Valid file mode.", BASE_FILE_MODE | TEST_FILE_MODE, mountableFile.getFileMode()); + assertThat(mountableFile.getFileMode()).as("Valid file mode.").isEqualTo(BASE_FILE_MODE | TEST_FILE_MODE); } @Test @@ -105,7 +103,7 @@ public void forHostFilePathWithPermission() throws Exception { final Path file = createTempFile("somepath"); final MountableFile mountableFile = MountableFile.forHostPath(file.toString(), TEST_FILE_MODE); performChecks(mountableFile); - assertEquals("Valid file mode.", BASE_FILE_MODE | TEST_FILE_MODE, mountableFile.getFileMode()); + assertThat(mountableFile.getFileMode()).as("Valid file mode.").isEqualTo(BASE_FILE_MODE | TEST_FILE_MODE); } @Test @@ -113,7 +111,7 @@ public void forHostDirPathWithPermission() throws Exception { final Path dir = createTempDir(); final MountableFile mountableFile = MountableFile.forHostPath(dir.toString(), TEST_FILE_MODE); performChecks(mountableFile); - assertEquals("Valid dir mode.", BASE_DIR_MODE | TEST_FILE_MODE, mountableFile.getFileMode()); + assertThat(mountableFile.getFileMode()).as("Valid dir mode.").isEqualTo(BASE_DIR_MODE | TEST_FILE_MODE); } @Test @@ -129,7 +127,7 @@ public void noTrailingSlashesInTarEntryNames() throws Exception { ArchiveEntry entry; while ((entry = tais.getNextEntry()) != null) { - assertFalse("no entries should have a trailing slash", entry.getName().endsWith("/")); + assertThat(entry.getName()).as("no entries should have a trailing slash").doesNotEndWith("/"); } } @@ -163,10 +161,9 @@ private Path createTempDir() throws IOException { private void performChecks(final MountableFile mountableFile) { final String mountablePath = mountableFile.getResolvedPath(); - assertTrue("The filesystem path '" + mountablePath + "' can be found", new File(mountablePath).exists()); - assertFalse( - "The filesystem path '" + mountablePath + "' does not contain any URL escaping", - mountablePath.contains("%20") - ); + assertThat(new File(mountablePath)).as("The filesystem path '" + mountablePath + "' can be found").exists(); + assertThat(mountablePath) + .as("The filesystem path '" + mountablePath + "' does not contain any URL escaping") + .doesNotContain("%20"); } } diff --git a/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java index 211f8e00536..04786119e36 100644 --- a/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java +++ b/core/src/test/java/org/testcontainers/utility/PrefixingImageNameSubstitutorTest.java @@ -3,11 +3,11 @@ import org.junit.Before; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; public class PrefixingImageNameSubstitutorTest { @@ -28,11 +28,9 @@ public void testHappyPath() { final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); - assertEquals( - "The prefix is applied", - "someregistry.com/our-mirror/some/image:tag", - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("The prefix is applied") + .isEqualTo("someregistry.com/our-mirror/some/image:tag"); } @Test @@ -42,7 +40,7 @@ public void hubIoRegistryIsNotChanged() { final DockerImageName result = underTest.apply(DockerImageName.parse("docker.io/some/image:tag")); - assertEquals("The prefix is applied", "docker.io/some/image:tag", result.asCanonicalNameString()); + assertThat(result.asCanonicalNameString()).as("The prefix is applied").isEqualTo("docker.io/some/image:tag"); } @Test @@ -52,7 +50,9 @@ public void hubComRegistryIsNotChanged() { final DockerImageName result = underTest.apply(DockerImageName.parse("registry.hub.docker.com/some/image:tag")); - assertEquals("The prefix is applied", "registry.hub.docker.com/some/image:tag", result.asCanonicalNameString()); + assertThat(result.asCanonicalNameString()) + .as("The prefix is applied") + .isEqualTo("registry.hub.docker.com/some/image:tag"); } @Test @@ -62,11 +62,9 @@ public void thirdPartyRegistriesNotAffected() { final DockerImageName result = underTest.apply(DockerImageName.parse("gcr.io/something/image:tag")); - assertEquals( - "The prefix is not applied if a third party registry is used", - "gcr.io/something/image:tag", - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("The prefix is not applied if a third party registry is used") + .isEqualTo("gcr.io/something/image:tag"); } @Test @@ -76,11 +74,9 @@ public void testNoDoublePrefixing() { final DockerImageName result = underTest.apply(DockerImageName.parse("someregistry.com/some/image:tag")); - assertEquals( - "The prefix is not applied if already present", - "someregistry.com/some/image:tag", - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("The prefix is not applied if already present") + .isEqualTo("someregistry.com/some/image:tag"); } @Test @@ -90,11 +86,9 @@ public void testHandlesEmptyValue() { final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); - assertEquals( - "The prefix is not applied if the env var is not set", - "some/image:tag", - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("The prefix is not applied if the env var is not set") + .isEqualTo("some/image:tag"); } @Test @@ -104,7 +98,9 @@ public void testHandlesRegistryOnlyWithTrailingSlash() { final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); - assertEquals("The prefix is applied", "someregistry.com/some/image:tag", result.asCanonicalNameString()); + assertThat(result.asCanonicalNameString()) + .as("The prefix is applied") + .isEqualTo("someregistry.com/some/image:tag"); } @Test @@ -114,11 +110,9 @@ public void testCombinesLiterallyForRegistryOnlyWithoutTrailingSlash() { final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); - assertEquals( - "The prefix is applied", - "someregistry.comsome/image:tag", // treating the prefix literally, for predictability - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("The prefix is applied") + .isEqualTo("someregistry.comsome/image:tag"); } @Test @@ -128,10 +122,8 @@ public void testCombinesLiterallyForBothPartsWithoutTrailingSlash() { final DockerImageName result = underTest.apply(DockerImageName.parse("some/image:tag")); - assertEquals( - "The prefix is applied", - "someregistry.com/our-mirrorsome/image:tag", // treating the prefix literally, for predictability - result.asCanonicalNameString() - ); + assertThat(result.asCanonicalNameString()) + .as("The prefix is applied") + .isEqualTo("someregistry.com/our-mirrorsome/image:tag"); } } diff --git a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java index 4ddfad8454f..fea7f93ed5a 100644 --- a/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java +++ b/core/src/test/java/org/testcontainers/utility/RegistryAuthLocatorTest.java @@ -11,7 +11,7 @@ import java.util.HashMap; import java.util.Map; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.assertj.core.api.Assertions.assertThat; public class RegistryAuthLocatorTest { @@ -24,13 +24,11 @@ public void lookupAuthConfigWithoutCredentials() throws URISyntaxException { new AuthConfig() ); - assertEquals( - "Default docker registry URL is set on auth config", - "https://index.docker.io/v1/", - authConfig.getRegistryAddress() - ); - assertNull("No username is set", authConfig.getUsername()); - assertNull("No password is set", authConfig.getPassword()); + assertThat(authConfig.getRegistryAddress()) + .as("Default docker registry URL is set on auth config") + .isEqualTo("https://index.docker.io/v1/"); + assertThat(authConfig.getUsername()).as("No username is set").isNull(); + assertThat(authConfig.getPassword()).as("No password is set").isNull(); } @Test @@ -42,13 +40,11 @@ public void lookupAuthConfigWithBasicAuthCredentials() throws URISyntaxException new AuthConfig() ); - assertEquals( - "Default docker registry URL is set on auth config", - "https://registry.example.com", - authConfig.getRegistryAddress() - ); - assertEquals("Username is set", "user", authConfig.getUsername()); - assertEquals("Password is set", "pass", authConfig.getPassword()); + assertThat(authConfig.getRegistryAddress()) + .as("Default docker registry URL is set on auth config") + .isEqualTo("https://registry.example.com"); + assertThat(authConfig.getUsername()).as("Username is set").isEqualTo("user"); + assertThat(authConfig.getPassword()).as("Password is set").isEqualTo("pass"); } @Test @@ -60,13 +56,11 @@ public void lookupAuthConfigWithJsonKeyCredentials() throws URISyntaxException { new AuthConfig() ); - assertEquals( - "Default docker registry URL is set on auth config", - "https://registry.example.com", - authConfig.getRegistryAddress() - ); - assertEquals("Username is set", "_json_key", authConfig.getUsername()); - assertNotNull("Password is set", authConfig.getPassword()); + assertThat(authConfig.getRegistryAddress()) + .as("Default docker registry URL is set on auth config") + .isEqualTo("https://registry.example.com"); + assertThat(authConfig.getUsername()).as("Username is set").isEqualTo("_json_key"); + assertThat(authConfig.getPassword()).as("Password is set").isNotNull(); } @Test @@ -78,9 +72,15 @@ public void lookupAuthConfigUsingStore() throws URISyntaxException { new AuthConfig() ); - assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); - assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); - assertEquals("Correct secret is obtained from a credential store", "secret", authConfig.getPassword()); + assertThat(authConfig.getRegistryAddress()) + .as("Correct server URL is obtained from a credential store") + .isEqualTo("url"); + assertThat(authConfig.getUsername()) + .as("Correct username is obtained from a credential store") + .isEqualTo("username"); + assertThat(authConfig.getPassword()) + .as("Correct secret is obtained from a credential store") + .isEqualTo("secret"); } @Test @@ -92,9 +92,15 @@ public void lookupAuthConfigUsingHelper() throws URISyntaxException { new AuthConfig() ); - assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); - assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); - assertEquals("Correct secret is obtained from a credential store", "secret", authConfig.getPassword()); + assertThat(authConfig.getRegistryAddress()) + .as("Correct server URL is obtained from a credential store") + .isEqualTo("url"); + assertThat(authConfig.getUsername()) + .as("Correct username is obtained from a credential store") + .isEqualTo("username"); + assertThat(authConfig.getPassword()) + .as("Correct secret is obtained from a credential store") + .isEqualTo("secret"); } @Test @@ -106,11 +112,9 @@ public void lookupAuthConfigUsingHelperWithToken() throws URISyntaxException { new AuthConfig() ); - assertEquals( - "Correct identitytoken is obtained from a credential store", - "secret", - authConfig.getIdentitytoken() - ); + assertThat(authConfig.getIdentitytoken()) + .as("Correct identitytoken is obtained from a credential store") + .isEqualTo("secret"); } @Test @@ -122,9 +126,15 @@ public void lookupUsingHelperEmptyAuth() throws URISyntaxException { new AuthConfig() ); - assertEquals("Correct server URL is obtained from a credential store", "url", authConfig.getRegistryAddress()); - assertEquals("Correct username is obtained from a credential store", "username", authConfig.getUsername()); - assertEquals("Correct secret is obtained from a credential store", "secret", authConfig.getPassword()); + assertThat(authConfig.getRegistryAddress()) + .as("Correct server URL is obtained from a credential store") + .isEqualTo("url"); + assertThat(authConfig.getUsername()) + .as("Correct username is obtained from a credential store") + .isEqualTo("username"); + assertThat(authConfig.getPassword()) + .as("Correct secret is obtained from a credential store") + .isEqualTo("secret"); } @Test @@ -136,9 +146,15 @@ public void lookupNonEmptyAuthWithHelper() throws URISyntaxException { new AuthConfig() ); - assertEquals("Correct server URL is obtained from a credential helper", "url", authConfig.getRegistryAddress()); - assertEquals("Correct username is obtained from a credential helper", "username", authConfig.getUsername()); - assertEquals("Correct password is obtained from a credential helper", "secret", authConfig.getPassword()); + assertThat(authConfig.getRegistryAddress()) + .as("Correct server URL is obtained from a credential helper") + .isEqualTo("url"); + assertThat(authConfig.getUsername()) + .as("Correct username is obtained from a credential helper") + .isEqualTo("username"); + assertThat(authConfig.getPassword()) + .as("Correct password is obtained from a credential helper") + .isEqualTo("secret"); } @Test @@ -152,17 +168,19 @@ public void lookupAuthConfigWithCredentialsNotFound() throws URISyntaxException DockerImageName dockerImageName = DockerImageName.parse("registry2.example.com/org/repo"); final AuthConfig authConfig = authLocator.lookupAuthConfig(dockerImageName, new AuthConfig()); - assertNull("No username should have been obtained from a credential store", authConfig.getUsername()); - assertNull("No secret should have been obtained from a credential store", authConfig.getPassword()); - assertEquals("Should have one 'credentials not found' message discovered", 1, notFoundMessagesReference.size()); + assertThat(authConfig.getUsername()) + .as("No username should have been obtained from a credential store") + .isNull(); + assertThat(authConfig.getPassword()).as("No secret should have been obtained from a credential store").isNull(); + assertThat(notFoundMessagesReference.size()) + .as("Should have one 'credentials not found' message discovered") + .isEqualTo(1); String discoveredMessage = notFoundMessagesReference.values().iterator().next(); - assertEquals( - "Not correct message discovered", - "Fake credentials not found on credentials store 'https://not.a.real.registry/url'", - discoveredMessage - ); + assertThat(discoveredMessage) + .as("Not correct message discovered") + .isEqualTo("Fake credentials not found on credentials store 'https://not.a.real.registry/url'"); } @Test @@ -172,7 +190,7 @@ public void lookupAuthConfigWithCredStoreEmpty() throws URISyntaxException { DockerImageName dockerImageName = DockerImageName.parse("registry2.example.com/org/repo"); final AuthConfig authConfig = authLocator.lookupAuthConfig(dockerImageName, new AuthConfig()); - assertNull("CredStore field will be ignored, because value is blank", authConfig.getAuth()); + assertThat(authConfig.getAuth()).as("CredStore field will be ignored, because value is blank").isNull(); } @NotNull diff --git a/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java b/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java index de97d100a39..4bd9e1b8edb 100644 --- a/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestEnvironmentTest.java @@ -2,7 +2,7 @@ import org.junit.Test; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by rnorth on 03/07/2016. @@ -11,21 +11,29 @@ public class TestEnvironmentTest { @Test public void testCompareVersionGreaterThanSameMajor() { - assertTrue("1.22 > 1.20", new ComparableVersion("1.22").compareTo(new ComparableVersion("1.20")) > 0); + assertThat(new ComparableVersion("1.22").compareTo(new ComparableVersion("1.20")) > 0) + .as("1.22 > 1.20") + .isTrue(); } @Test public void testCompareVersionEqual() { - assertTrue("1.20 == 1.20", new ComparableVersion("1.20").compareTo(new ComparableVersion("1.20")) == 0); + assertThat(new ComparableVersion("1.20")) + .as("1.20 == 1.20") + .isEqualByComparingTo(new ComparableVersion("1.20")); } @Test public void testCompareVersionGreaterThan() { - assertTrue("2.10 > 1.20", new ComparableVersion("2.10").compareTo(new ComparableVersion("1.20")) > 0); + assertThat(new ComparableVersion("2.10").compareTo(new ComparableVersion("1.20")) > 0) + .as("2.10 > 1.20") + .isTrue(); } @Test public void testCompareVersionIgnoresExcessLength() { - assertTrue("1.20 == 1.20.3", new ComparableVersion("1.20").compareTo(new ComparableVersion("1.20.3")) == 0); + assertThat(new ComparableVersion("1.20")) + .as("1.20 == 1.20.3") + .isEqualByComparingTo(new ComparableVersion("1.20.3")); } } diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index 56cbdb98a56..d51bc89348c 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -8,9 +8,7 @@ import java.util.Properties; import java.util.UUID; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class TestcontainersConfigurationTest { @@ -30,122 +28,102 @@ public void setUp() { @Test public void shouldSubstituteImageNamesFromClasspathProperties() { classpathProperties.setProperty("ryuk.container.image", "foo:version"); - assertEquals( - "an image name can be pulled from classpath properties", - DockerImageName.parse("foo:version"), - newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any")) - ); + assertThat(newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any"))) + .as("an image name can be pulled from classpath properties") + .isEqualTo(DockerImageName.parse("foo:version")); } @Test public void shouldSubstituteImageNamesFromUserProperties() { userProperties.setProperty("ryuk.container.image", "foo:version"); - assertEquals( - "an image name can be pulled from user properties", - DockerImageName.parse("foo:version"), - newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any")) - ); + assertThat(newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any"))) + .as("an image name can be pulled from user properties") + .isEqualTo(DockerImageName.parse("foo:version")); } @Test public void shouldSubstituteImageNamesFromEnvironmentVariables() { environment.put("TESTCONTAINERS_RYUK_CONTAINER_IMAGE", "foo:version"); - assertEquals( - "an image name can be pulled from an environment variable", - DockerImageName.parse("foo:version"), - newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any")) - ); + assertThat(newConfig().getConfiguredSubstituteImage(DockerImageName.parse("testcontainers/ryuk:any"))) + .as("an image name can be pulled from an environment variable") + .isEqualTo(DockerImageName.parse("foo:version")); } @Test public void shouldApplySettingsInOrder() { - assertEquals( - "precedence order for multiple sources of the same value is correct", - "default", - newConfig().getEnvVarOrProperty("key", "default") - ); + assertThat(newConfig().getEnvVarOrProperty("key", "default")) + .as("precedence order for multiple sources of the same value is correct") + .isEqualTo("default"); classpathProperties.setProperty("key", "foo"); - assertEquals( - "precedence order for multiple sources of the same value is correct", - "foo", - newConfig().getEnvVarOrProperty("key", "default") - ); + assertThat(newConfig().getEnvVarOrProperty("key", "default")) + .as("precedence order for multiple sources of the same value is correct") + .isEqualTo("foo"); userProperties.setProperty("key", "bar"); - assertEquals( - "precedence order for multiple sources of the same value is correct", - "bar", - newConfig().getEnvVarOrProperty("key", "default") - ); + assertThat(newConfig().getEnvVarOrProperty("key", "default")) + .as("precedence order for multiple sources of the same value is correct") + .isEqualTo("bar"); environment.put("TESTCONTAINERS_KEY", "baz"); - assertEquals( - "precedence order for multiple sources of the same value is correct", - "baz", - newConfig().getEnvVarOrProperty("key", "default") - ); + assertThat(newConfig().getEnvVarOrProperty("key", "default")) + .as("precedence order for multiple sources of the same value is correct") + .isEqualTo("baz"); } @Test public void shouldNotReadChecksFromClasspathProperties() { - assertFalse("checks enabled by default", newConfig().isDisableChecks()); + assertThat(newConfig().isDisableChecks()).as("checks enabled by default").isFalse(); classpathProperties.setProperty("checks.disable", "true"); - assertFalse("checks are not affected by classpath properties", newConfig().isDisableChecks()); + assertThat(newConfig().isDisableChecks()).as("checks are not affected by classpath properties").isFalse(); } @Test public void shouldReadChecksFromUserProperties() { - assertFalse("checks enabled by default", newConfig().isDisableChecks()); + assertThat(newConfig().isDisableChecks()).as("checks enabled by default").isFalse(); userProperties.setProperty("checks.disable", "true"); - assertTrue("checks disabled via user properties", newConfig().isDisableChecks()); + assertThat(newConfig().isDisableChecks()).as("checks disabled via user properties").isTrue(); } @Test public void shouldReadChecksFromEnvironment() { - assertFalse("checks enabled by default", newConfig().isDisableChecks()); + assertThat(newConfig().isDisableChecks()).as("checks enabled by default").isFalse(); userProperties.remove("checks.disable"); environment.put("TESTCONTAINERS_CHECKS_DISABLE", "true"); - assertTrue("checks disabled via env var", newConfig().isDisableChecks()); + assertThat(newConfig().isDisableChecks()).as("checks disabled via env var").isTrue(); } @Test public void shouldReadDockerSettingsFromEnvironmentWithoutTestcontainersPrefix() { userProperties.remove("docker.foo"); environment.put("DOCKER_FOO", "some value"); - assertEquals( - "reads unprefixed env vars for docker. settings", - "some value", - newConfig().getEnvVarOrUserProperty("docker.foo", "default") - ); + assertThat(newConfig().getEnvVarOrUserProperty("docker.foo", "default")) + .as("reads unprefixed env vars for docker. settings") + .isEqualTo("some value"); } @Test public void shouldNotReadDockerSettingsFromEnvironmentWithTestcontainersPrefix() { userProperties.remove("docker.foo"); environment.put("TESTCONTAINERS_DOCKER_FOO", "some value"); - assertEquals( - "reads unprefixed env vars for docker. settings", - "default", - newConfig().getEnvVarOrUserProperty("docker.foo", "default") - ); + assertThat(newConfig().getEnvVarOrUserProperty("docker.foo", "default")) + .as("reads unprefixed env vars for docker. settings") + .isEqualTo("default"); } @Test public void shouldReadDockerSettingsFromUserProperties() { environment.remove("DOCKER_FOO"); userProperties.put("docker.foo", "some value"); - assertEquals( - "reads unprefixed user properties for docker. settings", - "some value", - newConfig().getEnvVarOrUserProperty("docker.foo", "default") - ); + assertThat(newConfig().getEnvVarOrUserProperty("docker.foo", "default")) + .as("reads unprefixed user properties for docker. settings") + .isEqualTo("some value"); } @Test @@ -153,104 +131,90 @@ public void shouldNotReadDockerClientStrategyFromClasspathProperties() { String currentValue = newConfig().getDockerClientStrategyClassName(); classpathProperties.setProperty("docker.client.strategy", UUID.randomUUID().toString()); - assertEquals( - "Docker client strategy is not affected by classpath properties", - currentValue, - newConfig().getDockerClientStrategyClassName() - ); + assertThat(newConfig().getDockerClientStrategyClassName()) + .as("Docker client strategy is not affected by classpath properties") + .isEqualTo(currentValue); } @Test public void shouldReadDockerClientStrategyFromUserProperties() { userProperties.setProperty("docker.client.strategy", "foo"); - assertEquals( - "Docker client strategy is changed by user property", - "foo", - newConfig().getDockerClientStrategyClassName() - ); + assertThat(newConfig().getDockerClientStrategyClassName()) + .as("Docker client strategy is changed by user property") + .isEqualTo("foo"); } @Test public void shouldReadDockerClientStrategyFromEnvironment() { userProperties.remove("docker.client.strategy"); environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "foo"); - assertEquals( - "Docker client strategy is changed by env var", - "foo", - newConfig().getDockerClientStrategyClassName() - ); + assertThat(newConfig().getDockerClientStrategyClassName()) + .as("Docker client strategy is changed by env var") + .isEqualTo("foo"); } @Test public void shouldNotUseImplicitDockerClientStrategyWhenDockerHostAndStrategyAreBothSet() { userProperties.put("docker.client.strategy", "foo"); userProperties.put("docker.host", "tcp://1.2.3.4:5678"); - assertEquals( - "Docker client strategy is can be explicitly set", - "foo", - newConfig().getDockerClientStrategyClassName() - ); + assertThat(newConfig().getDockerClientStrategyClassName()) + .as("Docker client strategy is can be explicitly set") + .isEqualTo("foo"); userProperties.remove("docker.client.strategy"); environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "bar"); userProperties.put("docker.client.strategy", "foo"); - assertEquals( - "Docker client strategy is can be explicitly set", - "bar", - newConfig().getDockerClientStrategyClassName() - ); + assertThat(newConfig().getDockerClientStrategyClassName()) + .as("Docker client strategy is can be explicitly set") + .isEqualTo("bar"); environment.put("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY", "bar"); userProperties.remove("docker.client.strategy"); - assertEquals( - "Docker client strategy is can be explicitly set", - "bar", - newConfig().getDockerClientStrategyClassName() - ); + assertThat(newConfig().getDockerClientStrategyClassName()) + .as("Docker client strategy is can be explicitly set") + .isEqualTo("bar"); environment.remove("TESTCONTAINERS_DOCKER_CLIENT_STRATEGY"); userProperties.put("docker.client.strategy", "foo"); - assertEquals( - "Docker client strategy is can be explicitly set", - "foo", - newConfig().getDockerClientStrategyClassName() - ); + assertThat(newConfig().getDockerClientStrategyClassName()) + .as("Docker client strategy is can be explicitly set") + .isEqualTo("foo"); } @Test public void shouldNotReadReuseFromClasspathProperties() { - assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); + assertThat(newConfig().environmentSupportsReuse()).as("no reuse by default").isFalse(); classpathProperties.setProperty("testcontainers.reuse.enable", "true"); - assertFalse("reuse is not affected by classpath properties", newConfig().environmentSupportsReuse()); + assertThat(newConfig().environmentSupportsReuse()) + .as("reuse is not affected by classpath properties") + .isFalse(); } @Test public void shouldReadReuseFromUserProperties() { - assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); + assertThat(newConfig().environmentSupportsReuse()).as("no reuse by default").isFalse(); userProperties.setProperty("testcontainers.reuse.enable", "true"); - assertTrue("reuse enabled via user property", newConfig().environmentSupportsReuse()); + assertThat(newConfig().environmentSupportsReuse()).as("reuse enabled via user property").isTrue(); } @Test public void shouldReadReuseFromEnvironment() { - assertFalse("no reuse by default", newConfig().environmentSupportsReuse()); + assertThat(newConfig().environmentSupportsReuse()).as("no reuse by default").isFalse(); userProperties.remove("testcontainers.reuse.enable"); environment.put("TESTCONTAINERS_REUSE_ENABLE", "true"); - assertTrue("reuse enabled via env var", newConfig().environmentSupportsReuse()); + assertThat(newConfig().environmentSupportsReuse()).as("reuse enabled via env var").isTrue(); } @Test public void shouldTrimImageNames() { userProperties.setProperty("ryuk.container.image", " testcontainers/ryuk:0.3.2 "); - assertEquals( - "trailing whitespace was not removed from image name property", - "testcontainers/ryuk:0.3.2", - newConfig().getRyukImage() - ); + assertThat(newConfig().getRyukImage()) + .as("trailing whitespace was not removed from image name property") + .isEqualTo("testcontainers/ryuk:0.3.2"); } private TestcontainersConfiguration newConfig() { diff --git a/docs/examples/junit5/redis/build.gradle b/docs/examples/junit5/redis/build.gradle index 16f0d5bc598..72b943adc23 100644 --- a/docs/examples/junit5/redis/build.gradle +++ b/docs/examples/junit5/redis/build.gradle @@ -8,6 +8,7 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.2" testImplementation project(":testcontainers") testImplementation project(":junit-jupiter") + testImplementation 'org.assertj:assertj-core:3.23.1' } test { diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index 59d92210549..2c5f4baef67 100644 --- a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -7,7 +7,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; // class { @Testcontainers @@ -36,7 +36,7 @@ public void testSimplePutAndGet() { underTest.put("test", "example"); String retrieved = underTest.get("test"); - assertEquals("example", retrieved); + assertThat(retrieved).isEqualTo("example"); } } // } diff --git a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java index d9f889a8943..e1f3c3efbe8 100644 --- a/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java +++ b/docs/examples/junit5/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @Disabled("This test class is deliberately invalid, as it relies on a non-existent local Redis") public class RedisBackedCacheIntTestStep0 { @@ -22,6 +22,6 @@ public void testSimplePutAndGet() { underTest.put("test", "example"); String retrieved = underTest.get("test"); - assertEquals("example", retrieved); + assertThat(retrieved).isEqualTo("example"); } } diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle index 47bf340e2eb..6c7a453c3e9 100644 --- a/examples/disque-job-queue/build.gradle +++ b/examples/disque-job-queue/build.gradle @@ -15,5 +15,5 @@ dependencies { testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java b/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java index 4da6201eecb..dfbab3f9e6a 100644 --- a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java +++ b/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java @@ -6,15 +6,13 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.context; -import static org.rnorth.visibleassertions.VisibleAssertions.info; /** * Created by rnorth on 03/01/2016. @@ -35,14 +33,11 @@ public class DisqueBackedMailSenderTest { @Before public void setup() { - context(""); disqueClient = new DisqueClient(DisqueURI.create(container.getHost(), container.getMappedPort(7711))); mockMailApiClient = mock(MailApiClient.class); service = new DisqueBackedMailSenderService(disqueClient, mockMailApiClient); - info("Initialized a fresh Disque instance and service instance"); - dummyMessage1 = new MailMessage("Dummy Message 1", "bob@example.com", "Test body"); dummyMessage2 = new MailMessage("Dummy Message 2", "bob@example.com", "Test body"); dummyMessage3 = new MailMessage("Dummy Message 3", "bob@example.com", "Test body"); @@ -69,28 +64,23 @@ public void testRetryOnFailure() throws Exception { service.enqueueMessage(dummyMessage2); service.enqueueMessage(dummyMessage3); - info("Message 1 will fail to send on the first attempt"); when(mockMailApiClient.send(eq(dummyMessage1))).thenThrow(MailApiClient.MailSendException.class).thenReturn(true); when(mockMailApiClient.send(eq(dummyMessage2))).thenReturn(true); when(mockMailApiClient.send(eq(dummyMessage3))).thenReturn(true); MailSenderService.Result result; - context("Simulating sending messages"); - context("First sending attempt", 4); + result = service.doScheduledSend(); - assertEquals("2 messages were 'sent' successfully", 2, result.successfulCount); - assertEquals("1 messages failed", 1, result.failedCount); + assertThat(result.successfulCount).as("2 messages were 'sent' successfully").isEqualTo(2); + assertThat(result.failedCount).as("1 messages failed").isEqualTo(1); - context("Second attempt", 4); result = service.doScheduledSend(); - assertEquals("1 message was 'sent' successfully", 1, result.successfulCount); - assertEquals("0 messages failed", 0, result.failedCount); + assertThat(result.successfulCount).as("1 message was 'sent' successfully").isEqualTo(1); + assertThat(result.failedCount).as("0 messages failed").isZero(); - context("Third attempt", 4); - info("No messages should be due to send this time"); result = service.doScheduledSend(); - assertEquals("0 messages were 'sent' successfully", 0, result.successfulCount); - assertEquals("0 messages failed", 0, result.failedCount); + assertThat(result.successfulCount).as("0 messages were 'sent' successfully").isZero(); + assertThat(result.failedCount).as("0 messages failed").isZero(); verify(mockMailApiClient, times(2)).send(eq(dummyMessage1)); verify(mockMailApiClient).send(eq(dummyMessage2)); diff --git a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java b/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java index 7ded5d8da43..09830614eb0 100644 --- a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java +++ b/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java @@ -11,10 +11,7 @@ import java.util.concurrent.TimeUnit; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; -import static org.rnorth.visibleassertions.VisibleAssertions.context; -import static org.rnorth.visibleassertions.VisibleAssertions.info; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by rnorth on 03/01/2016. @@ -29,54 +26,36 @@ public class SingleDisqueInstanceTest { @Before public void setup() { - context(""); DisqueClient client = new DisqueClient(DisqueURI.create(container.getHost(), container.getMappedPort(7711))); connection = client.connect().sync(); retryAfter1Second = AddJobArgs.builder().retry(1, TimeUnit.SECONDS).build(); - - info("Initialized a fresh Disque instance and client"); } @Test public void testJobStoreAndRetrieve() { - - info("Adding a job to the queue"); connection.addjob("main_queue", "body", 1, TimeUnit.MINUTES); - info("Getting a job from the queue"); Job job = connection.getjob("main_queue"); - assertEquals("The retrieved job is the same as the one that was added", - "body", - job.getBody()); + assertThat(job.getBody()).as("The retrieved job is the same as the one that was added").isEqualTo("body"); - info("Acknowledging the job to mark completion"); connection.ackjob(job.getId()); } @Test public void testFailureToAckJobBeforeTimeout() throws InterruptedException { - - info("Adding a job to the queue"); connection.addjob("main_queue", "body", 1, TimeUnit.MINUTES, retryAfter1Second); - info("Getting a job from the queue"); Job job = connection.getjob("main_queue"); - assertEquals("The retrieved job is the same as the one that was added", - "body", - job.getBody()); + assertThat(job.getBody()).as("The retrieved job is the same as the one that was added").isEqualTo("body"); - info("Simulating a failure to ack the job before the timeout (1s)"); TimeUnit.SECONDS.sleep(2); - info("Attempting to get another job from the queue - the RETRY setting for the job means it should have reappeared"); // The timeout specified here is how long the command will wait for a job to appear Job job2 = connection.getjob(5, TimeUnit.SECONDS, "main_queue"); - assertNotNull("After re-getting the original job is back on the queue", job2); - assertEquals("The retrieved job is the same as the one that was added", - "body", - job2.getBody()); + assertThat(job2).as("After re-getting the original job is back on the queue").isNotNull(); + assertThat(job2.getBody()).as("The retrieved job is the same as the one that was added").isEqualTo("body"); } } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 1e09fbc84f0..9d0fd118f61 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -14,7 +14,7 @@ dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testng:testng:7.5' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } test { diff --git a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java index 927f097aa5f..e02b271f290 100644 --- a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java @@ -10,9 +10,7 @@ import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Integration test for Redis-backed cache implementation. @@ -45,18 +43,14 @@ public void testFindingAnInsertedValue() { cache.put("foo", "FOO"); Optional foundObject = cache.get("foo", String.class); - assertTrue("When an object in the cache is retrieved, it can be found", - foundObject.isPresent()); - assertEquals("When we put a String in to the cache and retrieve it, the value is the same", - "FOO", - foundObject.get()); + assertThat(foundObject).as("When an object in the cache is retrieved, it can be found").isPresent(); + assertThat(foundObject).as("When we put a String in to the cache and retrieve it, the value is the same").contains("FOO"); } @Test public void testNotFindingAValueThatWasNotInserted() { Optional foundObject = cache.get("bar", String.class); - assertFalse("When an object that's not in the cache is retrieved, nothing is found", - foundObject.isPresent()); + assertThat(foundObject).as("When an object that's not in the cache is retrieved, nothing is found").isNotPresent(); } } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 94f445f5ffe..c5f365b5502 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -14,5 +14,5 @@ dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' testImplementation 'ch.qos.logback:logback-classic:1.2.11' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java index aa4199684e8..24a21723b15 100644 --- a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java @@ -9,9 +9,7 @@ import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Integration test for Redis-backed cache implementation. @@ -35,18 +33,14 @@ public void testFindingAnInsertedValue() { cache.put("foo", "FOO"); Optional foundObject = cache.get("foo", String.class); - assertTrue("When an object in the cache is retrieved, it can be found", - foundObject.isPresent()); - assertEquals("When we put a String in to the cache and retrieve it, the value is the same", - "FOO", - foundObject.get()); + assertThat(foundObject.isPresent()).as("When an object in the cache is retrieved, it can be found").isTrue(); + assertThat(foundObject.get()).as("When we put a String in to the cache and retrieve it, the value is the same").isEqualTo("FOO"); } @Test public void testNotFindingAValueThatWasNotInserted() { Optional foundObject = cache.get("bar", String.class); - assertFalse("When an object that's not in the cache is retrieved, nothing is found", - foundObject.isPresent()); + assertThat(foundObject.isPresent()).as("When an object that's not in the cache is retrieved, nothing is found").isFalse(); } } diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 7677e82eefb..dc10798a060 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -15,5 +15,5 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.testcontainers:selenium' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/selenium-container/src/test/java/SeleniumContainerTest.java b/examples/selenium-container/src/test/java/SeleniumContainerTest.java index c21d6bf4eca..32411b98ed9 100644 --- a/examples/selenium-container/src/test/java/SeleniumContainerTest.java +++ b/examples/selenium-container/src/test/java/SeleniumContainerTest.java @@ -19,7 +19,7 @@ import java.io.File; import java.util.List; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; /** @@ -45,7 +45,7 @@ public void simplePlainSeleniumTest() { driver.get("http://host.testcontainers.internal:" + port + "/foo.html"); List hElement = driver.findElementsByTagName("h"); - assertTrue("The h element is found", hElement != null && hElement.size() > 0); + assertThat(hElement).as("The h element is found").isNotEmpty(); } public static class Initializer implements ApplicationContextInitializer { diff --git a/examples/settings.gradle b/examples/settings.gradle index cfb204f4b00..be455a78955 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -32,7 +32,6 @@ include 'solr-container' include 'spring-boot' include 'cucumber' include 'spring-boot-kotlin-redis' -include 'spock' ext.isCI = System.getenv("CI") != null diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index fd603d515c7..89f067d3a19 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -15,5 +15,5 @@ dependencies { testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java b/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java index 0f4e6d672d8..fff6e1a4a3a 100644 --- a/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java +++ b/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java @@ -8,8 +8,7 @@ import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class BarConcreteTestClass extends AbstractIntegrationTest { @@ -27,8 +26,8 @@ public void testInsertValue() { cache.put("bar", "BAR"); Optional foundObject = cache.get("bar", String.class); - assertTrue("When inserting an object into the cache, it can be retrieved", foundObject.isPresent()); - assertEquals("When accessing the value of a retrieved object, the value must be the same", "BAR", foundObject.get()); + assertThat(foundObject).as("When inserting an object into the cache, it can be retrieved").isPresent(); + assertThat(foundObject).as("When accessing the value of a retrieved object, the value must be the same").contains("BAR"); } } diff --git a/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java b/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java index 3a9e4e84f04..11ad98a0580 100644 --- a/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java +++ b/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java @@ -8,15 +8,14 @@ import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class FooConcreteTestClass extends AbstractIntegrationTest { private Cache cache; @Before - public void setUp() throws Exception { + public void setUp() { Jedis jedis = new Jedis(redis.getHost(), redis.getMappedPort(6379)); cache = new RedisBackedCache(jedis, "foo"); @@ -27,7 +26,7 @@ public void testInsertValue() { cache.put("foo", "FOO"); Optional foundObject = cache.get("foo", String.class); - assertTrue("When inserting an object into the cache, it can be retrieved", foundObject.isPresent()); - assertEquals("When accessing the value of a retrieved object, the value must be the same", "FOO", foundObject.get()); + assertThat(foundObject).as("When inserting an object into the cache, it can be retrieved").isPresent(); + assertThat(foundObject).as("When accessing the value of a retrieved object, the value must be the same").contains("FOO"); } } diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index abb7c12e0ed..56fd297cf5e 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -14,6 +14,6 @@ dependencies { testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java index 49f8cf99f33..6443a19b869 100644 --- a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java +++ b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java @@ -16,7 +16,7 @@ import java.util.Map; import static com.example.SolrSearchEngine.COLLECTION_NAME; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class SolrQueryTest { @@ -55,8 +55,8 @@ public void testQueryForShoes() { SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); SearchResult result = searchEngine.search("shoes"); - assertEquals("When searching for shoes we expect one result", 1L, result.getTotalHits()); - assertEquals("The result should have the id 1", "1", result.getResults().get(0).get("id")); + assertThat(result.getTotalHits()).as("When searching for shoes we expect one result").isEqualTo(1L); + assertThat(result.getResults().get(0).get("id")).as("The result should have the id 1").isEqualTo("1"); } @Test @@ -64,8 +64,8 @@ public void testQueryForTShirt() { SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); SearchResult result = searchEngine.search("t-shirt"); - assertEquals("When searching for t-shirt we expect one result", 1L, result.getTotalHits()); - assertEquals("The result should have the id 2", "2", result.getResults().get(0).get("id")); + assertThat(result.getTotalHits()).as("When searching for t-shirt we expect one result").isEqualTo(1L); + assertThat(result.getResults().get(0).get("id")).as("The result should have the id 2").isEqualTo("2"); } @Test @@ -73,7 +73,7 @@ public void testQueryForAsterisk() { SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); SearchResult result = searchEngine.search("*"); - assertEquals("When searching for * we expect no results", 0L, result.getTotalHits()); + assertThat(result.getTotalHits()).as("When searching for * we expect no results").isEqualTo(0L); } private static SolrInputField createInputField(String key, String value) { diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index e3b3376e28f..650b5a60d98 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -17,5 +17,4 @@ dependencies { runtimeOnly 'org.postgresql:postgresql' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.testcontainers:postgresql' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' } diff --git a/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java b/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java index 286ce41ffbf..c305ae67811 100644 --- a/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java +++ b/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java @@ -4,8 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.client.TestRestTemplate; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.info; +import static org.assertj.core.api.Assertions.assertThat; public class DemoControllerTest extends AbstractIntegrationTest { @@ -19,10 +18,9 @@ public class DemoControllerTest extends AbstractIntegrationTest { public void simpleTest() { String fooResource = "/foo"; - info("putting 'bar' to " + fooResource); restTemplate.put(fooResource, "bar"); - assertEquals("value is set", "bar", restTemplate.getForObject(fooResource, String.class)); + assertThat(restTemplate.getForObject(fooResource, String.class)).as("value is set").isEqualTo("bar"); } @Test @@ -33,7 +31,7 @@ public void simpleJPATest() { DemoEntity result = restTemplate.getForObject("/" + demoEntity.getId(), DemoEntity.class); - assertEquals("value is set", "Some value", result.getValue()); + assertThat(result.getValue()).as("value is set").isEqualTo("Some value"); } } diff --git a/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java b/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java index 37422b30af7..140bd64c39a 100644 --- a/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java +++ b/modules/azure/src/test/java/org/testcontainers/containers/CosmosDBEmulatorContainerTest.java @@ -4,7 +4,6 @@ import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.models.CosmosContainerResponse; import com.azure.cosmos.models.CosmosDatabaseResponse; -import org.assertj.core.api.Assertions; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; @@ -17,6 +16,8 @@ import java.security.KeyStore; import java.util.Properties; +import static org.assertj.core.api.Assertions.assertThat; + public class CosmosDBEmulatorContainerTest { private static Properties originalSystemProperties; @@ -64,12 +65,12 @@ public void testWithCosmosClient() throws Exception { // } // testWithClientAgainstEmulatorContainer { CosmosDatabaseResponse databaseResponse = client.createDatabaseIfNotExists("Azure").block(); - Assertions.assertThat(databaseResponse.getStatusCode()).isEqualTo(201); + assertThat(databaseResponse.getStatusCode()).isEqualTo(201); CosmosContainerResponse containerResponse = client .getDatabase("Azure") .createContainerIfNotExists("ServiceContainer", "/name") .block(); - Assertions.assertThat(containerResponse.getStatusCode()).isEqualTo(201); + assertThat(containerResponse.getStatusCode()).isEqualTo(201); // } } } diff --git a/modules/clickhouse/build.gradle b/modules/clickhouse/build.gradle index 914ee7efbd4..9f7df373b27 100644 --- a/modules/clickhouse/build.gradle +++ b/modules/clickhouse/build.gradle @@ -6,4 +6,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'ru.yandex.clickhouse:clickhouse-jdbc:0.3.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java index 2f6edcc722d..8f81c88bfc0 100644 --- a/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java +++ b/modules/clickhouse/src/test/java/org/testcontainers/junit/clickhouse/SimpleClickhouseTest.java @@ -11,7 +11,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Parameterized.class) public class SimpleClickhouseTest extends AbstractContainerDatabaseTest { @@ -38,7 +38,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } } diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index fb9f53189d9..80763e312b5 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -5,4 +5,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'org.postgresql:postgresql:42.4.0' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java index 87e82fb30e3..65c79441f32 100644 --- a/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java +++ b/modules/cockroachdb/src/test/java/org/testcontainers/junit/cockroachdb/SimpleCockroachDBTest.java @@ -10,9 +10,7 @@ import java.util.logging.Level; import java.util.logging.LogManager; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class SimpleCockroachDBTest extends AbstractContainerDatabaseTest { static { @@ -28,7 +26,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(cockroach, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -43,7 +41,7 @@ public void testExplicitInitScript() throws SQLException { ResultSet resultSet = performQuery(cockroach, "SELECT foo FROM bar"); String firstColumnValue = resultSet.getString(1); - assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + assertThat(firstColumnValue).as("Value from init script should equal real value").isEqualTo("hello world"); } } @@ -56,10 +54,10 @@ public void testWithAdditionalUrlParamInJdbcUrl() { try { cockroach.start(); String jdbcUrl = cockroach.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("sslmode=disable")); - assertThat(jdbcUrl, containsString("application_name=cockroach")); + assertThat(jdbcUrl).contains("?"); + assertThat(jdbcUrl).contains("&"); + assertThat(jdbcUrl).contains("sslmode=disable"); + assertThat(jdbcUrl).contains("application_name=cockroach"); } finally { cockroach.stop(); } diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java index bc9476cc83d..99ebb69a1e8 100644 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptSplittingTest.java @@ -1,13 +1,13 @@ package org.testcontainers.ext; -import org.assertj.core.api.Assertions; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class ScriptSplittingTest { @@ -283,7 +283,7 @@ public void testIssue1452Case() { private void splitAndCompare(String script, List expected) { final List statements = doSplit(script); - Assertions.assertThat(statements).isEqualTo(expected); + assertThat(statements).isEqualTo(expected); } private List doSplit(String script) { diff --git a/modules/db2/build.gradle b/modules/db2/build.gradle index 0c8cd323779..804f51000d7 100644 --- a/modules/db2/build.gradle +++ b/modules/db2/build.gradle @@ -5,4 +5,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'com.ibm.db2:jcc:11.5.7.0' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java index 8f3489eae95..2c2c4cb2f09 100644 --- a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -8,9 +8,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class SimpleDb2Test extends AbstractContainerDatabaseTest { @@ -22,7 +20,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(db2, "SELECT 1 FROM SYSIBM.SYSDUMMY1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -36,7 +34,7 @@ public void testWithAdditionalUrlParamInJdbcUrl() { db2.start(); String jdbcUrl = db2.getJdbcUrl(); - assertThat(jdbcUrl, containsString(":sslConnection=false;")); + assertThat(jdbcUrl).contains(":sslConnection=false;"); } } } diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 5b9ff919da7..6abd9cd943a 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -5,6 +5,5 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.253' - - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java index ced5931de31..10e02566d16 100644 --- a/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java +++ b/modules/dynalite/src/test/java/org/testcontainers/dynamodb/DynaliteContainerTest.java @@ -13,8 +13,7 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; public class DynaliteContainerTest { @@ -54,12 +53,10 @@ private void runTest(AmazonDynamoDB client) { final TableDescription tableDescription = client.describeTable("foo").getTable(); - assertNotNull("the description is not null", tableDescription); - assertEquals("the table has the right name", "foo", tableDescription.getTableName()); - assertEquals( - "the name has the right primary key", - "Name", - tableDescription.getKeySchema().get(0).getAttributeName() - ); + assertThat(tableDescription).as("the description is not null").isNotNull(); + assertThat(tableDescription.getTableName()).as("the table has the right name").isEqualTo("foo"); + assertThat(tableDescription.getKeySchema().get(0).getAttributeName()) + .as("the name has the right primary key") + .isEqualTo("Name"); } } diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index a3a47d11fab..0e6c5bd7b5d 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.3.3" testImplementation "org.elasticsearch.client:transport:7.17.5" - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 9fcfc45af76..1e1e70b5d75 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -29,10 +29,8 @@ import javax.net.ssl.SSLHandshakeException; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; public class ElasticsearchContainerTest { @@ -84,14 +82,14 @@ public void elasticsearchDeprecatedCtorTest() throws IOException { // Do whatever you want with the rest client ... Response response = getClient(container).performRequest(new Request("GET", "/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION)); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains(ELASTICSEARCH_VERSION); // The default image is running with the features under Elastic License response = getClient(container).performRequest(new Request("GET", "/_xpack/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); // For now we test that we have the monitoring feature available - assertThat(EntityUtils.toString(response.getEntity()), containsString("monitoring")); + assertThat(EntityUtils.toString(response.getEntity())).contains("monitoring"); } } @@ -106,14 +104,14 @@ public void elasticsearchDefaultTest() throws IOException { // Do whatever you want with the rest client ... Response response = getClient(container).performRequest(new Request("GET", "/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION)); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains(ELASTICSEARCH_VERSION); // The default image is running with the features under Elastic License response = getClient(container).performRequest(new Request("GET", "/_xpack/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); // For now we test that we have the monitoring feature available - assertThat(EntityUtils.toString(response.getEntity()), containsString("monitoring")); + assertThat(EntityUtils.toString(response.getEntity())).contains("monitoring"); } } @@ -126,16 +124,14 @@ public void elasticsearchSecuredTest() throws IOException { container.start(); // The cluster should be secured so it must fail when we try to access / without credentials - assertThrows( - "We should not be able to access / URI with an anonymous client.", - ResponseException.class, - () -> getAnonymousClient(container).performRequest(new Request("GET", "/")) - ); + assertThat(catchThrowable(() -> getAnonymousClient(container).performRequest(new Request("GET", "/")))) + .as("We should not be able to access / URI with an anonymous client.") + .isInstanceOf(ResponseException.class); // But it should work when we try to access / with the proper login and password Response response = getClient(container).performRequest(new Request("GET", "/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION)); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains(ELASTICSEARCH_VERSION); } } @@ -144,9 +140,9 @@ public void elasticsearchVersion() throws IOException { try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); String responseAsString = EntityUtils.toString(response.getEntity()); - assertThat(responseAsString, containsString(ELASTICSEARCH_VERSION)); + assertThat(responseAsString).contains(ELASTICSEARCH_VERSION); } } @@ -159,8 +155,8 @@ public void elasticsearchVersion83() throws IOException { ) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString("8.3.0")); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains("8.3.0"); } } @@ -177,13 +173,11 @@ public void elasticsearchOssImage() throws IOException { ) { container.start(); Response response = getClient(container).performRequest(new Request("GET", "/")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); // The OSS image does not have any feature under Elastic License - assertThrows( - "We should not have /_xpack endpoint with an OSS License", - ResponseException.class, - () -> getClient(container).performRequest(new Request("GET", "/_xpack/")) - ); + assertThat(catchThrowable(() -> getClient(container).performRequest(new Request("GET", "/_xpack/")))) + .as("We should not have /_xpack endpoint with an OSS License") + .isInstanceOf(ResponseException.class); } } @@ -212,8 +206,8 @@ public void restClientClusterHealth() throws IOException { Response response = client.performRequest(new Request("GET", "/_cluster/health")); // }} - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains("cluster_name"); // httpClientContainer {{ } // } @@ -248,8 +242,8 @@ public void restClientSecuredClusterHealth() throws IOException { Response response = client.performRequest(new Request("GET", "/_cluster/health")); // }} - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains("cluster_name"); // httpClientSecuredContainer {{ } // } @@ -275,7 +269,7 @@ public void transportClientClusterHealth() { ClusterHealthResponse healths = transportClient.admin().cluster().prepareHealth().get(); String clusterName = healths.getClusterName(); // }}} - assertThat(clusterName, is(expectedClusterName)); + assertThat(clusterName).isEqualTo(expectedClusterName); // transportClientContainer {{{ } } @@ -285,18 +279,18 @@ public void transportClientClusterHealth() { @Test public void incompatibleSettingsTest() { // The OSS image can not use security feature - assertThrows( - "We should not be able to activate security with an OSS License", - IllegalArgumentException.class, - () -> { + assertThat( + catchThrowable(() -> { new ElasticsearchContainer( DockerImageName .parse("docker.elastic.co/elasticsearch/elasticsearch-oss") .withTag(ELASTICSEARCH_VERSION) ) .withPassword("foo"); - } - ); + }) + ) + .as("We should not be able to activate security with an OSS License") + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -310,8 +304,8 @@ public void testElasticsearch8SecureByDefault() throws Exception { container.start(); Response response = getClusterHealth(container); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains("cluster_name"); } } @@ -329,11 +323,11 @@ public void testElasticsearch8SecureByDefaultCustomCaCertFails() throws Exceptio container.start(); // this is expected, as a different cert is used for creating the SSL context - assertThrows( - "PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors", - SSLHandshakeException.class, - () -> getClusterHealth(container) - ); + assertThat(catchThrowable(() -> getClusterHealth(container))) + .as( + "PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors" + ) + .isInstanceOf(SSLHandshakeException.class); } } @@ -357,8 +351,8 @@ public void testElasticsearch8SecureByDefaultHttpWaitStrategy() throws Exception container.start(); Response response = getClusterHealth(container); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains("cluster_name"); } } @@ -376,8 +370,8 @@ public void testElasticsearch8SecureByDefaultFailsSilentlyOnLatestImages() throw container.start(); Response response = getClient(container).performRequest(new Request("GET", "/_cluster/health")); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name")); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(EntityUtils.toString(response.getEntity())).contains("cluster_name"); } } diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 1651517dece..8336cfd8249 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -17,6 +17,7 @@ dependencies { testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.11") + testImplementation 'org.assertj:assertj-core:3.23.1' testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0") } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java index fe119854c80..3a3f2d13bb7 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class ContainerWithCustomConfigIT { @@ -33,13 +33,11 @@ void test() throws Exception { publisher.connect(); - assertThrows( - MqttSessionExpiredException.class, - () -> { + assertThatExceptionOfType(MqttSessionExpiredException.class) + .isThrownBy(() -> { // this should fail since only QoS 0 is allowed by the configuration publisher.publishWith().topic("test/topic").qos(MqttQos.EXACTLY_ONCE).send(); - } - ); + }); } } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java index 75d308e3f90..fde18e09285 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -24,8 +24,7 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class ContainerWithoutPlatformExtensionsIT { @@ -61,13 +60,13 @@ public void removeAllPlatformExtensions() throws InterruptedException { client.subscribeWith().topicFilter("extensions").send(); final Mqtt5Publish receive = publishes.receive(); - assertTrue(receive.getPayload().isPresent()); + assertThat(receive.getPayload()).isPresent(); final String extensionInfo = new String(receive.getPayloadAsBytes()); - assertFalse(extensionInfo.contains("hivemq-allow-all-extension")); - assertFalse(extensionInfo.contains("hivemq-kafka-extension")); - assertFalse(extensionInfo.contains("hivemq-bridge-extension")); - assertFalse(extensionInfo.contains("hivemq-enterprise-security-extension")); + assertThat(extensionInfo).doesNotContain("hivemq-allow-all-extension"); + assertThat(extensionInfo).doesNotContain("hivemq-kafka-extension"); + assertThat(extensionInfo).doesNotContain("hivemq-bridge-extension"); + assertThat(extensionInfo).doesNotContain("hivemq-enterprise-security-extension"); hivemq.start(); } @@ -96,13 +95,13 @@ public void removeKafkaExtension() throws InterruptedException { client.subscribeWith().topicFilter("extensions").send(); final Mqtt5Publish receive = publishes.receive(); - assertTrue(receive.getPayload().isPresent()); + assertThat(receive.getPayload().isPresent()).isTrue(); final String extensionInfo = new String(receive.getPayloadAsBytes()); - assertTrue(extensionInfo.contains("hivemq-allow-all-extension")); - assertFalse(extensionInfo.contains("hivemq-kafka-extension")); - assertTrue(extensionInfo.contains("hivemq-bridge-extension")); - assertTrue(extensionInfo.contains("hivemq-enterprise-security-extension")); + assertThat(extensionInfo).contains("hivemq-allow-all-extension"); + assertThat(extensionInfo).doesNotContain("hivemq-kafka-extension"); + assertThat(extensionInfo).contains("hivemq-bridge-extension"); + assertThat(extensionInfo).contains("hivemq-enterprise-security-extension"); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java index 191ea41f303..cd83cb8a10d 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -22,15 +22,15 @@ import java.nio.file.Files; import java.util.concurrent.TimeUnit; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class CreateFileInCopiedDirectoryIT { private @NotNull MountableFile createDirectory() throws IOException { final File directory = new File(Files.createTempDirectory("").toFile(), "directory"); - assertTrue(directory.mkdir()); + assertThat(directory.mkdir()).isTrue(); final File subdirectory = new File(directory, "sub-directory"); - assertTrue(subdirectory.mkdir()); + assertThat(subdirectory.mkdir()).isTrue(); return MountableFile.forHostPath(directory.getPath()); } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java index 9588e3404e6..a2ee9edfbcf 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -10,7 +10,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class DisableEnableExtensionFromDirectoryIT { @@ -27,10 +27,8 @@ void test() throws Exception { TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.disableExtension("Modifier Extension", "modifier-extension"); - assertThrows( - ExecutionException.class, - () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()) - ); + assertThatExceptionOfType(ExecutionException.class) + .isThrownBy(() -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); hivemq.enableExtension("Modifier Extension", "modifier-extension"); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java index e50664f240e..361af190a57 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -11,7 +11,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class DisableEnableExtensionIT { @@ -35,17 +35,13 @@ void test() throws Exception { ) { hivemq.start(); - assertThrows( - ExecutionException.class, - () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()) - ); + assertThatExceptionOfType(ExecutionException.class) + .isThrownBy(() -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); hivemq.enableExtension(hiveMQExtension); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); hivemq.disableExtension(hiveMQExtension); - assertThrows( - ExecutionException.class, - () -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()) - ); + assertThatExceptionOfType(ExecutionException.class) + .isThrownBy(() -> TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost())); hivemq.enableExtension(hiveMQExtension); TestPublishModifiedUtil.testPublishModified(hivemq.getMqttPort(), hivemq.getHost()); } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java index 08e1df797a1..38b8e918925 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java @@ -2,15 +2,13 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; class HiveMQExtensionTest { @Test void builder_classDoesNotImplementExtensionMain_exception() { - assertThrows( - IllegalArgumentException.class, - () -> HiveMQExtension.builder().mainClass(HiveMQExtensionTest.class) - ); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> HiveMQExtension.builder().mainClass(HiveMQExtensionTest.class)); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java index d4dd2be9621..32097e52641 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java @@ -10,8 +10,8 @@ import java.io.File; import java.io.IOException; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; class HiveMQTestContainerCore { @@ -24,69 +24,72 @@ class HiveMQTestContainerCore { @Test void withExtension_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows(ContainerLaunchException.class, () -> container.withExtension(mountableFile)); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withExtension(mountableFile)); } @Test void withExtension_fileNoDirectory_Exception() throws IOException { final File extension = new File(tempDir, "extension"); - assertTrue(extension.createNewFile()); + assertThat(extension.createNewFile()).isTrue(); final MountableFile mountableFile = MountableFile.forHostPath(extension.getAbsolutePath()); - assertThrows(ContainerLaunchException.class, () -> container.withExtension(mountableFile)); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withExtension(mountableFile)); } @Test void withLicense_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows(ContainerLaunchException.class, () -> container.withLicense(mountableFile)); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withLicense(mountableFile)); } @Test void withExtension_fileEndingWrong_Exception() throws IOException { final File extension = new File(tempDir, "extension.wrong"); - assertTrue(extension.createNewFile()); + assertThat(extension.createNewFile()).isTrue(); final MountableFile mountableFile = MountableFile.forHostPath(extension.getAbsolutePath()); - assertThrows(ContainerLaunchException.class, () -> container.withLicense(mountableFile)); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withLicense(mountableFile)); } @Test void withHiveMQConfig_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows(ContainerLaunchException.class, () -> container.withHiveMQConfig(mountableFile)); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withHiveMQConfig(mountableFile)); } @Test void withFileInHomeFolder_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows(ContainerLaunchException.class, () -> container.withFileInHomeFolder(mountableFile, "some/path")); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withFileInHomeFolder(mountableFile, "some/path")); } @Test void withFileInHomeFolder_pathEmpty_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows(ContainerLaunchException.class, () -> container.withFileInHomeFolder(mountableFile, "")); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withFileInHomeFolder(mountableFile, "")); } @Test void withFileInExtensionHomeFolder_withPath_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows( - ContainerLaunchException.class, - () -> container.withFileInExtensionHomeFolder(mountableFile, "my-extension", "some/path") - ); + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> container.withFileInExtensionHomeFolder(mountableFile, "my-extension", "some/path")); } @Test void withFileInExtensionHomeFolder_fileDoesNotExist_Exception() { final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); - assertThrows( - ContainerLaunchException.class, - () -> { + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> { final HiveMQContainer hiveMQContainer = container.withFileInExtensionHomeFolder( mountableFile, "my-extension" ); - } - ); + }); } } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java index f1e060e68d9..d845acb6684 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java @@ -2,42 +2,42 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; class PathUtilTest { @Test void prepareInnerPath_emptyString() { - assertEquals("/", PathUtil.prepareInnerPath("")); + assertThat(PathUtil.prepareInnerPath("")).isEqualTo("/"); } @Test void prepareInnerPath_onlyDelimiter() { - assertEquals("/", PathUtil.prepareInnerPath("/")); + assertThat(PathUtil.prepareInnerPath("/")).isEqualTo("/"); } @Test void prepareInnerPath_noDelimiter() { - assertEquals("/path/", PathUtil.prepareInnerPath("path")); + assertThat(PathUtil.prepareInnerPath("path")).isEqualTo("/path/"); } @Test void prepareInnerPath_delimiterAtEnd() { - assertEquals("/path/", PathUtil.prepareInnerPath("path/")); + assertThat(PathUtil.prepareInnerPath("path/")).isEqualTo("/path/"); } @Test void prepareInnerPath_delimiterAtBeginning() { - assertEquals("/path/", PathUtil.prepareInnerPath("/path")); + assertThat(PathUtil.prepareInnerPath("/path")).isEqualTo("/path/"); } @Test void prepareAppendPath_delimiterAtBeginning_noChange() { - assertEquals("/path", PathUtil.prepareAppendPath("/path")); + assertThat(PathUtil.prepareAppendPath("/path")).isEqualTo("/path"); } @Test void prepareAppendPath_delimiterAtBeginning_delimiterAdded() { - assertEquals("/path", PathUtil.prepareAppendPath("path")); + assertThat(PathUtil.prepareAppendPath("path")).isEqualTo("/path"); } } diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index 0d8e2abedf9..f8b55d01bc5 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -9,10 +9,7 @@ dependencies { api 'com.googlecode.junit-toolbox:junit-toolbox:2.4' - api('org.rnorth.visible-assertions:visible-assertions:2.1.2') { - // Excluded in favor of jna-platform - exclude(group: "net.java.dev.jna", module: "jna") - } + api 'org.assertj:assertj-core:3.23.1' api 'org.apache.tomcat:tomcat-jdbc:10.0.23' api 'org.vibur:vibur-dbcp:25.0' diff --git a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java index 5566db6244e..a152a1ae550 100644 --- a/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java +++ b/modules/jdbc-test/src/main/java/org/testcontainers/jdbc/AbstractJDBCDriverTest.java @@ -14,9 +14,8 @@ import java.sql.Statement; import java.util.EnumSet; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class AbstractJDBCDriverTest { @@ -82,12 +81,12 @@ private void performSimpleTest(HikariDataSource dataSource) throws SQLException rs -> { rs.next(); int resultSetInt = rs.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); return true; } ); - assertTrue("The database returned a record as expected", result); + assertThat(result).as("The database returned a record as expected").isTrue(); } private void performTestForScriptedSchema(HikariDataSource dataSource) throws SQLException { @@ -97,16 +96,14 @@ private void performTestForScriptedSchema(HikariDataSource dataSource) throws SQ rs -> { rs.next(); String resultSetString = rs.getString(1); - assertEquals( - "A basic SELECT query succeeds where the schema has been applied from a script", - "hello world", - resultSetString - ); + assertThat(resultSetString) + .as("A basic SELECT query succeeds where the schema has been applied from a script") + .isEqualTo("hello world"); return true; } ); - assertTrue("The database returned a record as expected", result); + assertThat(result).as("The database returned a record as expected").isTrue(); } private void performTestForJDBCParamUsage(HikariDataSource dataSource) throws SQLException { @@ -120,12 +117,12 @@ private void performTestForJDBCParamUsage(HikariDataSource dataSource) throws SQ if (resultUser.endsWith("@%")) { resultUser = resultUser.substring(0, resultUser.length() - 2); } - assertEquals("User from query param is created.", "someuser", resultUser); + assertThat(resultUser).as("User from query param is created.").isEqualTo("someuser"); return true; } ); - assertTrue("The database returned a record as expected", result); + assertThat(result).as("The database returned a record as expected").isTrue(); String databaseQuery = "SELECT DATABASE()"; // Postgres does not have Database() as a function @@ -145,12 +142,12 @@ private void performTestForJDBCParamUsage(HikariDataSource dataSource) throws SQ rs -> { rs.next(); String resultDB = rs.getString(1); - assertEquals("Database name from URL String is used.", "databasename", resultDB); + assertThat(resultDB).as("Database name from URL String is used.").isEqualTo("databasename"); return true; } ); - assertTrue("The database returned a record as expected", result); + assertThat(result).as("The database returned a record as expected").isTrue(); } private void performTestForCharacterEncodingForInitialScriptConnection(HikariDataSource dataSource) @@ -161,16 +158,14 @@ private void performTestForCharacterEncodingForInitialScriptConnection(HikariDat rs -> { rs.next(); String resultSetString = rs.getString(1); - assertEquals( - "A SELECT query succeed and the correct charset has been applied for the init script", - "привет мир", - resultSetString - ); + assertThat(resultSetString) + .as("A basic SELECT query succeeds where the schema has been applied from a script") + .isEqualTo("привет мир"); return true; } ); - assertTrue("The database returned a record as expected", result); + assertThat(result).as("The database returned a record as expected").isTrue(); } /** @@ -195,15 +190,14 @@ private HikariDataSource verifyCharacterSet(String jdbcUrl) throws SQLException rs -> { rs.next(); String resultSetString = rs.getString(2); - assertTrue( - "Passing query parameters to set DB connection encoding is successful", - resultSetString.startsWith("utf8") - ); + assertThat(resultSetString) + .as("Passing query parameters to set DB connection encoding is successful") + .startsWith("utf8"); return true; } ); - assertTrue("The database returned a record as expected", result); + assertThat(result).as("The database returned a record as expected").isTrue(); return dataSource; } @@ -213,10 +207,10 @@ private void performTestForCustomIniFile(HikariDataSource dataSource) throws SQL statement.execute("SELECT @@GLOBAL.innodb_file_format"); ResultSet resultSet = statement.getResultSet(); - assertTrue("The query returns a result", resultSet.next()); + assertThat(resultSet.next()).as("The query returns a result").isTrue(); String result = resultSet.getString(1); - assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result); + assertThat(result).as("The InnoDB file format has been set by the ini file content").isEqualTo("Barracuda"); } private HikariDataSource getDataSource(String jdbcUrl, int poolSize) { diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 3a6681aee13..6047a3c0f3e 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -10,6 +10,5 @@ dependencies { testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.23' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java index 9b88e6b503d..2ac8cf88b5d 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlDriversTests.java @@ -8,7 +8,7 @@ import java.util.Arrays; import java.util.Optional; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * This Test class validates that all supported JDBC URL's can be parsed by ConnectionUrl class. @@ -125,9 +125,9 @@ public static Iterable data() { @Test public void test() { ConnectionUrl url = ConnectionUrl.newInstance(jdbcUrl); - assertEquals("Database Type is as expected", databaseType, url.getDatabaseType()); - assertEquals("Image tag is as expected", tag, url.getImageTag()); - assertEquals("Database Host String is as expected", dbHostString, url.getDbHostString()); - assertEquals("Database Name is as expected", databaseName, url.getDatabaseName().orElse("")); + assertThat(url.getDatabaseType()).as("Database Type is as expected").isEqualTo(databaseType); + assertThat(url.getImageTag()).as("Image tag is as expected").isEqualTo(tag); + assertThat(url.getDbHostString()).as("Database Host String is as expected").isEqualTo(dbHostString); + assertThat(url.getDatabaseName().orElse("")).as("Database Name is as expected").isEqualTo(databaseName); } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java index 6888f881ec4..fa50dbbe76e 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ConnectionUrlTest.java @@ -4,9 +4,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import java.util.Optional; - -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.assertj.core.api.Assertions.assertThat; public class ConnectionUrlTest { @@ -18,16 +16,18 @@ public void testConnectionUrl1() { String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); - assertEquals("Database Type value is as expected", "mysql", url.getDatabaseType()); - assertEquals("Database Image tag value is as expected", "5.7.34", url.getImageTag().get()); - assertEquals("Database Host String is as expected", "somehostname:3306/databasename", url.getDbHostString()); - assertEquals("Query String value is as expected", "?a=b&c=d", url.getQueryString().get()); - assertEquals("Database Host value is as expected", "somehostname", url.getDatabaseHost().get()); - assertEquals("Database Port value is as expected", 3306, url.getDatabasePort().get()); - assertEquals("Database Name value is as expected", "databasename", url.getDatabaseName().get()); - - assertEquals("Parameter a is captured", "b", url.getQueryParameters().get("a")); - assertEquals("Parameter c is captured", "d", url.getQueryParameters().get("c")); + assertThat(url.getDatabaseType()).as("Database Type value is as expected").isEqualTo("mysql"); + assertThat(url.getImageTag()).as("Database Image tag value is as expected").contains("5.7.34"); + assertThat(url.getDbHostString()) + .as("Database Host String is as expected") + .isEqualTo("somehostname:3306/databasename"); + assertThat(url.getQueryString()).as("Query String value is as expected").contains("?a=b&c=d"); + assertThat(url.getDatabaseHost()).as("Database Host value is as expected").contains("somehostname"); + assertThat(url.getDatabasePort()).as("Database Port value is as expected").contains(3306); + assertThat(url.getDatabaseName()).as("Database Name value is as expected").contains("databasename"); + + assertThat(url.getQueryParameters()).as("Parameter a is captured").containsEntry("a", "b"); + assertThat(url.getQueryParameters()).as("Parameter c is captured").containsEntry("c", "d"); } @Test @@ -35,21 +35,23 @@ public void testConnectionUrl2() { String urlString = "jdbc:tc:mysql://somehostname/databasename"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); - assertEquals("Database Type value is as expected", "mysql", url.getDatabaseType()); - assertFalse("Database Image tag value is as expected", url.getImageTag().isPresent()); - assertEquals("Database Host String is as expected", "somehostname/databasename", url.getDbHostString()); - assertEquals("Query String value is as expected", Optional.empty(), url.getQueryString()); - assertEquals("Database Host value is as expected", "somehostname", url.getDatabaseHost().get()); - assertFalse("Database Port is null as expected", url.getDatabasePort().isPresent()); - assertEquals("Database Name value is as expected", "databasename", url.getDatabaseName().get()); - - assertTrue("Connection Parameters set is empty", url.getQueryParameters().isEmpty()); + assertThat(url.getDatabaseType()).as("Database Type value is as expected").isEqualTo("mysql"); + assertThat(url.getImageTag()).as("Database Image tag value is as expected").isNotPresent(); + assertThat(url.getDbHostString()) + .as("Database Host String is as expected") + .isEqualTo("somehostname/databasename"); + assertThat(url.getQueryString()).as("Query String value is as expected").isEmpty(); + assertThat(url.getDatabaseHost()).as("Database Host value is as expected").contains("somehostname"); + assertThat(url.getDatabasePort()).as("Database Port is null as expected").isNotPresent(); + assertThat(url.getDatabaseName()).as("Database Name value is as expected").contains("databasename"); + + assertThat(url.getQueryParameters().isEmpty()).as("Connection Parameters set is empty").isTrue(); } @Test public void testEmptyQueryParameter() { ConnectionUrl url = ConnectionUrl.newInstance("jdbc:tc:mysql://somehostname/databasename?key="); - assertEquals("'key' property value", "", url.getQueryParameters().get("key")); + assertThat(url.getQueryParameters().get("key")).as("'key' property value").isEqualTo(""); } @Test @@ -57,17 +59,13 @@ public void testTmpfsOption() { String urlString = "jdbc:tc:mysql://somehostname/databasename?TC_TMPFS=key:value,key1:value1"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); - assertTrue("Connection Parameters set is empty", url.getQueryParameters().isEmpty()); - assertFalse("Container Parameters set is not empty", url.getContainerParameters().isEmpty()); - assertEquals( - "Container Parameter TC_TMPFS is true", - "key:value,key1:value1", - url.getContainerParameters().get("TC_TMPFS") - ); - assertTrue("tmpfs option key exists", url.getTmpfsOptions().containsKey("key")); - assertEquals("tmpfs option key has correct value", "value", url.getTmpfsOptions().get("key")); - assertTrue("tmpfs option key1 exists", url.getTmpfsOptions().containsKey("key1")); - assertEquals("tmpfs option key1 has correct value", "value1", url.getTmpfsOptions().get("key1")); + assertThat(url.getQueryParameters()).as("Connection Parameters set is empty").isEmpty(); + assertThat(url.getContainerParameters()).as("Container Parameters set is not empty").isNotEmpty(); + assertThat(url.getContainerParameters()) + .as("Container Parameter TC_TMPFS is true") + .containsEntry("TC_TMPFS", "key:value,key1:value1"); + assertThat(url.getTmpfsOptions()).as("tmpfs option key has correct value").containsEntry("key", "value"); + assertThat(url.getTmpfsOptions()).as("tmpfs option key1 has correct value").containsEntry("key1", "value1"); } @Test @@ -76,13 +74,13 @@ public void testInitScriptPathCapture() { "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITSCRIPT=somepath/init_mysql.sql"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); - assertEquals("Database Type value is as expected", "somepath/init_mysql.sql", url.getInitScriptPath().get()); - assertEquals("Query String value is as expected", "?a=b&c=d", url.getQueryString().get()); - assertEquals( - "INIT SCRIPT Path exists in Container Parameters", - "somepath/init_mysql.sql", - url.getContainerParameters().get("TC_INITSCRIPT") - ); + assertThat(url.getInitScriptPath()) + .as("Database Type value is as expected") + .contains("somepath/init_mysql.sql"); + assertThat(url.getQueryString()).as("Query String value is as expected").contains("?a=b&c=d"); + assertThat(url.getContainerParameters()) + .as("INIT SCRIPT Path exists in Container Parameters") + .containsEntry("TC_INITSCRIPT", "somepath/init_mysql.sql"); //Parameter sets are unmodifiable thrown.expect(UnsupportedOperationException.class); @@ -96,18 +94,14 @@ public void testInitFunctionCapture() { "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); - assertTrue("Init Function parameter exists", url.getInitFunction().isPresent()); - - assertEquals( - "Init function class is as expected", - "org.testcontainers.jdbc.JDBCDriverTest", - url.getInitFunction().get().getClassName() - ); - assertEquals( - "Init function class is as expected", - "sampleInitFunction", - url.getInitFunction().get().getMethodName() - ); + assertThat(url.getInitFunction()).as("Init Function parameter exists").isPresent(); + + assertThat(url.getInitFunction().get().getClassName()) + .as("Init function class is as expected") + .isEqualTo("org.testcontainers.jdbc.JDBCDriverTest"); + assertThat(url.getInitFunction().get().getMethodName()) + .as("Init function class is as expected") + .isEqualTo("sampleInitFunction"); } @Test @@ -115,6 +109,6 @@ public void testDaemonCapture() { String urlString = "jdbc:tc:mysql:5.7.34://somehostname:3306/databasename?a=b&c=d&TC_DAEMON=true"; ConnectionUrl url = ConnectionUrl.newInstance(urlString); - assertTrue("Daemon flag is set to true.", url.isInDaemonMode()); + assertThat(url.isInDaemonMode()).as("Daemon flag is set to true.").isTrue(); } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java index 68afe8692e8..379b262aa3a 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java @@ -9,9 +9,8 @@ import java.sql.SQLException; import java.util.concurrent.atomic.AtomicInteger; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.rnorth.visibleassertions.VisibleAssertions.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class MissingJdbcDriverTest { @@ -24,12 +23,16 @@ public void shouldFailFastIfNoDriverFound() { fail("The container is expected to fail to start"); } catch (Exception e) { final Throwable rootCause = Throwables.getRootCause(e); - assertTrue("ClassNotFoundException is the root cause", rootCause instanceof ClassNotFoundException); + assertThat(rootCause) + .as("ClassNotFoundException is the root cause") + .isInstanceOf(ClassNotFoundException.class); } finally { container.stop(); } - assertEquals("only one connection attempt should have been made", 1, container.getConnectionAttempts()); + assertThat(container.getConnectionAttempts()) + .as("only one connection attempt should have been made") + .isEqualTo(1); } /** diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java index f49aa8732f5..866b76df301 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/ComposeContainerTests.java @@ -11,7 +11,7 @@ import java.io.File; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @Testcontainers class ComposeContainerTests { @@ -38,6 +38,6 @@ void running_compose_defined_container_is_accessible_on_configured_port() throws HttpResponse response = client.execute(new HttpGet("http://" + host + ":" + port)); - assertEquals(200, response.getStatusLine().getStatusCode()); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); } } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java index 6c44d978b69..e8ce714ab28 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MixedLifecycleTests.java @@ -4,7 +4,7 @@ import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.PostgreSQLContainer; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; // testClass { @Testcontainers @@ -23,8 +23,8 @@ class MixedLifecycleTests { @Test void test() { - assertTrue(MY_SQL_CONTAINER.isRunning()); - assertTrue(postgresqlContainer.isRunning()); + assertThat(MY_SQL_CONTAINER.isRunning()).isTrue(); + assertThat(postgresqlContainer.isRunning()).isTrue(); } } // } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java index 526038853c9..8852524d451 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersExtensionTests.java @@ -4,8 +4,7 @@ import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExtensionContext; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -15,28 +14,28 @@ public class TestcontainersExtensionTests { void whenDisabledWithoutDockerAndDockerIsAvailableTestsAreEnabled() { ConditionEvaluationResult result = new TestTestcontainersExtension(true) .evaluateExecutionCondition(extensionContext(DisabledWithoutDocker.class)); - assertFalse(result.isDisabled()); + assertThat(result.isDisabled()).isFalse(); } @Test void whenDisabledWithoutDockerAndDockerIsUnavailableTestsAreDisabled() { ConditionEvaluationResult result = new TestTestcontainersExtension(false) .evaluateExecutionCondition(extensionContext(DisabledWithoutDocker.class)); - assertTrue(result.isDisabled()); + assertThat(result.isDisabled()).isTrue(); } @Test void whenEnabledWithoutDockerAndDockerIsAvailableTestsAreEnabled() { ConditionEvaluationResult result = new TestTestcontainersExtension(true) .evaluateExecutionCondition(extensionContext(EnabledWithoutDocker.class)); - assertFalse(result.isDisabled()); + assertThat(result.isDisabled()).isFalse(); } @Test void whenEnabledWithoutDockerAndDockerIsUnavailableTestsAreEnabled() { ConditionEvaluationResult result = new TestTestcontainersExtension(false) .evaluateExecutionCondition(extensionContext(EnabledWithoutDocker.class)); - assertFalse(result.isDisabled()); + assertThat(result.isDisabled()).isFalse(); } private ExtensionContext extensionContext(Class clazz) { diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java index c41b184defa..f3d81a0dfcd 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedRestartedContainerTests.java @@ -4,8 +4,7 @@ import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; // testClass { @Testcontainers @@ -24,7 +23,7 @@ class TestcontainersNestedRestartedContainerTests { // testClass { @Test void top_level_container_should_be_running() { - assertTrue(topLevelContainer.isRunning()); + assertThat(topLevelContainer.isRunning()).isTrue(); // }} topLevelContainerId = topLevelContainer.getContainerId(); // testClass {{ @@ -40,14 +39,14 @@ class NestedTestCase { @Test void both_containers_should_be_running() { // top level container is restarted for nested methods - assertTrue(topLevelContainer.isRunning()); + assertThat(topLevelContainer.isRunning()).isTrue(); // nested containers are only available inside their nested class - assertTrue(nestedContainer.isRunning()); + assertThat(nestedContainer.isRunning()).isTrue(); // }}} if (nestedContainerId == null) { nestedContainerId = nestedContainer.getContainerId(); } else { - assertNotEquals(nestedContainerId, nestedContainer.getContainerId()); + assertThat(nestedContainer.getContainerId()).isNotEqualTo(nestedContainerId); } // testClass {{ } @@ -55,23 +54,23 @@ void both_containers_should_be_running() { // } @Test void containers_should_not_be_the_same() { - assertNotEquals(topLevelContainer.getContainerId(), nestedContainer.getContainerId()); + assertThat(nestedContainer.getContainerId()).isNotEqualTo(topLevelContainer.getContainerId()); if (nestedContainerId == null) { nestedContainerId = nestedContainer.getContainerId(); } else { - assertNotEquals(nestedContainerId, nestedContainer.getContainerId()); + assertThat(nestedContainer.getContainerId()).isNotEqualTo(nestedContainerId); } } @Test void ids_should_not_change() { - assertNotEquals(topLevelContainerId, topLevelContainer.getContainerId()); + assertThat(topLevelContainer.getContainerId()).isNotEqualTo(topLevelContainerId); if (nestedContainerId == null) { nestedContainerId = nestedContainer.getContainerId(); } else { - assertNotEquals(nestedContainerId, nestedContainer.getContainerId()); + assertThat(nestedContainer.getContainerId()).isNotEqualTo(nestedContainerId); } } // testClass {{{ diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java index c00e66c2d9d..61a4df2c6ec 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersNestedSharedContainerTests.java @@ -4,8 +4,7 @@ import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; @Testcontainers class TestcontainersNestedSharedContainerTests { @@ -20,7 +19,7 @@ class TestcontainersNestedSharedContainerTests { @Test void top_level_container_should_be_running() { - assertTrue(TOP_LEVEL_CONTAINER.isRunning()); + assertThat(TOP_LEVEL_CONTAINER.isRunning()).isTrue(); topLevelContainerId = TOP_LEVEL_CONTAINER.getContainerId(); } @@ -29,12 +28,12 @@ class NestedTestCase { @Test void top_level_containers_should_be_running() { - assertTrue(TOP_LEVEL_CONTAINER.isRunning()); + assertThat(TOP_LEVEL_CONTAINER.isRunning()).isTrue(); } @Test void ids_should_not_change() { - assertEquals(topLevelContainerId, TOP_LEVEL_CONTAINER.getContainerId()); + assertThat(TOP_LEVEL_CONTAINER.getContainerId()).isEqualTo(topLevelContainerId); } } } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java index 46c6045984f..53e6a0968a0 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersRestartBetweenTests.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.assertj.core.api.Assertions.assertThat; @Testcontainers class TestcontainersRestartBetweenTests { @@ -19,7 +19,7 @@ void first_test() { if (lastContainerId == null) { lastContainerId = genericContainer.getContainerId(); } else { - assertNotEquals(lastContainerId, genericContainer.getContainerId()); + assertThat(genericContainer.getContainerId()).isNotEqualTo(lastContainerId); } } @@ -28,7 +28,7 @@ void second_test() { if (lastContainerId == null) { lastContainerId = genericContainer.getContainerId(); } else { - assertNotEquals(lastContainerId, genericContainer.getContainerId()); + assertThat(genericContainer.getContainerId()).isNotEqualTo(lastContainerId); } } } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java index b23b2fe0e53..9bd23e8d20e 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestcontainersSharedContainerTests.java @@ -4,8 +4,7 @@ import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; @Testcontainers class TestcontainersSharedContainerTests { @@ -20,7 +19,7 @@ class TestcontainersSharedContainerTests { @BeforeAll static void doSomethingWithAContainer() { - assertTrue(GENERIC_CONTAINER.isRunning()); + assertThat(GENERIC_CONTAINER.isRunning()).isTrue(); } @Test @@ -28,7 +27,7 @@ void first_test() { if (lastContainerId == null) { lastContainerId = GENERIC_CONTAINER.getContainerId(); } else { - assertEquals(lastContainerId, GENERIC_CONTAINER.getContainerId()); + assertThat(GENERIC_CONTAINER.getContainerId()).isEqualTo(lastContainerId); } } @@ -37,7 +36,7 @@ void second_test() { if (lastContainerId == null) { lastContainerId = GENERIC_CONTAINER.getContainerId(); } else { - assertEquals(lastContainerId, GENERIC_CONTAINER.getContainerId()); + assertThat(GENERIC_CONTAINER.getContainerId()).isEqualTo(lastContainerId); } } } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java index adeaf58675c..f57fde6b419 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/inheritance/InheritedTests.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Test; import org.testcontainers.junit.jupiter.Container; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; class InheritedTests extends AbstractTestBase { @@ -12,15 +12,15 @@ class InheritedTests extends AbstractTestBase { @Test void step1() { - assertEquals(1, redisPerClass.getJedis().incr("key")); - assertEquals(1, redisPerTest.getJedis().incr("key")); - assertEquals(1, myRedis.getJedis().incr("key")); + assertThat(redisPerClass.getJedis().incr("key")).isEqualTo(1); + assertThat(redisPerTest.getJedis().incr("key")).isEqualTo(1); + assertThat(myRedis.getJedis().incr("key")).isEqualTo(1); } @Test void step2() { - assertEquals(2, redisPerClass.getJedis().incr("key")); - assertEquals(1, redisPerTest.getJedis().incr("key")); - assertEquals(1, myRedis.getJedis().incr("key")); + assertThat(redisPerClass.getJedis().incr("key")).isEqualTo(2); + assertThat(redisPerTest.getJedis().incr("key")).isEqualTo(1); + assertThat(myRedis.getJedis().incr("key")).isEqualTo(1); } } diff --git a/modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java b/modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java index 970e2390457..c2504c27dbe 100644 --- a/modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java +++ b/modules/k3s/src/test/java/org/testcontainers/k3s/OfficialClientK3sContainerTest.java @@ -6,7 +6,6 @@ import io.kubernetes.client.openapi.models.V1NodeList; import io.kubernetes.client.util.Config; import lombok.extern.slf4j.Slf4j; -import org.assertj.core.api.Assertions; import org.junit.Test; import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.utility.DockerImageName; @@ -14,6 +13,8 @@ import java.io.IOException; import java.io.StringReader; +import static org.assertj.core.api.Assertions.assertThat; + @Slf4j public class OfficialClientK3sContainerTest { @@ -37,7 +38,7 @@ public void shouldStartAndHaveListableNode() throws IOException, ApiException { V1NodeList nodes = api.listNode(null, null, null, null, null, null, null, null, null, null); // } - Assertions.assertThat(nodes.getItems()).hasSize(1); + assertThat(nodes.getItems()).hasSize(1); } } } diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 72149520b6a..8702d2e1a83 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -8,5 +8,5 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.273' testImplementation 'software.amazon.awssdk:s3:2.17.244' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java index c075d2805d6..a535699438f 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LegacyModeTest.java @@ -15,9 +15,7 @@ import java.util.Arrays; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Enclosed.class) public class LegacyModeTest { @@ -52,25 +50,25 @@ public void samePortIsExposedForAllServices() { localstack.start(); try { - assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); - assertEquals( - "Endpoint overrides are different", - localstack.getEndpointOverride(Service.S3).toString(), - localstack.getEndpointOverride(Service.SQS).toString() - ); - assertEquals( - "Endpoint configuration have different endpoints", - new AwsClientBuilder.EndpointConfiguration( - localstack.getEndpointOverride(Service.S3).toString(), - localstack.getRegion() - ) - .getServiceEndpoint(), + assertThat(localstack.getExposedPorts()).as("A single port is exposed").hasSize(1); + assertThat(localstack.getEndpointOverride(Service.SQS).toString()) + .as("Endpoint overrides are different") + .isEqualTo(localstack.getEndpointOverride(Service.S3).toString()); + assertThat( new AwsClientBuilder.EndpointConfiguration( localstack.getEndpointOverride(Service.SQS).toString(), localstack.getRegion() ) .getServiceEndpoint() - ); + ) + .as("Endpoint configuration have different endpoints") + .isEqualTo( + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() + ) + .getServiceEndpoint() + ); } finally { localstack.stop(); } @@ -117,25 +115,25 @@ public void differentPortsAreExposed() { localstack.start(); try { - assertTrue("Multiple ports are exposed", localstack.getExposedPorts().size() > 1); - assertNotEquals( - "Endpoint overrides are different", - localstack.getEndpointOverride(Service.S3).toString(), - localstack.getEndpointOverride(Service.SQS).toString() - ); - assertNotEquals( - "Endpoint configuration have different endpoints", - new AwsClientBuilder.EndpointConfiguration( - localstack.getEndpointOverride(Service.S3).toString(), - localstack.getRegion() - ) - .getServiceEndpoint(), + assertThat(localstack.getExposedPorts()).as("Multiple ports are exposed").hasSizeGreaterThan(1); + assertThat(localstack.getEndpointOverride(Service.SQS).toString()) + .as("Endpoint overrides are different") + .isNotEqualTo(localstack.getEndpointOverride(Service.S3).toString()); + assertThat( new AwsClientBuilder.EndpointConfiguration( localstack.getEndpointOverride(Service.SQS).toString(), localstack.getRegion() ) .getServiceEndpoint() - ); + ) + .as("Endpoint configuration have different endpoints") + .isNotEqualTo( + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() + ) + .getServiceEndpoint() + ); } finally { localstack.stop(); } diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index 950f29866ba..a678d30eb80 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -38,14 +38,11 @@ import software.amazon.awssdk.services.s3.S3Client; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Optional; -import static org.hamcrest.Matchers.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Tests for Localstack Container, used both in bridge network (exposed to host) and docker network modes. @@ -101,17 +98,17 @@ public void s3TestOverBridgeNetwork() throws IOException { .stream() .filter(b -> b.getName().equals(bucketName)) .findFirst(); - assertTrue("The created bucket is present", maybeBucket.isPresent()); + assertThat(maybeBucket).as("The created bucket is present").isPresent(); final Bucket bucket = maybeBucket.get(); - assertEquals("The created bucket has the right name", bucketName, bucket.getName()); + assertThat(bucket.getName()).as("The created bucket has the right name").isEqualTo(bucketName); final ObjectListing objectListing = s3.listObjects(bucketName); - assertEquals("The created bucket has 1 item in it", 1, objectListing.getObjectSummaries().size()); + assertThat(objectListing.getObjectSummaries()).as("The created bucket has 1 item in it").hasSize(1); final S3Object object = s3.getObject(bucketName, "bar"); - final String content = IOUtils.toString(object.getObjectContent(), Charset.forName("UTF-8")); - assertEquals("The object can be retrieved", "baz", content); + final String content = IOUtils.toString(object.getObjectContent(), StandardCharsets.UTF_8); + assertThat(content).as("The object can be retrieved").isEqualTo("baz"); } @Test @@ -131,10 +128,9 @@ public void s3TestUsingAwsSdkV2() { final String bucketName = "foov2"; s3.createBucket(b -> b.bucket(bucketName)); - assertTrue( - "New bucket was created", - s3.listBuckets().buckets().stream().anyMatch(b -> b.name().equals(bucketName)) - ); + assertThat(s3.listBuckets().buckets().stream().anyMatch(b -> b.name().equals(bucketName))) + .as("New bucket was created") + .isTrue(); } @Test @@ -156,16 +152,14 @@ public void sqsTestOverBridgeNetwork() { CreateQueueResult queueResult = sqs.createQueue("baz"); String fooQueueUrl = queueResult.getQueueUrl(); - assertThat( - "Created queue has external hostname URL", - fooQueueUrl, - containsString( + assertThat(fooQueueUrl) + .as("Created queue has external hostname URL") + .contains( "http://" + DockerClientFactory.instance().dockerHostIpAddress() + ":" + localstack.getMappedPort(LocalStackContainer.PORT) - ) - ); + ); sqs.sendMessage(fooQueueUrl, "test"); final long messageCount = sqs @@ -174,7 +168,7 @@ public void sqsTestOverBridgeNetwork() { .stream() .filter(message -> message.getBody().equals("test")) .count(); - assertEquals("the sent message can be received", 1L, messageCount); + assertThat(messageCount).as("the sent message can be received").isEqualTo(1L); } @Test @@ -197,8 +191,8 @@ public void cloudWatchLogsTestOverBridgeNetwork() { logs.createLogGroup(new CreateLogGroupRequest("foo")); List groups = logs.describeLogGroups().getLogGroups(); - assertEquals("One log group should be created", 1, groups.size()); - assertEquals("Name of created log group is [foo]", "foo", groups.get(0).getLogGroupName()); + assertThat(groups).as("One log group should be created").hasSize(1); + assertThat(groups.get(0).getLogGroupName()).as("Name of created log group is [foo]").isEqualTo("foo"); } @Test @@ -223,34 +217,32 @@ public void kmsKeyCreationTest() { CreateKeyRequest req = new CreateKeyRequest().withDescription(desc).withTags(createdByTag); CreateKeyResult key = awskms.createKey(req); - assertEquals( - "AWS KMS Customer Managed Key should be created ", - key.getKeyMetadata().getDescription(), - desc - ); + assertThat(desc) + .as("AWS KMS Customer Managed Key should be created ") + .isEqualTo(key.getKeyMetadata().getDescription()); } @Test public void samePortIsExposedForAllServices() { - assertTrue("A single port is exposed", localstack.getExposedPorts().size() == 1); - assertEquals( - "Endpoint overrides are different", - localstack.getEndpointOverride(Service.S3).toString(), - localstack.getEndpointOverride(Service.SQS).toString() - ); - assertEquals( - "Endpoint configuration have different endpoints", - new AwsClientBuilder.EndpointConfiguration( - localstack.getEndpointOverride(Service.S3).toString(), - localstack.getRegion() - ) - .getServiceEndpoint(), + assertThat(localstack.getExposedPorts()).as("A single port is exposed").hasSize(1); + assertThat(localstack.getEndpointOverride(Service.SQS).toString()) + .as("Endpoint overrides are different") + .isEqualTo(localstack.getEndpointOverride(Service.S3).toString()); + assertThat( new AwsClientBuilder.EndpointConfiguration( localstack.getEndpointOverride(Service.SQS).toString(), localstack.getRegion() ) .getServiceEndpoint() - ); + ) + .as("Endpoint configuration have different endpoints") + .isEqualTo( + new AwsClientBuilder.EndpointConfiguration( + localstack.getEndpointOverride(Service.S3).toString(), + localstack.getRegion() + ) + .getServiceEndpoint() + ); } } @@ -292,11 +284,9 @@ public void sqsTestOverDockerNetwork() throws Exception { "sqs create-queue --queue-name baz" ); - assertThat( - "Created queue has external hostname URL", - queueCreationResponse, - containsString("http://localstack:" + LocalStackContainer.PORT) - ); + assertThat(queueCreationResponse) + .as("Created queue has external hostname URL") + .contains("http://localstack:" + LocalStackContainer.PORT); runAwsCliAgainstDockerNetworkContainer( String.format( @@ -313,7 +303,7 @@ public void sqsTestOverDockerNetwork() throws Exception { ) ); - assertTrue("the sent message can be received", message.contains("\"Body\": \"test\"")); + assertThat(message).as("the sent message can be received").contains("\"Body\": \"test\""); } @Test @@ -356,11 +346,9 @@ public void s3EndpointHasProperRegion() { localstack.getEndpointOverride(Service.S3).toString(), localstack.getRegion() ); - assertEquals( - "The endpoint configuration has right region", - region, - endpointConfiguration.getSigningRegion() - ); + assertThat(endpointConfiguration.getSigningRegion()) + .as("The endpoint configuration has right region") + .isEqualTo(region); } } } diff --git a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java index 21a48b6e73c..e403a09b382 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/junit/mariadb/SimpleMariaDBTest.java @@ -9,11 +9,8 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class SimpleMariaDBTest extends AbstractContainerDatabaseTest { @@ -25,7 +22,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(mariadb, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -41,10 +38,9 @@ public void testSpecificVersion() throws SQLException { ResultSet resultSet = performQuery(mariadbOldVersion, "SELECT VERSION()"); String resultSetString = resultSet.getString(1); - assertTrue( - "The database version can be set using a container rule parameter", - resultSetString.startsWith("5.5.51") - ); + assertThat(resultSetString) + .as("The database version can be set using a container rule parameter") + .startsWith("5.5.51"); } } @@ -63,7 +59,7 @@ public void testMariaDBWithCustomIniFile() throws SQLException { ResultSet resultSet = performQuery(mariadbCustomConfig, "SELECT @@GLOBAL.innodb_file_format"); String result = resultSet.getString(1); - assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result); + assertThat(result).as("The InnoDB file format has been set by the ini file content").isEqualTo("Barracuda"); } } @@ -77,7 +73,7 @@ public void testMariaDBWithCommandOverride() throws SQLException { ResultSet resultSet = performQuery(mariadbCustomConfig, "show variables like 'auto_increment_increment'"); String result = resultSet.getString("Value"); - assertEquals("Auto increment increment should be overriden by command line", "10", result); + assertThat(result).as("Auto increment increment should be overriden by command line").isEqualTo("10"); } } @@ -90,10 +86,10 @@ public void testWithAdditionalUrlParamInJdbcUrl() { try { mariaDBContainer.start(); String jdbcUrl = mariaDBContainer.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); - assertThat(jdbcUrl, containsString("connectTimeout=40000")); + assertThat(jdbcUrl).contains("?"); + assertThat(jdbcUrl).contains("&"); + assertThat(jdbcUrl).contains("rewriteBatchedStatements=true"); + assertThat(jdbcUrl).contains("connectTimeout=40000"); } finally { mariaDBContainer.stop(); } diff --git a/modules/mockserver/build.gradle b/modules/mockserver/build.gradle index 9ea504ca74a..2156ef045cd 100644 --- a/modules/mockserver/build.gradle +++ b/modules/mockserver/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':testcontainers') testImplementation 'org.mock-server:mockserver-client-java:5.5.4' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java index 3f34d000603..84d472f5e75 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java @@ -5,10 +5,9 @@ import org.mockserver.client.MockServerClient; import org.testcontainers.utility.DockerImageName; -import static org.hamcrest.Matchers.containsString; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; public class MockServerContainerRuleTest { @@ -37,10 +36,8 @@ public void shouldReturnExpectation() throws Exception { // } // spotless:on - assertThat( - "Expectation returns expected response body", - SimpleHttpClient.responseFromMockserver(mockServer, "/person?name=peter"), - containsString("Peter the person") - ); + assertThat(SimpleHttpClient.responseFromMockserver(mockServer, "/person?name=peter")) + .as("Expectation returns expected response body") + .contains("Peter the person"); } } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index d038b111824..6ddce4b6cbf 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -4,11 +4,9 @@ import org.mockserver.client.MockServerClient; import org.testcontainers.utility.DockerImageName; -import static org.hamcrest.Matchers.equalTo; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; public class MockServerContainerTest { @@ -30,15 +28,13 @@ public void shouldCallActualMockserverVersion() throws Exception { MockServerClient client = new MockServerClient(mockServer.getHost(), mockServer.getServerPort()); - assertTrue("Mockserver running", client.isRunning()); + assertThat(client.isRunning()).as("Mockserver running").isTrue(); client.when(request().withPath("/hello")).respond(response().withBody(expectedBody)); - assertThat( - "MockServer returns correct result", - SimpleHttpClient.responseFromMockserver(mockServer, "/hello"), - equalTo(expectedBody) - ); + assertThat(SimpleHttpClient.responseFromMockserver(mockServer, "/hello")) + .as("MockServer returns correct result") + .isEqualTo(expectedBody); } } diff --git a/modules/mockserver/src/test/resources/logback-test.xml b/modules/mockserver/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/mockserver/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java index 49bae13d9e3..97904c6b7d1 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java @@ -10,7 +10,7 @@ import java.util.Arrays; import java.util.Collection; -import static org.rnorth.visibleassertions.VisibleAssertions.fail; +import static org.assertj.core.api.Assertions.fail; /** * Tests if the password passed to the container satisfied the password policy described at diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java index 21ea5380801..4cfc34f9e73 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java @@ -8,7 +8,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class CustomizableMSSQLServerTest extends AbstractContainerDatabaseTest { @@ -26,7 +26,7 @@ public void testSqlServerConnection() throws SQLException { ResultSet resultSet = performQuery(mssqlServerContainer, mssqlServerContainer.getTestQueryString()); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } } diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index 36d215c8757..15edbaa2ca1 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -11,9 +11,7 @@ import javax.sql.DataSource; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest { @@ -26,7 +24,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(mssqlServer, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -40,7 +38,7 @@ public void testWithAdditionalUrlParamInJdbcUrl() { mssqlServer.start(); String jdbcUrl = mssqlServer.getJdbcUrl(); - assertThat(jdbcUrl, containsString(";integratedSecurity=false;applicationName=MyApp")); + assertThat(jdbcUrl).contains(";integratedSecurity=false;applicationName=MyApp"); } } @@ -63,7 +61,7 @@ public void testSetupDatabase() throws SQLException { resultSet.next(); int resultSetInt = resultSet.getInt("ID"); - assertEquals("A basic SELECT query succeeds", 3, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(3); } } } diff --git a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java index a30f3f59888..254f58807b7 100644 --- a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/JDBCDriverWithPoolTest.java @@ -21,7 +21,7 @@ import javax.sql.DataSource; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * This test belongs in the jdbc module, as it is focused on testing the behaviour of {@link org.testcontainers.containers.JdbcDatabaseContainer}. @@ -82,7 +82,7 @@ public void testMySQLWithConnectionPoolUsingSameContainer() throws SQLException, return rs.getInt(1); } ); - assertEquals("Reuse of a datasource points to the same DB container", 100, count); + assertThat(count).as("Reuse of a datasource points to the same DB container").isEqualTo(100); int sum = new QueryRunner(dataSource) .query( @@ -93,7 +93,7 @@ public void testMySQLWithConnectionPoolUsingSameContainer() throws SQLException, } ); // 100 records * 5 = 500 expected - assertEquals("Reuse of a datasource points to the same DB container", 500, sum); + assertThat(sum).as("Reuse of a datasource points to the same DB container").isEqualTo(500); } private static DataSource getTomcatDataSourceWithDriverClassName() { diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java index 20b49d19201..f0a4f5d24ea 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/CustomizableMysqlTest.java @@ -8,7 +8,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class CustomizableMysqlTest extends AbstractContainerDatabaseTest { @@ -33,7 +33,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(mysql, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } } diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java index 735af251236..8a6c17c538e 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/MultiVersionMySQLTest.java @@ -11,7 +11,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Parameterized.class) public class MultiVersionMySQLTest extends AbstractContainerDatabaseTest { @@ -35,11 +35,9 @@ public void versionCheckTest() throws SQLException { final ResultSet resultSet = performQuery(mysql, "SELECT VERSION()"); final String resultSetString = resultSet.getString(1); - assertEquals( - "The database version can be set using a container rule parameter", - dockerImageName.getVersionPart(), - resultSetString - ); + assertThat(resultSetString) + .as("The database version can be set using a container rule parameter") + .isEqualTo(dockerImageName.getVersionPart()); } } } diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index 6441724c443..146010058ac 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -19,12 +19,9 @@ import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; import static org.junit.Assume.assumeFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; -import static org.rnorth.visibleassertions.VisibleAssertions.fail; public class SimpleMySQLTest extends AbstractContainerDatabaseTest { @@ -59,7 +56,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(mysql, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -75,10 +72,9 @@ public void testSpecificVersion() throws SQLException { ResultSet resultSet = performQuery(mysqlOldVersion, "SELECT VERSION()"); String resultSetString = resultSet.getString(1); - assertTrue( - "The database version can be set using a container rule parameter", - resultSetString.startsWith("5.6") - ); + assertThat(resultSetString) + .as("The database version can be set using a container rule parameter") + .startsWith("5.6"); } } @@ -95,7 +91,7 @@ public void testMySQLWithCustomIniFile() throws SQLException { ResultSet resultSet = performQuery(mysqlCustomConfig, "SELECT @@GLOBAL.innodb_file_format"); String result = resultSet.getString(1); - assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result); + assertThat(result).as("The InnoDB file format has been set by the ini file content").isEqualTo("Barracuda"); } } @@ -110,7 +106,7 @@ public void testCommandOverride() throws SQLException { ResultSet resultSet = performQuery(mysqlCustomConfig, "show variables like 'auto_increment_increment'"); String result = resultSet.getString("Value"); - assertEquals("Auto increment increment should be overriden by command line", "42", result); + assertThat(result).as("Auto increment increment should be overriden by command line").isEqualTo("42"); } } @@ -126,7 +122,7 @@ public void testExplicitInitScript() throws SQLException { ResultSet resultSet = performQuery(container, "SELECT foo FROM bar"); String firstColumnValue = resultSet.getString(1); - assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + assertThat(firstColumnValue).as("Value from init script should equal real value").isEqualTo("hello world"); } } @@ -159,7 +155,7 @@ public void testEmptyPasswordWithRootUser() throws SQLException { ResultSet resultSet = performQuery(mysql, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -191,7 +187,7 @@ public void testWithAdditionalUrlParamTimeZone() throws SQLException { actualDateTime, expectedDateTime ); - assertTrue(message, actualDateTime.equals(expectedDateTime)); + assertThat(actualDateTime).as(message).isEqualTo(expectedDateTime); } } finally { mysql.stop(); @@ -216,7 +212,7 @@ public void testWithAdditionalUrlParamMultiQueries() throws SQLException { try (ResultSet resultSet = statement.getResultSet()) { resultSet.next(); String firstColumnValue = resultSet.getString(1); - assertEquals("Value from bar should equal real value", "hello world", firstColumnValue); + assertThat(firstColumnValue).as("Value from bar should equal real value").isEqualTo("hello world"); } } finally { mysql.stop(); @@ -233,10 +229,10 @@ public void testWithAdditionalUrlParamInJdbcUrl() { try { mysql.start(); String jdbcUrl = mysql.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("rewriteBatchedStatements=true")); - assertThat(jdbcUrl, containsString("allowMultiQueries=true")); + assertThat(jdbcUrl).contains("?"); + assertThat(jdbcUrl).contains("&"); + assertThat(jdbcUrl).contains("rewriteBatchedStatements=true"); + assertThat(jdbcUrl).contains("allowMultiQueries=true"); } finally { mysql.stop(); } diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java index 20cd38dc70c..de5420afd88 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java @@ -1,6 +1,5 @@ package org.testcontainers.containers; -import org.assertj.core.api.Assertions; import org.junit.Test; import org.neo4j.driver.AuthToken; import org.neo4j.driver.AuthTokens; @@ -13,8 +12,7 @@ import java.util.Collections; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assumptions.assumeThat; /** @@ -64,16 +62,14 @@ public void shouldCopyDatabase() { @Test public void shouldFailOnCopyDatabaseForDefaultNeo4j4Image() { - Assertions - .assertThatIllegalArgumentException() + assertThatIllegalArgumentException() .isThrownBy(() -> new Neo4jContainer<>().withDatabase(MountableFile.forClasspathResource("/test-graph.db"))) .withMessage("Copying database folder is not supported for Neo4j instances with version 4.0 or higher."); } @Test public void shouldFailOnCopyDatabaseForCustomNeo4j4Image() { - Assertions - .assertThatIllegalArgumentException() + assertThatIllegalArgumentException() .isThrownBy(() -> { new Neo4jContainer<>("neo4j:4.4.1").withDatabase(MountableFile.forClasspathResource("/test-graph.db")); }) @@ -82,8 +78,7 @@ public void shouldFailOnCopyDatabaseForCustomNeo4j4Image() { @Test public void shouldFailOnCopyDatabaseForCustomNonSemverNeo4j4Image() { - Assertions - .assertThatIllegalArgumentException() + assertThatIllegalArgumentException() .isThrownBy(() -> { new Neo4jContainer<>("neo4j:latest").withDatabase(MountableFile.forClasspathResource("/test-graph.db")); }) diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index 288b45b027a..aee69e253ad 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Nginx" dependencies { api project(':testcontainers') compileOnly 'org.jetbrains:annotations:23.0.0' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java index c1ba3d30684..24e913cf281 100644 --- a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java +++ b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java @@ -12,8 +12,7 @@ import java.net.URL; import java.net.URLConnection; -import static org.hamcrest.Matchers.containsString; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.assertj.core.api.Assertions.assertThat; /** * @author richardnorth @@ -55,11 +54,9 @@ public void testSimple() throws Exception { // getFromNginxServer { URL baseUrl = nginx.getBaseUrl("http", 80); - assertThat( - "An HTTP GET from the Nginx server returns the index.html from the custom content directory", - responseFromNginx(baseUrl), - containsString("Hello World!") - ); + assertThat(responseFromNginx(baseUrl)) + .as("An HTTP GET from the Nginx server returns the index.html from the custom content directory") + .contains("Hello World!"); // } } diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java index 003941f4dfc..5e44f0d368c 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java @@ -9,7 +9,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class OracleJDBCDriverTest { @@ -28,7 +28,7 @@ private void performSimpleTest(String jdbcUrl) throws SQLException { public Object handle(ResultSet rs) throws SQLException { rs.next(); int resultSetInt = rs.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); return true; } } diff --git a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java index 675218637ce..6cf0e2e8ea9 100644 --- a/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java +++ b/modules/orientdb/src/test/java/org/testcontainers/containers/OrientDBContainerTest.java @@ -4,7 +4,7 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; /** * @author robfrank diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java index 3be7685ea27..275517250b6 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLConnectionURLTest.java @@ -3,10 +3,8 @@ import org.junit.Test; import org.testcontainers.PostgreSQLTestImages; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertFalse; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; public class PostgreSQLConnectionURLTest { @@ -16,12 +14,11 @@ public void shouldCorrectlyAppendQueryString() { String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); - assertTrue( - "Query String contains expected params", - queryString.contains("?stringtype=unspecified&stringtype=unspecified") - ); - assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); - assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); + assertThat(queryString) + .as("Query String contains expected params") + .contains("?stringtype=unspecified&stringtype=unspecified"); + assertThat(queryString.indexOf('?')).as("Query String starts with '?'").isZero(); + assertThat(queryString.substring(1)).as("Query String does not contain extra '?'").doesNotContain("?"); } @Test @@ -30,12 +27,11 @@ public void shouldCorrectlyAppendQueryStringWhenNoBaseParams() { String connectionUrl = postgres.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); - assertTrue( - "Query String contains expected params", - queryString.contains("?stringtype=unspecified&stringtype=unspecified") - ); - assertEquals("Query String starts with '?'", 0, queryString.indexOf('?')); - assertFalse("Query String does not contain extra '?'", queryString.substring(1).contains("?")); + assertThat(queryString) + .as("Query String contains expected params") + .contains("?stringtype=unspecified&stringtype=unspecified"); + assertThat(queryString.indexOf('?')).as("Query String starts with '?'").isZero(); + assertThat(queryString.substring(1)).as("Query String does not contain extra '?'").doesNotContain("?"); } @Test @@ -43,16 +39,18 @@ public void shouldReturnOriginalURLWhenEmptyQueryString() { PostgreSQLContainer postgres = new FixedJdbcUrlPostgreSQLContainer(); String connectionUrl = postgres.constructUrlForConnection(""); - assertTrue("Query String remains unchanged", postgres.getJdbcUrl().equals(connectionUrl)); + assertThat(postgres.getJdbcUrl()).as("Query String remains unchanged").isEqualTo(connectionUrl); } @Test public void shouldRejectInvalidQueryString() { - assertThrows( - "Fails when invalid query string provided", - IllegalArgumentException.class, - () -> new NoParamsUrlPostgreSQLContainer().constructUrlForConnection("stringtype=unspecified") - ); + assertThat( + catchThrowable(() -> { + new NoParamsUrlPostgreSQLContainer().constructUrlForConnection("stringtype=unspecified"); + }) + ) + .as("Fails when invalid query string provided") + .isInstanceOf(IllegalArgumentException.class); } static class FixedJdbcUrlPostgreSQLContainer extends PostgreSQLContainer { diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java index 74d60b2d32d..f49c7dc6aa7 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/TimescaleDBContainerTest.java @@ -6,8 +6,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; +import static org.assertj.core.api.Assertions.assertThat; public class TimescaleDBContainerTest extends AbstractContainerDatabaseTest { @@ -18,7 +17,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -36,7 +35,7 @@ public void testCommandOverride() throws SQLException { "SELECT current_setting('max_connections')" ); String result = resultSet.getString(1); - assertEquals("max_connections should be overriden", "42", result); + assertThat(result).as("max_connections should be overriden").isEqualTo("42"); } } @@ -55,7 +54,7 @@ public void testUnsetCommand() throws SQLException { "SELECT current_setting('max_connections')" ); String result = resultSet.getString(1); - assertNotEquals("max_connections should not be overriden", "42", result); + assertThat(result).as("max_connections should not be overriden").isNotEqualTo("42"); } } @@ -71,7 +70,7 @@ public void testExplicitInitScript() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); String firstColumnValue = resultSet.getString(1); - assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + assertThat(firstColumnValue).as("Value from init script should equal real value").isEqualTo("hello world"); } } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java index 5acbd875c23..ed519ed2e4b 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverShutdownTest.java @@ -8,9 +8,7 @@ import java.sql.DriverManager; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNull; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * This test belongs in the jdbc module, as it is focused on testing the behaviour of {@link org.testcontainers.containers.JdbcDatabaseContainer}. @@ -32,7 +30,7 @@ public void shouldStopContainerWhenAllConnectionsClosed() throws SQLException { getConnectionAndClose(jdbcUrl); JdbcDatabaseContainer container = ContainerDatabaseDriver.getContainer(jdbcUrl); - assertNull("Database container instance is null as expected", container); + assertThat(container).as("Database container instance is null as expected").isNull(); } @Test @@ -42,13 +40,13 @@ public void shouldNotStopDaemonContainerWhenAllConnectionsClosed() throws SQLExc getConnectionAndClose(jdbcUrl); JdbcDatabaseContainer container = ContainerDatabaseDriver.getContainer(jdbcUrl); - assertNotNull("Database container instance is not null as expected", container); - assertTrue("Database container is running as expected", container.isRunning()); + assertThat(container).as("Database container instance is not null as expected").isNotNull(); + assertThat(container.isRunning()).as("Database container is running as expected").isTrue(); } private void getConnectionAndClose(String jdbcUrl) throws SQLException { try (Connection connection = DriverManager.getConnection(jdbcUrl)) { - assertNotNull("Obtained connection as expected", connection); + assertThat(connection).as("Obtained connection as expected").isNotNull(); } } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java index 4c8d6afeef0..463981d2d59 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/jdbc/DatabaseDriverTmpfsTest.java @@ -7,8 +7,7 @@ import java.sql.Connection; import java.sql.DriverManager; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * This test belongs in the jdbc module, as it is focused on testing the behaviour of {@link org.testcontainers.containers.JdbcDatabaseContainer}. @@ -26,11 +25,13 @@ public void testDatabaseHasTmpFsViaConnectionString() throws Exception { // check file doesn't exist String path = "/testtmpfs/test.file"; Container.ExecResult execResult = container.execInContainer("ls", path); - assertNotEquals("tmpfs inside container doesn't have file that doesn't exist", 0, execResult.getExitCode()); + assertThat(execResult.getExitCode()) + .as("tmpfs inside container doesn't have file that doesn't exist") + .isNotZero(); // touch && check file does exist container.execInContainer("touch", path); execResult = container.execInContainer("ls", path); - assertEquals("tmpfs inside container has file that does exist", 0, execResult.getExitCode()); + assertThat(execResult.getExitCode()).as("tmpfs inside container has file that does exist").isZero(); } } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java index 1b256c0fd6b..6dea67c9e26 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java @@ -8,7 +8,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * @author richardnorth @@ -34,7 +34,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 2a0dd351ad6..2a7db242421 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -10,10 +10,7 @@ import java.util.logging.Level; import java.util.logging.LogManager; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertNotEquals; +import static org.assertj.core.api.Assertions.assertThat; public class SimplePostgreSQLTest extends AbstractContainerDatabaseTest { static { @@ -28,7 +25,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } @@ -42,7 +39,7 @@ public void testCommandOverride() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); String result = resultSet.getString(1); - assertEquals("max_connections should be overriden", "42", result); + assertThat(result).as("max_connections should be overriden").isEqualTo("42"); } } @@ -57,7 +54,7 @@ public void testUnsetCommand() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT current_setting('max_connections')"); String result = resultSet.getString(1); - assertNotEquals("max_connections should not be overriden", "42", result); + assertThat(result).as("max_connections should not be overriden").isNotEqualTo("42"); } } @@ -72,7 +69,7 @@ public void testExplicitInitScript() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar"); String firstColumnValue = resultSet.getString(1); - assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + assertThat(firstColumnValue).as("Value from init script should equal real value").isEqualTo("hello world"); } } @@ -84,9 +81,9 @@ public void testWithAdditionalUrlParamInJdbcUrl() { ) { postgres.start(); String jdbcUrl = postgres.getJdbcUrl(); - assertThat(jdbcUrl, containsString("?")); - assertThat(jdbcUrl, containsString("&")); - assertThat(jdbcUrl, containsString("charSet=UNICODE")); + assertThat(jdbcUrl).contains("?"); + assertThat(jdbcUrl).contains("&"); + assertThat(jdbcUrl).contains("charSet=UNICODE"); } } } diff --git a/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java b/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java index 3772e6d49a6..9ae49b00bd1 100644 --- a/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java +++ b/modules/r2dbc/src/test/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactoryTest.java @@ -6,7 +6,6 @@ import io.r2dbc.spi.ConnectionFactories; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.Result; -import org.assertj.core.api.Assertions; import org.junit.Test; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -14,14 +13,14 @@ import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class TestcontainersR2DBCConnectionFactoryTest { @Test public void failsOnUnknownProvider() { String nonExistingProvider = UUID.randomUUID().toString(); - Assertions - .assertThatThrownBy(() -> { + assertThatThrownBy(() -> { ConnectionFactories.get(String.format("r2dbc:tc:%s:///db", nonExistingProvider)); }) .hasMessageContaining("Missing provider") @@ -64,8 +63,7 @@ public void reusesUntilConnectionFactoryIsClosed() { close(connectionFactory); - Assertions - .assertThatThrownBy(select::blockFirst) + assertThatThrownBy(select::blockFirst) .isInstanceOf(PostgresqlException.class) // relation "X" does not exists // https://github.com/postgres/postgres/blob/REL_10_0/src/backend/utils/errcodes.txt#L349 diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index 5f0824f8b12..38fab63dc0a 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -10,7 +10,7 @@ dependencies { testImplementation 'org.mortbay.jetty:jetty:6.1.26' testImplementation project(':nginx') - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' compileOnly 'org.jetbrains:annotations:23.0.0' testCompileClasspath 'org.jetbrains:annotations:23.0.0' diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java index d0865a06b09..c49e24ba867 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java @@ -13,8 +13,7 @@ import java.util.concurrent.TimeUnit; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -41,13 +40,15 @@ protected static void doSimpleExplore(BrowserWebDriverContainer rule) { driver.get("http://helloworld:8080"); WebElement title = driver.findElement(By.tagName("h1")); - assertEquals("the index page contains the title 'Hello world'", "Hello world", title.getText().trim()); + assertThat(title.getText().trim()) + .as("the index page contains the title 'Hello world'") + .isEqualTo("Hello world"); } protected void assertBrowserNameIs(BrowserWebDriverContainer rule, String expectedName) { RemoteWebDriver driver = setupDriverFromRule(rule); String actual = driver.getCapabilities().getBrowserName(); - assertTrue(String.format("actual browser name is %s", actual), actual.equals(expectedName)); + assertThat(actual).as(String.format("actual browser name is %s", actual)).isEqualTo(expectedName); } @NotNull diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java index 60d113dc290..370d9cffedb 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BrowserWebDriverContainerTest.java @@ -13,7 +13,7 @@ import java.util.List; import java.util.stream.Collectors; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class BrowserWebDriverContainerTest { @@ -31,7 +31,7 @@ public void honorPresetNoProxyEnvironment() { chromeWithNoProxySet.start(); Object noProxy = chromeWithNoProxySet.getEnvMap().get(NO_PROXY_KEY); - assertEquals("no_proxy should be preserved by the container rule", NO_PROXY_VALUE, noProxy); + assertThat(noProxy).as("no_proxy should be preserved by the container rule").isEqualTo(NO_PROXY_VALUE); } } @@ -44,7 +44,7 @@ public void provideDefaultNoProxyEnvironmentIfNotSet() { chromeWithoutNoProxySet.start(); Object noProxy = chromeWithoutNoProxySet.getEnvMap().get(NO_PROXY_KEY); - assertEquals("no_proxy should be set to default if not already present", "localhost", noProxy); + assertThat(noProxy).as("no_proxy should be set to default if not already present").isEqualTo("localhost"); } } @@ -59,9 +59,9 @@ public void createContainerWithShmVolume() { final List shmVolumes = shmVolumes(webDriverContainer); - assertEquals("Only one shm mount present", 1, shmVolumes.size()); - assertEquals("Shm mount source is correct", "/dev/shm", shmVolumes.get(0).getSource()); - assertEquals("Shm mount mode is correct", "rw", shmVolumes.get(0).getMode()); + assertThat(shmVolumes).as("Only one shm mount present").hasSize(1); + assertThat(shmVolumes.get(0).getSource()).as("Shm mount source is correct").isEqualTo("/dev/shm"); + assertThat(shmVolumes.get(0).getMode()).as("Shm mount mode is correct").isEqualTo("rw"); } } @@ -74,9 +74,11 @@ public void createContainerWithoutShmVolume() { ) { webDriverContainer.start(); - assertEquals("Shared memory size is configured", 512 * FileUtils.ONE_MB, webDriverContainer.getShmSize()); + assertThat(webDriverContainer.getShmSize()) + .as("Shared memory size is configured") + .isEqualTo(512 * FileUtils.ONE_MB); - assertEquals("No shm mounts present", Collections.emptyList(), shmVolumes(webDriverContainer)); + assertThat(shmVolumes(webDriverContainer)).as("No shm mounts present").isEqualTo(Collections.emptyList()); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java index 2d2feb6aaff..88b40f4fbbe 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/LocalServerWebDriverContainerTest.java @@ -10,7 +10,7 @@ import org.testcontainers.Testcontainers; import org.testcontainers.containers.BrowserWebDriverContainer; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * Test that a browser running in a container can access a web server hosted on the host machine (i.e. the one running @@ -53,10 +53,8 @@ public void testConnection() { String headingText = driver.findElement(By.cssSelector("h1")).getText().trim(); - assertEquals( - "The hardcoded success message was found on a page fetched from a local server", - "It worked", - headingText - ); + assertThat(headingText) + .as("The hardcoded success message was found on a page fetched from a local server") + .isEqualTo("It worked"); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java index 4cbfca77d21..6208cb3a5bb 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/SeleniumUtilsTest.java @@ -6,7 +6,7 @@ import java.io.IOException; import java.util.jar.Manifest; -import static org.rnorth.visibleassertions.VisibleAssertions.*; +import static org.assertj.core.api.Assertions.assertThat; /** * Created by Julien LAMY @@ -32,6 +32,8 @@ private void checkSeleniumVersionDetected(String urlManifest, String expectedVer Manifest manifest = new Manifest(); manifest.read(this.getClass().getClassLoader().getResourceAsStream(urlManifest)); String seleniumVersion = SeleniumUtils.getSeleniumVersionFromManifest(manifest); - assertEquals("Check if Selenium Version detected is the correct one.", expectedVersion, seleniumVersion); + assertThat(seleniumVersion) + .as("Check if Selenium Version detected is the correct one.") + .isEqualTo(expectedVersion); } } diff --git a/modules/toxiproxy/build.gradle b/modules/toxiproxy/build.gradle index a1e5f58551a..afe76308ba6 100644 --- a/modules/toxiproxy/build.gradle +++ b/modules/toxiproxy/build.gradle @@ -5,7 +5,7 @@ dependencies { api 'eu.rekawek.toxiproxy:toxiproxy-java:2.1.7' testImplementation 'redis.clients:jedis:3.0.1' - testImplementation 'org.rnorth.visible-assertions:visible-assertions:2.1.2' + testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation project(':test-support') } diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index c5982bc45c1..bfe488eaac1 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -10,9 +10,8 @@ import java.io.IOException; import java.time.Duration; -import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; -import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; -import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; public class ToxiproxyTest { @@ -53,7 +52,7 @@ public void testDirect() { jedis.set("somekey", "somevalue"); final String s = jedis.get("somekey"); - assertEquals("direct access to the container works OK", "somevalue", s); + assertThat(s).as("direct access to the container works OK").isEqualTo("somevalue"); } @Test @@ -90,32 +89,28 @@ public void testConnectionCut() { final Jedis jedis = createJedis(proxy.getContainerIpAddress(), proxy.getProxyPort()); jedis.set("somekey", "somevalue"); - assertEquals( - "access to the container works OK before cutting the connection", - "somevalue", - jedis.get("somekey") - ); + assertThat(jedis.get("somekey")) + .as("access to the container works OK before cutting the connection") + .isEqualTo("somevalue"); // disableProxy { proxy.setConnectionCut(true); // for example, expect failure when the connection is cut - assertThrows( - "calls fail when the connection is cut", - JedisConnectionException.class, - () -> { + assertThat( + catchThrowable(() -> { jedis.get("somekey"); - } - ); + }) + ) + .as("calls fail when the connection is cut") + .isInstanceOf(JedisConnectionException.class); proxy.setConnectionCut(false); // and with the connection re-established, expect success - assertEquals( - "access to the container works OK after re-establishing the connection", - "somevalue", - jedis.get("somekey") - ); + assertThat(jedis.get("somekey")) + .as("access to the container works OK after re-establishing the connection") + .isEqualTo("somevalue"); // } } @@ -139,15 +134,15 @@ public void testMultipleProxiesCanBeCreated() { firstProxy.setConnectionCut(true); - assertThrows( - "calls fail when the connection is cut, for only the relevant proxy", - JedisConnectionException.class, - () -> { + assertThat( + catchThrowable(() -> { firstJedis.get("somekey"); - } - ); + }) + ) + .as("calls fail when the connection is cut, for only the relevant proxy") + .isInstanceOf(JedisConnectionException.class); - assertEquals("access via a different proxy is OK", "somevalue", secondJedis.get("somekey")); + assertThat(secondJedis.get("somekey")).as("access via a different proxy is OK").isEqualTo("somevalue"); } } @@ -158,38 +153,34 @@ public void testOriginalAndMappedPorts() { final String hostViaToxiproxy = TOXIPROXY_NETWORK_ALIAS; final int portViaToxiproxy = proxy.getOriginalProxyPort(); // } - assertEquals("host is correct", TOXIPROXY_NETWORK_ALIAS, hostViaToxiproxy); - assertEquals("original port is correct", 8666, portViaToxiproxy); + assertThat(hostViaToxiproxy).as("host is correct").isEqualTo(TOXIPROXY_NETWORK_ALIAS); + assertThat(portViaToxiproxy).as("original port is correct").isEqualTo(8666); final ToxiproxyContainer.ContainerProxy proxy1 = toxiproxy.getProxy("hostname1", 8080); - assertEquals("original port is correct", 8667, proxy1.getOriginalProxyPort()); - assertEquals( - "mapped port is correct", - toxiproxy.getMappedPort(proxy1.getOriginalProxyPort()), - proxy1.getProxyPort() - ); + assertThat(proxy1.getOriginalProxyPort()).as("original port is correct").isEqualTo(8667); + assertThat(proxy1.getProxyPort()) + .as("mapped port is correct") + .isEqualTo(toxiproxy.getMappedPort(proxy1.getOriginalProxyPort())); final ToxiproxyContainer.ContainerProxy proxy2 = toxiproxy.getProxy("hostname2", 9090); - assertEquals("original port is correct", 8668, proxy2.getOriginalProxyPort()); - assertEquals( - "mapped port is correct", - toxiproxy.getMappedPort(proxy2.getOriginalProxyPort()), - proxy2.getProxyPort() - ); + assertThat(proxy2.getOriginalProxyPort()).as("original port is correct").isEqualTo(8668); + assertThat(proxy2.getProxyPort()) + .as("mapped port is correct") + .isEqualTo(toxiproxy.getMappedPort(proxy2.getOriginalProxyPort())); } @Test public void testProxyName() { final ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy("hostname", 7070); - assertEquals("proxy name is hostname and port", "hostname:7070", proxy.getName()); + assertThat(proxy.getName()).as("proxy name is hostname and port").isEqualTo("hostname:7070"); } @Test public void testControlPort() { final int controlPort = toxiproxy.getControlPort(); - assertEquals("control port is mapped from port 8474", toxiproxy.getMappedPort(8474), controlPort); + assertThat(controlPort).as("control port is mapped from port 8474").isEqualTo(toxiproxy.getMappedPort(8474)); } private void checkCallWithLatency( @@ -203,15 +194,13 @@ private void checkCallWithLatency( final long end = System.currentTimeMillis(); final long duration = end - start; - assertEquals(String.format("access to the container %s works OK", description), "somevalue", s); - assertTrue( - String.format("%s there is at least %dms latency", description, expectedMinLatency), - duration >= expectedMinLatency - ); - assertTrue( - String.format("%s there is no more than %dms latency", description, expectedMaxLatency), - duration < expectedMaxLatency - ); + assertThat(s).as(String.format("access to the container %s works OK", description)).isEqualTo("somevalue"); + assertThat(duration >= expectedMinLatency) + .as(String.format("%s there is at least %dms latency", description, expectedMinLatency)) + .isTrue(); + assertThat(duration < expectedMaxLatency) + .as(String.format("%s there is no more than %dms latency", description, expectedMaxLatency)) + .isTrue(); } private static Jedis createJedis(String host, int port) { From 7c70a8af559935fe6474848cd30241a2731d484f Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 9 Aug 2022 09:14:55 +0100 Subject: [PATCH 2103/4969] Removes unused module junit-toolbox (#5678) Co-authored-by: Kevin Wittek --- modules/jdbc/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 6047a3c0f3e..43ff0968715 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -9,6 +9,8 @@ dependencies { testImplementation 'org.vibur:vibur-dbcp:25.0' testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.23' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' - testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4' testImplementation 'org.assertj:assertj-core:3.23.1' + testImplementation ('org.mockito:mockito-core:4.6.1') { + exclude(module: 'hamcrest-core') + } } From 54d7f3931d8856e7a53b8d1b2646aff0faa3dbf2 Mon Sep 17 00:00:00 2001 From: Cheese Date: Mon, 15 Aug 2022 22:01:46 +0800 Subject: [PATCH 2104/4969] Add TiDB module (#5511) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sergei Egorov Co-authored-by: Kevin Wittek Co-authored-by: Eddú Meléndez Gonzales --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 + .github/labeler.yml | 2 + docs/modules/databases/jdbc.md | 4 + docs/modules/databases/tidb.md | 25 ++++ mkdocs.yml | 1 + modules/tidb/build.gradle | 10 ++ modules/tidb/sql/init_mysql.sql | 5 + .../testcontainers/tidb/TiDBContainer.java | 126 ++++++++++++++++++ .../tidb/TiDBContainerProvider.java | 32 +++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../org/testcontainers/TiDBTestImages.java | 8 ++ .../jdbc/tidb/TiDBJDBCDriverTest.java | 19 +++ .../junit/tidb/SimpleTiDBTest.java | 54 ++++++++ .../tidb/src/test/resources/logback-test.xml | 16 +++ .../src/test/resources/somepath/init_tidb.sql | 16 +++ 18 files changed, 327 insertions(+) create mode 100644 docs/modules/databases/tidb.md create mode 100644 modules/tidb/build.gradle create mode 100644 modules/tidb/sql/init_mysql.sql create mode 100644 modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java create mode 100644 modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainerProvider.java create mode 100644 modules/tidb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/tidb/src/test/java/org/testcontainers/TiDBTestImages.java create mode 100644 modules/tidb/src/test/java/org/testcontainers/jdbc/tidb/TiDBJDBCDriverTest.java create mode 100644 modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java create mode 100644 modules/tidb/src/test/resources/logback-test.xml create mode 100644 modules/tidb/src/test/resources/somepath/init_tidb.sql diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 686086d076c..07d944243cd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -43,6 +43,7 @@ body: - RabbitMQ - Selenium - Solr + - TiDB - ToxiProxy - Trino - Vault diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 9ef8eafaab2..ea190cefc80 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -43,6 +43,7 @@ body: - RabbitMQ - Selenium - Solr + - TiDB - ToxiProxy - Trino - Vault diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 1ab2693f210..09810d3e56f 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -43,6 +43,7 @@ body: - RabbitMQ - Selenium - Solr + - TiDB - ToxiProxy - Trino - Vault diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3e2d53fed65..2d877f664ab 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -197,6 +197,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/tidb" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/toxiproxy" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 84e21af744a..826e5c16215 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -73,6 +73,8 @@ - modules/solr/* "modules/spock": - modules/spock/* +"modules/tidb": + - modules/tidb/* "modules/toxiproxy": - modules/toxiproxy/* "modules/trino": diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 3c52dd1d8a8..e3a077333cd 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -51,6 +51,10 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database `jdbc:tc:cockroach:v21.2.3:///databasename` +#### Using TiDB + +`jdbc:tc:tidb:v6.1.0:///databasename` + ### Using a classpath init script Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows: diff --git a/docs/modules/databases/tidb.md b/docs/modules/databases/tidb.md new file mode 100644 index 00000000000..01c6b4cfcd4 --- /dev/null +++ b/docs/modules/databases/tidb.md @@ -0,0 +1,25 @@ +# TiDB Module + +See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:tidb:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + tidb + {{latest_version}} + test + + ``` + +!!! hint + Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/mkdocs.yml b/mkdocs.yml index 396986a955b..9491ebe6019 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -63,6 +63,7 @@ nav: - modules/databases/orientdb.md - modules/databases/postgres.md - modules/databases/presto.md + - modules/databases/tidb.md - modules/databases/trino.md - modules/azure.md - modules/docker_compose.md diff --git a/modules/tidb/build.gradle b/modules/tidb/build.gradle new file mode 100644 index 00000000000..51f15a6a798 --- /dev/null +++ b/modules/tidb/build.gradle @@ -0,0 +1,10 @@ +description = "Testcontainers :: JDBC :: TiDB" + +dependencies { + api project(':jdbc') + + testImplementation project(':jdbc-test') + testImplementation 'mysql:mysql-connector-java:8.0.29' + + compileOnly 'org.jetbrains:annotations:23.0.0' +} diff --git a/modules/tidb/sql/init_mysql.sql b/modules/tidb/sql/init_mysql.sql new file mode 100644 index 00000000000..2b00ee968b0 --- /dev/null +++ b/modules/tidb/sql/init_mysql.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + foo VARCHAR(255) +); + +INSERT INTO bar (foo) VALUES ('hello world'); \ No newline at end of file diff --git a/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java b/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java new file mode 100644 index 00000000000..f8030fd2422 --- /dev/null +++ b/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java @@ -0,0 +1,126 @@ +package org.testcontainers.tidb; + +import org.jetbrains.annotations.NotNull; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; +import org.testcontainers.utility.DockerImageName; + +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; + +/** + * Testcontainers implementation for TiDB. + * + * @author Icemap + */ +public class TiDBContainer extends JdbcDatabaseContainer { + + static final String NAME = "tidb"; + + static final String DOCKER_IMAGE_NAME = "pingcap/tidb"; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse(DOCKER_IMAGE_NAME); + + private static final Integer TIDB_PORT = 4000; + + private static final int REST_API_PORT = 10080; + + private String databaseName = "test"; + + private String username = "root"; + + private String password = ""; + + public TiDBContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public TiDBContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + addExposedPorts(TIDB_PORT, REST_API_PORT); + + waitingFor( + new HttpWaitStrategy() + .forPath("/status") + .forPort(REST_API_PORT) + .forStatusCode(200) + .withStartupTimeout(Duration.ofMinutes(1)) + ); + } + + @NotNull + @Override + protected Set getLivenessCheckPorts() { + return new HashSet<>(getMappedPort(TIDB_PORT)); + } + + @Override + public String getDriverClassName() { + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + return "com.mysql.cj.jdbc.Driver"; + } catch (ClassNotFoundException e) { + return "com.mysql.jdbc.Driver"; + } + } + + @Override + public String getJdbcUrl() { + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:mysql://" + getHost() + ":" + getMappedPort(TIDB_PORT) + "/" + databaseName + additionalUrlParams; + } + + @Override + protected String constructUrlForConnection(String queryString) { + String url = super.constructUrlForConnection(queryString); + + if (!url.contains("useSSL=")) { + String separator = url.contains("?") ? "&" : "?"; + url = url + separator + "useSSL=false"; + } + + if (!url.contains("allowPublicKeyRetrieval=")) { + url = url + "&allowPublicKeyRetrieval=true"; + } + + return url; + } + + @Override + public String getDatabaseName() { + return databaseName; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getTestQueryString() { + return "SELECT 1"; + } + + @Override + public TiDBContainer withDatabaseName(final String databaseName) { + throw new UnsupportedOperationException("The TiDB docker image does not currently support this"); + } + + @Override + public TiDBContainer withUsername(final String username) { + throw new UnsupportedOperationException("The TiDB docker image does not currently support this"); + } + + @Override + public TiDBContainer withPassword(final String password) { + throw new UnsupportedOperationException("The TiDB docker image does not currently support this"); + } +} diff --git a/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainerProvider.java b/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainerProvider.java new file mode 100644 index 00000000000..ee66771b42c --- /dev/null +++ b/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainerProvider.java @@ -0,0 +1,32 @@ +package org.testcontainers.tidb; + +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.JdbcDatabaseContainerProvider; +import org.testcontainers.utility.DockerImageName; + +/** + * Factory for TiDB containers. + */ +public class TiDBContainerProvider extends JdbcDatabaseContainerProvider { + + private static final String DEFAULT_TAG = "v6.1.0"; + + @Override + public boolean supports(String databaseType) { + return databaseType.equals(TiDBContainer.NAME); + } + + @Override + public JdbcDatabaseContainer newInstance() { + return newInstance(DEFAULT_TAG); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + if (tag != null) { + return new TiDBContainer(DockerImageName.parse(TiDBContainer.DOCKER_IMAGE_NAME).withTag(tag)); + } else { + return newInstance(); + } + } +} diff --git a/modules/tidb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/tidb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..a4168b00e74 --- /dev/null +++ b/modules/tidb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.tidb.TiDBContainerProvider diff --git a/modules/tidb/src/test/java/org/testcontainers/TiDBTestImages.java b/modules/tidb/src/test/java/org/testcontainers/TiDBTestImages.java new file mode 100644 index 00000000000..32fb57911a2 --- /dev/null +++ b/modules/tidb/src/test/java/org/testcontainers/TiDBTestImages.java @@ -0,0 +1,8 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public class TiDBTestImages { + + public static final DockerImageName TIDB_IMAGE = DockerImageName.parse("pingcap/tidb:v6.1.0"); +} diff --git a/modules/tidb/src/test/java/org/testcontainers/jdbc/tidb/TiDBJDBCDriverTest.java b/modules/tidb/src/test/java/org/testcontainers/jdbc/tidb/TiDBJDBCDriverTest.java new file mode 100644 index 00000000000..566850fa629 --- /dev/null +++ b/modules/tidb/src/test/java/org/testcontainers/jdbc/tidb/TiDBJDBCDriverTest.java @@ -0,0 +1,19 @@ +package org.testcontainers.jdbc.tidb; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.Arrays; +import java.util.EnumSet; + +@RunWith(Parameterized.class) +public class TiDBJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return Arrays.asList( + new Object[][] { { "jdbc:tc:tidb://hostname/databasename", EnumSet.noneOf(Options.class) } } + ); + } +} diff --git a/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java b/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java new file mode 100644 index 00000000000..c4833f14224 --- /dev/null +++ b/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java @@ -0,0 +1,54 @@ +package org.testcontainers.junit.tidb; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; +import org.testcontainers.TiDBTestImages; +import org.testcontainers.db.AbstractContainerDatabaseTest; +import org.testcontainers.tidb.TiDBContainer; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class SimpleTiDBTest extends AbstractContainerDatabaseTest { + + @Test + public void testSimple() throws SQLException { + try (TiDBContainer tidb = new TiDBContainer(TiDBTestImages.TIDB_IMAGE)) { + tidb.start(); + + ResultSet resultSet = performQuery(tidb, "SELECT 1"); + + int resultSetInt = resultSet.getInt(1); + Assert.assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + } + } + + @Test + public void testExplicitInitScript() throws SQLException { + try ( + TiDBContainer tidb = new TiDBContainer(TiDBTestImages.TIDB_IMAGE).withInitScript("somepath/init_tidb.sql") + ) { // TiDB is expected to be compatible with MySQL + tidb.start(); + + ResultSet resultSet = performQuery(tidb, "SELECT foo FROM bar"); + + String firstColumnValue = resultSet.getString(1); + Assert.assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + } + } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + TiDBContainer tidb = new TiDBContainer(TiDBTestImages.TIDB_IMAGE).withUrlParam("sslmode", "disable"); + + try { + tidb.start(); + String jdbcUrl = tidb.getJdbcUrl(); + Assert.assertThat(jdbcUrl, Matchers.containsString("?")); + Assert.assertThat(jdbcUrl, Matchers.containsString("sslmode=disable")); + } finally { + tidb.stop(); + } + } +} diff --git a/modules/tidb/src/test/resources/logback-test.xml b/modules/tidb/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/tidb/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/tidb/src/test/resources/somepath/init_tidb.sql b/modules/tidb/src/test/resources/somepath/init_tidb.sql new file mode 100644 index 00000000000..73bc09151cb --- /dev/null +++ b/modules/tidb/src/test/resources/somepath/init_tidb.sql @@ -0,0 +1,16 @@ +CREATE TABLE bar ( + foo VARCHAR(255) +); + +SELECT "a /* string literal containing comment characters like -- here"; +SELECT "a 'quoting' \"scenario ` involving BEGIN keyword\" here"; +SELECT * from `bar`; + +-- What about a line comment containing imbalanced string delimiters? " + +/* or a block comment + containing imbalanced string delimiters? + ' " + */ + +INSERT INTO bar (foo) /* ; */ VALUES ('hello world'); From 89803a204af6c3d4ba8de80d50ac5b43bcd12ea3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:17 +0000 Subject: [PATCH 2105/4969] Bump mockito-core from 4.6.1 to 4.7.0 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 4.6.1 to 4.7.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.6.1...v4.7.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9febf2802e9..c210ed48510 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -91,7 +91,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.15.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.11' - testImplementation ('org.mockito:mockito-core:4.6.1') { + testImplementation ('org.mockito:mockito-core:4.7.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 13cbb5d321216239524731476649acf9c976ea57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:18 +0000 Subject: [PATCH 2106/4969] Bump java-client from 3.3.2 to 3.3.3 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.3.2 to 3.3.3. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.3.2...java-client-3.3.3) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index e59e346c29f..10970df542e 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:3.14.9' - testImplementation 'com.couchbase.client:java-client:3.3.2' + testImplementation 'com.couchbase.client:java-client:3.3.3' testImplementation 'org.awaitility:awaitility:4.2.0' } From 7dcb1d1705fff6c01fb21626954301b2b6c3ab76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:19 +0000 Subject: [PATCH 2107/4969] Bump com.gradle.enterprise.gradle.plugin from 3.10.3 to 3.11.1 Bumps com.gradle.enterprise.gradle.plugin from 3.10.3 to 3.11.1. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index b56048c1126..116a4e26506 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.3" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" } } From 3b2c90e71e72be89648e0b0a2b658ce1a6116638 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:19 +0000 Subject: [PATCH 2108/4969] Bump postgresql from 42.4.0 to 42.4.1 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index 80763e312b5..1fc5dac8d8a 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.4.0' + testImplementation 'org.postgresql:postgresql:42.4.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From 981d47e0d3e45eb3ab726b08b421cf9cb3b50d91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:19 +0000 Subject: [PATCH 2109/4969] Bump java-driver-core from 4.8.0 to 4.14.1 in /modules/cassandra Bumps [java-driver-core](https://github.com/datastax/java-driver) from 4.8.0 to 4.14.1. - [Release notes](https://github.com/datastax/java-driver/releases) - [Commits](https://github.com/datastax/java-driver/compare/4.8.0...4.14.1) --- updated-dependencies: - dependency-name: com.datastax.oss:java-driver-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/cassandra/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cassandra/build.gradle b/modules/cassandra/build.gradle index b00740d09fd..385001db8f8 100644 --- a/modules/cassandra/build.gradle +++ b/modules/cassandra/build.gradle @@ -9,5 +9,5 @@ configurations.all { dependencies { api project(":database-commons") api "com.datastax.cassandra:cassandra-driver-core:3.10.0" - testImplementation 'com.datastax.oss:java-driver-core:4.8.0' + testImplementation 'com.datastax.oss:java-driver-core:4.14.1' } From caee839e2b97fe7fee57b71e463a6464ff04faea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:22 +0000 Subject: [PATCH 2110/4969] Bump azure-cosmos from 4.33.1 to 4.34.0 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.33.1 to 4.34.0. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.33.1...azure-cosmos_4.34.0) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index c6707401ff6..f8a7193571e 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:3.14.9' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'com.azure:azure-cosmos:4.33.1' + testImplementation 'com.azure:azure-cosmos:4.34.0' } From 88773a7dfda704643972d8ca625f745b5afab4e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:23 +0000 Subject: [PATCH 2111/4969] Bump mariadb-java-client from 3.0.6 to 3.0.7 in /modules/mariadb Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 3.0.6 to 3.0.7. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.0.6...3.0.7) --- updated-dependencies: - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index ed7f428ba3e..1a11f0fbfb6 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:1.0.3' testImplementation project(':jdbc-test') - testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.6' + testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.7' testImplementation testFixtures(project(':r2dbc')) testImplementation 'org.mariadb:r2dbc-mariadb:1.0.2' From e0c1b3652258b8e44f27807fd3a5248417dbe306 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:25 +0000 Subject: [PATCH 2112/4969] Bump postgresql from 42.4.0 to 42.4.1 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 57932ec84fd..7e14656f20f 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0' - testRuntimeOnly 'org.postgresql:postgresql:42.4.0' + testRuntimeOnly 'org.postgresql:postgresql:42.4.1' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' } From aa8a67964f2f2b6aea378081eeb7aa41f3a27c10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:25 +0000 Subject: [PATCH 2113/4969] Bump mssql-jdbc in /modules/mssqlserver Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 11.1.2.jre8-preview to 11.2.0.jre8. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) --- updated-dependencies: - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index 30b9af2bd77..cc05b6ffea4 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.9.0.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.1.2.jre8-preview' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.2.0.jre8' testImplementation project(':r2dbc') testImplementation 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' From 4495b0c89efb355373faa986772cde94c157f29c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:26 +0000 Subject: [PATCH 2114/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.273 to 1.12.281. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.273...1.12.281) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 6abd9cd943a..81ec1f9deb5 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.273' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.253' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.281' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.281' testImplementation 'org.assertj:assertj-core:3.23.1' } From 2c9e843d09868f3ec877fdb5a9e6916ae59e586e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:27 +0000 Subject: [PATCH 2115/4969] Bump hivemq-extension-sdk from 4.8.2 to 4.8.3 in /modules/hivemq Bumps [hivemq-extension-sdk](https://github.com/hivemq/hivemq-extension-sdk) from 4.8.2 to 4.8.3. - [Release notes](https://github.com/hivemq/hivemq-extension-sdk/releases) - [Commits](https://github.com/hivemq/hivemq-extension-sdk/compare/4.8.2...4.8.3) --- updated-dependencies: - dependency-name: com.hivemq:hivemq-extension-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 8336cfd8249..a85288f9fbd 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -13,7 +13,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") testImplementation(project(":junit-jupiter")) - testImplementation("com.hivemq:hivemq-extension-sdk:4.8.2") + testImplementation("com.hivemq:hivemq-extension-sdk:4.8.3") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.11") From c3586528904a4fcfc1de8cf1666606c248b53b3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:28 +0000 Subject: [PATCH 2116/4969] Bump mockito-core from 4.6.1 to 4.7.0 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 4.6.1 to 4.7.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.6.1...v4.7.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 57932ec84fd..03ae3a9a08c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:4.2.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:4.6.1') { + testImplementation ('org.mockito:mockito-core:4.7.0') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.23.1' From 3f3987a1ee46c9f0101a055e2e4d4353fcad2fe6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:29 +0000 Subject: [PATCH 2117/4969] Bump postgresql from 42.4.0 to 42.4.1 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 87705f77d5d..f769bf9b07c 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.4.0' + testImplementation 'org.postgresql:postgresql:42.4.1' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' From 11ca75a76836b51b649d6464e03d9a2b8dff27be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:29 +0000 Subject: [PATCH 2118/4969] Bump trino-jdbc from 391 to 392 in /modules/trino Bumps trino-jdbc from 391 to 392. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index c25007bb223..09b5b8cb16c 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:391' + testImplementation 'io.trino:trino-jdbc:392' compileOnly 'org.jetbrains:annotations:23.0.0' } From 7f036604c36b6f68bc938b9ad2695b31025c5a60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:29 +0000 Subject: [PATCH 2119/4969] Bump neo4j from 3.5.34 to 3.5.35 in /modules/neo4j Bumps [neo4j](https://github.com/neo4j/neo4j) from 3.5.34 to 3.5.35. - [Release notes](https://github.com/neo4j/neo4j/releases) - [Commits](https://github.com/neo4j/neo4j/compare/3.5.34...3.5.35) --- updated-dependencies: - dependency-name: org.neo4j:neo4j dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/neo4j/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/build.gradle b/modules/neo4j/build.gradle index de42bca2d5d..aabb571edf6 100644 --- a/modules/neo4j/build.gradle +++ b/modules/neo4j/build.gradle @@ -29,7 +29,7 @@ task customNeo4jPluginJar(type: Jar) { processTestResources.dependsOn customNeo4jPluginJar dependencies { - customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.34" + customNeo4jPluginCompileOnly "org.neo4j:neo4j:3.5.35" api project(":testcontainers") From 7bba5118cfd74b9bee5687e546801e56c7dd8779 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:30 +0000 Subject: [PATCH 2120/4969] Bump aws-java-sdk-s3 from 1.12.273 to 1.12.281 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.273 to 1.12.281. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.273...1.12.281) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8702d2e1a83..0b28ee848ae 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.273' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.281' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.273' From 3842d784ec323af87bfe958b7ff1422ecbdc2ae6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:30 +0000 Subject: [PATCH 2121/4969] Bump postgresql from 42.4.0 to 42.4.1 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 3eadd33ea2a..304e0b98dc4 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.4.0' + testRuntimeOnly 'org.postgresql:postgresql:42.4.1' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testCompileClasspath 'org.jetbrains:annotations:23.0.0' From ae6d57c4c2999527d0c91ceb90d597432754ceb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:30 +0000 Subject: [PATCH 2122/4969] Bump reactor-core from 3.4.21 to 3.4.22 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.21 to 3.4.22. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.21...v3.4.22) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index f51a13b9296..f38803104a3 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.21' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.22' testFixturesImplementation 'org.assertj:assertj-core:3.23.1' } From 6d873e0f9534706ee5a007eb6e125055f14c4b20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:32 +0000 Subject: [PATCH 2123/4969] Bump mysql-connector-java from 8.0.29 to 8.0.30 in /modules/tidb Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.29 to 8.0.30. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.29...8.0.30) --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/tidb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/tidb/build.gradle b/modules/tidb/build.gradle index 51f15a6a798..36f6acfe806 100644 --- a/modules/tidb/build.gradle +++ b/modules/tidb/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.29' + testImplementation 'mysql:mysql-connector-java:8.0.30' compileOnly 'org.jetbrains:annotations:23.0.0' } From f4a68fe044779bef456e0b2cb917fc21f5217c4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:35 +0000 Subject: [PATCH 2124/4969] Bump aws-java-sdk-logs from 1.12.273 to 1.12.281 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.273 to 1.12.281. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.273...1.12.281) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 8702d2e1a83..eacdc411a73 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.273' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.281' testImplementation 'software.amazon.awssdk:s3:2.17.244' testImplementation 'org.assertj:assertj-core:3.23.1' } From dd5dc8a813faa02c8d3bc5b8cf4a697fdf487307 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:35 +0000 Subject: [PATCH 2125/4969] Bump google-cloud-spanner from 6.27.0 to 6.28.0 in /modules/gcloud Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.27.0 to 6.28.0. - [Release notes](https://github.com/googleapis/java-spanner/releases) - [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-spanner/compare/v6.27.0...v6.28.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-spanner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index ee7f563c88e..bac92bebde9 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.10.1' testImplementation 'com.google.cloud:google-cloud-firestore:3.3.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' - testImplementation 'com.google.cloud:google-cloud-spanner:6.27.0' + testImplementation 'com.google.cloud:google-cloud-spanner:6.28.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From 93051c42ac1afaa24959b189cec1270ab7f55443 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:35 +0000 Subject: [PATCH 2126/4969] Bump actions/cache from 3.0.5 to 3.0.7 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.5 to 3.0.7. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.5...v3.0.7) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 9fa1f78e47b..f23fc66e889 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -25,7 +25,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.5 + uses: actions/cache@v3.0.7 continue-on-error: true with: path: ~/.gradle/caches @@ -53,7 +53,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.5 + uses: actions/cache@v3.0.7 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55432b3e2c6..288e9329824 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.5 + uses: actions/cache@v3.0.7 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -59,7 +59,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.5 + uses: actions/cache@v3.0.7 continue-on-error: true with: path: ~/.gradle/caches From 63e65926b2b97f7249ffe3f626978948df65327a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:38 +0000 Subject: [PATCH 2127/4969] Bump cucumber-java from 7.5.0 to 7.6.0 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 7.5.0 to 7.6.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.5.0...v7.6.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index ba51bbe0d2c..cc6b073413f 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:7.5.0' + testImplementation 'io.cucumber:cucumber-java:7.6.0' testImplementation 'io.cucumber:cucumber-junit:7.5.0' testImplementation 'org.testcontainers:selenium' } From a45bb987ed20e03fb441fc76da119eeccb04d744 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:39 +0000 Subject: [PATCH 2128/4969] Bump google-cloud-firestore from 3.3.0 to 3.4.0 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.3.0...v3.4.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index ee7f563c88e..f28fb904be8 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.10.1' - testImplementation 'com.google.cloud:google-cloud-firestore:3.3.0' + testImplementation 'com.google.cloud:google-cloud-firestore:3.4.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' testImplementation 'com.google.cloud:google-cloud-spanner:6.27.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.1' From 39e2005700fffeb88ed1d4f9788684e1d2b32044 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:02:44 +0000 Subject: [PATCH 2129/4969] Bump com.gradle.enterprise.gradle.plugin in /examples Bumps com.gradle.enterprise.gradle.plugin from 3.10.3 to 3.11.1. --- updated-dependencies: - dependency-name: com.gradle.enterprise:com.gradle.enterprise.gradle.plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index be455a78955..1d3956a88cb 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.10.3" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" } } From 625947f89c7e2fcbebbf70462923987deded02b5 Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 15 Aug 2022 16:31:59 +0200 Subject: [PATCH 2130/4969] Add Consul module (#4683) Co-authored-by: Kevin Wittek --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 + .github/labeler.yml | 2 + docs/modules/consul.md | 36 +++++++ mkdocs.yml | 1 + modules/consul/build.gradle | 9 ++ .../consul/ConsulContainer.java | 100 ++++++++++++++++++ .../consul/ConsulContainerTest.java | 78 ++++++++++++++ .../consul/ConsulTestImages.java | 7 ++ .../src/test/resources/logback-test.xml | 16 +++ 12 files changed, 257 insertions(+) create mode 100644 docs/modules/consul.md create mode 100644 modules/consul/build.gradle create mode 100644 modules/consul/src/main/java/org/testcontainers/consul/ConsulContainer.java create mode 100644 modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java create mode 100644 modules/consul/src/test/java/org/testcontainers/consul/ConsulTestImages.java create mode 100644 modules/consul/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 07d944243cd..5aca9e624b3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -18,6 +18,7 @@ body: - Cassandra - Clickhouse - CockroachDB + - Consul - Couchbase - DB2 - Dynalite diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index ea190cefc80..ba5b1f88006 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -18,6 +18,7 @@ body: - Cassandra - Clickhouse - CockroachDB + - Consul - Couchbase - DB2 - Dynalite diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 09810d3e56f..981f5613a1e 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -18,6 +18,7 @@ body: - Cassandra - Clickhouse - CockroachDB + - Consul - Couchbase - DB2 - Dynalite diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2d877f664ab..22437e15825 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -42,6 +42,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/consul" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/couchbase" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 826e5c16215..cf75af99d26 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -15,6 +15,8 @@ - modules/clickhouse/* "modules/cockroachdb": - modules/cockroachdb/* +"modules/consul": + - modules/consul/* "modules/couchbase": - modules/couchbase/* "modules/db2": diff --git a/docs/modules/consul.md b/docs/modules/consul.md new file mode 100644 index 00000000000..1580690cad7 --- /dev/null +++ b/docs/modules/consul.md @@ -0,0 +1,36 @@ +# Hashicorp Consul Module + +Testcontainers module for [Consul](https://github.com/hashicorp/consul). Consul is a tool for managing key value properties. More information on Consul [here](https://www.consul.io/). + +## Usage example + + +[Running Consul in your Junit tests](../../modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java) + + +## Why Consul in Junit tests? + +With the increasing popularity of Consul and config externalization, applications are now needing to source properties from Consul. +This can prove challenging in the development phase without a running Consul instance readily on hand. This library +aims to solve your apps integration testing with Consul. You can also use it to +test how your application behaves with Consul by writing different test scenarios in Junit. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +```groovy tab='Gradle' +testImplementation "org.testcontainers:consul:{{latest_version}}" +``` + +```xml tab='Maven' + + org.testcontainers + consul + {{latest_version}} + test + +``` + +See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/modules/consul/AUTHORS) for contributors. + diff --git a/mkdocs.yml b/mkdocs.yml index 9491ebe6019..a836e0a2ff7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -66,6 +66,7 @@ nav: - modules/databases/tidb.md - modules/databases/trino.md - modules/azure.md + - modules/consul.md - modules/docker_compose.md - modules/elasticsearch.md - modules/gcloud.md diff --git a/modules/consul/build.gradle b/modules/consul/build.gradle new file mode 100644 index 00000000000..0d0d6e7e992 --- /dev/null +++ b/modules/consul/build.gradle @@ -0,0 +1,9 @@ +description = "Testcontainers :: Consul" + +dependencies { + api project(':testcontainers') + + testImplementation 'com.ecwid.consul:consul-api:1.4.5' + testImplementation 'io.rest-assured:rest-assured:4.4.0' + testImplementation 'org.assertj:assertj-core:3.21.0' +} diff --git a/modules/consul/src/main/java/org/testcontainers/consul/ConsulContainer.java b/modules/consul/src/main/java/org/testcontainers/consul/ConsulContainer.java new file mode 100644 index 00000000000..0c9d2607072 --- /dev/null +++ b/modules/consul/src/main/java/org/testcontainers/consul/ConsulContainer.java @@ -0,0 +1,100 @@ +package org.testcontainers.consul; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Capability; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Testcontainers implementation for Consul. + */ +public class ConsulContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("consul"); + + private static final int CONSUL_HTTP_PORT = 8500; + + private static final int CONSUL_GRPC_PORT = 8502; + + private List initCommands = new ArrayList<>(); + + private String[] startConsulCmd = new String[] { "agent", "-dev", "-client", "0.0.0.0" }; + + public ConsulContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public ConsulContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + // Use the status leader endpoint to verify if consul is running. + setWaitStrategy(Wait.forHttp("/v1/status/leader").forPort(CONSUL_HTTP_PORT).forStatusCode(200)); + + withCreateContainerCmdModifier(cmd -> cmd.getHostConfig().withCapAdd(Capability.IPC_LOCK)); + withEnv("CONSUL_ADDR", "http://0.0.0.0:" + CONSUL_HTTP_PORT); + withCommand(startConsulCmd); + withExposedPorts(CONSUL_HTTP_PORT, CONSUL_GRPC_PORT); + } + + @Override + protected void containerIsStarted(InspectContainerResponse containerInfo) { + runConsulCommands(); + } + + private void runConsulCommands() { + if (!initCommands.isEmpty()) { + String commands = initCommands + .stream() + .map(command -> "consul " + command) + .collect(Collectors.joining(" && ")); + try { + ExecResult execResult = this.execInContainer(new String[] { "/bin/sh", "-c", commands }); + if (execResult.getExitCode() != 0) { + logger() + .error( + "Failed to execute these init commands {}. Exit code {}. Stdout {}. Stderr {}", + initCommands, + execResult.getExitCode(), + execResult.getStdout(), + execResult.getStderr() + ); + } + } catch (IOException | InterruptedException e) { + logger() + .error( + "Failed to execute these init commands {}. Exception message: {}", + initCommands, + e.getMessage() + ); + } + } + } + + /** + * Run consul commands using the consul cli. + * + * Useful for enableing more secret engines like: + *
+     *     .withConsulCommand("secrets enable pki")
+     *     .withConsulCommand("secrets enable transit")
+     * 
+ * or register specific K/V like: + *
+     *     .withConsulCommand("kv put config/testing1 value123")
+     * 
+ * @param commands The commands to send to the consul cli + * @return this + */ + public ConsulContainer withConsulCommand(String... commands) { + initCommands.addAll(Arrays.asList(commands)); + return self(); + } +} diff --git a/modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java b/modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java new file mode 100644 index 00000000000..e29ff7ffbd8 --- /dev/null +++ b/modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java @@ -0,0 +1,78 @@ +package org.testcontainers.consul; + +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.kv.model.GetValue; +import io.restassured.RestAssured; +import org.assertj.core.api.Assertions; +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; +import org.junit.ClassRule; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * This test shows the pattern to use the ConsulContainer @ClassRule for a junit test. It also has tests that ensure + * the properties were added correctly by reading from Consul with the CLI and over HTTP. + */ +public class ConsulContainerTest { + + @ClassRule + public static ConsulContainer consulContainer = new ConsulContainer(ConsulTestImages.CONSUL_IMAGE) + .withConsulCommand("kv put config/testing1 value123"); + + @Test + public void readFirstPropertyPathWithCli() throws IOException, InterruptedException { + GenericContainer.ExecResult result = consulContainer.execInContainer("consul", "kv", "get", "config/testing1"); + final String output = result.getStdout().replaceAll("\\r?\\n", ""); + MatcherAssert.assertThat(output, CoreMatchers.containsString("value123")); + } + + @Test + public void readFirstSecretPathOverHttpApi() throws InterruptedException { + RestAssured + .given() + .when() + .get("http://" + getHostAndPort() + "/v1/kv/config/testing1") + .then() + .assertThat() + .body( + "[0].Value", + CoreMatchers.equalTo(Base64.getEncoder().encodeToString("value123".getBytes(StandardCharsets.UTF_8))) + ); + } + + @Test + public void writeAndReadMultipleValuesUsingClient() { + final ConsulClient consulClient = new ConsulClient( + consulContainer.getHost(), + consulContainer.getFirstMappedPort() + ); + + final Map properties = new HashMap<>(); + properties.put("value", "world"); + properties.put("other_value", "another world"); + + // Write operation + properties.forEach((key, value) -> { + Response writeResponse = consulClient.setKVValue(key, value); + Assertions.assertThat(writeResponse.getValue()).isTrue(); + }); + + // Read operation + properties.forEach((key, value) -> { + Response readResponse = consulClient.getKVValue(key); + Assertions.assertThat(readResponse.getValue().getDecodedValue()).isEqualTo(value); + }); + } + + private String getHostAndPort() { + return consulContainer.getHost() + ":" + consulContainer.getMappedPort(8500); + } +} diff --git a/modules/consul/src/test/java/org/testcontainers/consul/ConsulTestImages.java b/modules/consul/src/test/java/org/testcontainers/consul/ConsulTestImages.java new file mode 100644 index 00000000000..de2b9702066 --- /dev/null +++ b/modules/consul/src/test/java/org/testcontainers/consul/ConsulTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers.consul; + +import org.testcontainers.utility.DockerImageName; + +public interface ConsulTestImages { + DockerImageName CONSUL_IMAGE = DockerImageName.parse("consul:1.10.12"); +} diff --git a/modules/consul/src/test/resources/logback-test.xml b/modules/consul/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..535e406fc13 --- /dev/null +++ b/modules/consul/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 84102fe2590c9128f218a3c65ac77e3a606d69bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:32:43 +0000 Subject: [PATCH 2131/4969] Bump assertj-core from 3.21.0 to 3.23.1 in /modules/consul Bumps [assertj-core](https://github.com/assertj/assertj-core) from 3.21.0 to 3.23.1. - [Release notes](https://github.com/assertj/assertj-core/releases) - [Commits](https://github.com/assertj/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.23.1) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/consul/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/consul/build.gradle b/modules/consul/build.gradle index 0d0d6e7e992..49e9b404690 100644 --- a/modules/consul/build.gradle +++ b/modules/consul/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation 'com.ecwid.consul:consul-api:1.4.5' testImplementation 'io.rest-assured:rest-assured:4.4.0' - testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.assertj:assertj-core:3.23.1' } From df2b1d1aed8b8f612059781ff9c620ef06eb2999 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:24 +0000 Subject: [PATCH 2132/4969] Bump google-cloud-bigtable from 2.10.1 to 2.10.3 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.10.1 to 2.10.3. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.10.1...v2.10.3) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 60778fff111..ce332830e07 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.4.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' testImplementation 'com.google.cloud:google-cloud-spanner:6.28.0' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.1' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.3' testImplementation 'org.assertj:assertj-core:3.23.1' } From 9b51b77f02d776583cca635e55e114b82b687f57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:25 +0000 Subject: [PATCH 2133/4969] Bump common-custom-user-data-gradle-plugin from 1.7.2 to 1.8.0 Bumps common-custom-user-data-gradle-plugin from 1.7.2 to 1.8.0. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 116a4e26506..bd51349bb05 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.0" } } From b1cd2beca42b259813fa09884c279b79cf0f9b71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:34 +0000 Subject: [PATCH 2134/4969] Bump aws-java-sdk-sqs from 1.12.273 to 1.12.282 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.273 to 1.12.282. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.273...1.12.282) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ea528389c23..98027ef09b7 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.281' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.273' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.282' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.281' testImplementation 'software.amazon.awssdk:s3:2.17.244' testImplementation 'org.assertj:assertj-core:3.23.1' From c3ba559f13f32b44353efc59cc44d4b7f66faf8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:49 +0000 Subject: [PATCH 2135/4969] Bump google-cloud-datastore from 2.10.1 to 2.11.0 in /modules/gcloud Bumps [google-cloud-datastore](https://github.com/googleapis/java-datastore) from 2.10.1 to 2.11.0. - [Release notes](https://github.com/googleapis/java-datastore/releases) - [Changelog](https://github.com/googleapis/java-datastore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-datastore/compare/v2.10.1...v2.11.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-datastore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 60778fff111..5202c3c8fbe 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:2.10.1' + testImplementation 'com.google.cloud:google-cloud-datastore:2.11.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' testImplementation 'com.google.cloud:google-cloud-spanner:6.28.0' From 04c7b0a49c470592cb8fa1f1344273987a87e598 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:49 +0000 Subject: [PATCH 2136/4969] Bump google-cloud-pubsub from 1.120.6 to 1.120.11 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.120.6 to 1.120.11. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.120.6...v1.120.11) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 60778fff111..db006563c74 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.10.1' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.0' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.6' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.11' testImplementation 'com.google.cloud:google-cloud-spanner:6.28.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.1' testImplementation 'org.assertj:assertj-core:3.23.1' From 115eca1a326bf7fc4e925461ddfdccc987e3a0c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:51 +0000 Subject: [PATCH 2137/4969] Bump postgresql from 42.4.0 to 42.4.1 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index c6272fc7522..ab32d55df91 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220320' - testImplementation 'org.postgresql:postgresql:42.4.0' + testImplementation 'org.postgresql:postgresql:42.4.1' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:postgresql' } From 66e51c890f9992d4fbfdfb01138252821e97a09f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:51 +0000 Subject: [PATCH 2138/4969] Bump mockito-core from 4.6.1 to 4.7.0 in /modules/jdbc Bumps [mockito-core](https://github.com/mockito/mockito) from 4.6.1 to 4.7.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.6.1...v4.7.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 43ff0968715..ba0f845b47d 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -10,7 +10,7 @@ dependencies { testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.23' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation ('org.mockito:mockito-core:4.6.1') { + testImplementation ('org.mockito:mockito-core:4.7.0') { exclude(module: 'hamcrest-core') } } From 5bc0a1c0c5f741ca63e595c69b47a44a165935ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:32:54 +0000 Subject: [PATCH 2139/4969] Bump s3 from 2.17.244 to 2.17.253 in /modules/localstack Bumps s3 from 2.17.244 to 2.17.253. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ea528389c23..d29dbda0cd2 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.281' - testImplementation 'software.amazon.awssdk:s3:2.17.244' + testImplementation 'software.amazon.awssdk:s3:2.17.253' testImplementation 'org.assertj:assertj-core:3.23.1' } From f92ff763362857e9f0854ed3c7a43673ff0dad5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:33:04 +0000 Subject: [PATCH 2140/4969] Bump rest-assured from 4.4.0 to 5.1.1 in /modules/consul Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 4.4.0 to 5.1.1. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-4.4.0...rest-assured-5.1.1) --- updated-dependencies: - dependency-name: io.rest-assured:rest-assured dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/consul/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/consul/build.gradle b/modules/consul/build.gradle index 49e9b404690..acb97a47927 100644 --- a/modules/consul/build.gradle +++ b/modules/consul/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation 'com.ecwid.consul:consul-api:1.4.5' - testImplementation 'io.rest-assured:rest-assured:4.4.0' + testImplementation 'io.rest-assured:rest-assured:5.1.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From 159922275dd6ddb6ecac7f6ea7b0a923ab9e509c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:33:04 +0000 Subject: [PATCH 2141/4969] Bump common-custom-user-data-gradle-plugin in /examples Bumps common-custom-user-data-gradle-plugin from 1.7.2 to 1.8.0. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 1d3956a88cb..83ba91e8321 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -7,7 +7,7 @@ buildscript { dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.7.2" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.0" } } From ae2e71c82bc33922376f7272b9801d79025bd068 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 01:33:07 +0000 Subject: [PATCH 2142/4969] Bump cucumber-junit from 7.5.0 to 7.6.0 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.5.0 to 7.6.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.5.0...v7.6.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index cc6b073413f..ab0331f81f4 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.6.0' - testImplementation 'io.cucumber:cucumber-junit:7.5.0' + testImplementation 'io.cucumber:cucumber-junit:7.6.0' testImplementation 'org.testcontainers:selenium' } From 6a3e649b296bba3c5723a2538b21d4eabb593cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 16 Aug 2022 09:25:10 -0500 Subject: [PATCH 2143/4969] Move junit4 to assertj (#5685) Co-authored-by: Kevin Wittek --- config/checkstyle/checkstyle.xml | 4 - .../FrameConsumerResultCallbackTest.java | 27 ++++--- .../DockerClientConfigUtilsTest.java | 14 ++-- .../images/AgeBasedPullPolicyTest.java | 7 +- .../images/ParsedDockerfileTest.java | 74 ++++++++----------- .../images/RemoteDockerImageTest.java | 26 +++---- .../junit/FixedHostPortContainerTest.java | 13 ++-- .../strategy/AbstractWaitStrategyTest.java | 8 +- .../wait/strategy/HttpWaitStrategyTest.java | 7 +- .../utility/ComparableVersionTest.java | 4 +- .../DefaultImageNameSubstitutorTest.java | 7 +- .../DockerImageNameCompatibilityTest.java | 14 +--- .../utility/DockerStatusTest.java | 31 ++++---- .../utility/FilterRegistryTest.java | 10 +-- .../utility/ResourceReaperTest.java | 3 +- .../test/java/generic/CmdModifierTest.java | 6 +- .../src/test/java/generic/CommandsTest.java | 4 +- .../java/generic/ContainerCreationTest.java | 6 +- .../src/test/java/generic/DependsOnTest.java | 6 +- .../src/test/java/generic/ExecTest.java | 6 +- .../java/generic/HostPortExposedTest.java | 4 +- .../test/java/generic/WaitStrategiesTest.java | 8 +- docs/examples/junit4/redis/build.gradle | 1 + .../quickstart/RedisBackedCacheIntTest.java | 4 +- .../RedisBackedCacheIntTestStep0.java | 4 +- examples/linked-container/build.gradle | 1 + .../linkedcontainer/RedmineClientTest.java | 7 +- .../containers/Neo4jExampleTest.java | 2 +- modules/cassandra/build.gradle | 2 + .../containers/CassandraContainerTest.java | 34 ++++----- .../containers/CassandraDriver3Test.java | 4 +- .../containers/CassandraDriver4Test.java | 4 +- .../consul/ConsulContainerTest.java | 25 +++---- modules/couchbase/build.gradle | 1 + .../couchbase/CouchbaseContainerTest.java | 27 +++---- modules/influxdb/build.gradle | 1 + .../containers/InfluxDBContainerTest.java | 14 ++-- .../InfluxDBContainerWithUserTest.java | 26 +++---- .../jdbc/ContainerDatabaseDriverTest.java | 5 +- .../junit/jupiter/PostgresContainerTests.java | 4 +- ...tLifecycleAwareExceptionCapturingTest.java | 7 +- .../localstack/LocalstackContainerTest.java | 3 +- modules/mongodb/build.gradle | 1 + .../containers/MongoDBContainerTest.java | 11 +-- .../junit/oracle/SimpleOracleTest.java | 16 ++-- .../containers/PrestoContainerTest.java | 71 ++++++++---------- .../DefaultRecordingFileFactoryTest.java | 5 +- ...ChromeRecordingWebDriverContainerTest.java | 19 +++-- modules/solr/build.gradle | 2 +- .../containers/SolrContainerTest.java | 12 ++- .../junit/tidb/SimpleTiDBTest.java | 12 +-- .../containers/TrinoContainerTest.java | 26 +++---- .../vault/VaultContainerTest.java | 46 ++++++------ test-support/build.gradle | 1 + .../testsupport/FlakyRuleTest.java | 34 +++++---- 55 files changed, 325 insertions(+), 396 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 6e73f4da4aa..6e51c56c942 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -29,11 +29,7 @@ org.assertj.core.api.Assertions.*, org.assertj.core.api.Assumptions.*, org.awaitility.Awaitility.*, - org.hamcrest.Matchers.*, - org.hamcrest.MatcherAssert.*, - org.junit.Assert.*, org.junit.Assume.*, - org.junit.jupiter.api.Assertions.*, org.mockito.Mockito.*, org.mockito.ArgumentMatchers.*, org.mockserver.model.HttpRequest.*, diff --git a/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java b/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java index 5282712b733..298e7a981a0 100644 --- a/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/FrameConsumerResultCallbackTest.java @@ -10,8 +10,7 @@ import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class FrameConsumerResultCallbackTest { @@ -26,7 +25,7 @@ public void passStderrFrameWithoutColors() { ToStringConsumer consumer = new ToStringConsumer(); callback.addConsumer(OutputFrame.OutputType.STDERR, consumer); callback.onNext(new Frame(StreamType.STDERR, FRAME_PAYLOAD.getBytes())); - assertEquals(LOG_RESULT, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(LOG_RESULT); } @Test @@ -35,7 +34,7 @@ public void passStderrFrameWithColors() { ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); callback.addConsumer(OutputFrame.OutputType.STDERR, consumer); callback.onNext(new Frame(StreamType.STDERR, FRAME_PAYLOAD.getBytes())); - assertEquals(FRAME_PAYLOAD, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(FRAME_PAYLOAD); } @Test @@ -44,7 +43,7 @@ public void passStdoutFrameWithoutColors() { ToStringConsumer consumer = new ToStringConsumer(); callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, FRAME_PAYLOAD.getBytes())); - assertEquals(LOG_RESULT, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(LOG_RESULT); } @Test @@ -53,7 +52,7 @@ public void passStdoutFrameWithColors() { ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, FRAME_PAYLOAD.getBytes())); - assertEquals(FRAME_PAYLOAD, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(FRAME_PAYLOAD); } @Test @@ -62,7 +61,7 @@ public void basicConsumer() { BasicConsumer consumer = new BasicConsumer(); callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, FRAME_PAYLOAD.getBytes())); - assertEquals(LOG_RESULT, consumer.toString()); + assertThat(consumer.toString()).isEqualTo(LOG_RESULT); } @Test @@ -71,7 +70,7 @@ public void passStdoutNull() { ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, null)); - assertEquals("", consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(""); } @Test @@ -81,7 +80,7 @@ public void passStdoutEmptyLine() { ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, payload.getBytes())); - assertEquals(payload, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(payload); } @Test @@ -91,7 +90,7 @@ public void passStdoutSingleLine() { ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, payload.getBytes())); - assertEquals(payload, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(payload); } @Test @@ -101,7 +100,7 @@ public void passStdoutSingleLineWithNewline() { ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false); callback.addConsumer(OutputFrame.OutputType.STDOUT, consumer); callback.onNext(new Frame(StreamType.STDOUT, payload.getBytes())); - assertEquals(payload, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(payload); } @Test @@ -130,7 +129,7 @@ public void passRawFrameWithoutColors() throws TimeoutException, IOException { } catch (Exception e) { exception = e; } - assertTrue(exception instanceof TimeoutException); + assertThat(exception instanceof TimeoutException).isTrue(); callback.close(); waitConsumer.waitUntil( frame -> frame.getType() == OutputFrame.OutputType.STDOUT && frame.getUtf8String().equals("Test3"), @@ -180,7 +179,7 @@ public void passRawFrameWithColors() throws TimeoutException, IOException { } catch (Exception e) { exception = e; } - assertTrue(exception instanceof TimeoutException); + assertThat(exception instanceof TimeoutException).isTrue(); callback.close(); waitConsumer.waitUntil( frame -> { @@ -208,7 +207,7 @@ public void reconstructBreakedUnicode() throws IOException { callback.onNext(new Frame(StreamType.RAW, bytes1)); callback.onNext(new Frame(StreamType.RAW, bytes2)); callback.close(); - assertEquals(payload, consumer.toUtf8String()); + assertThat(consumer.toUtf8String()).isEqualTo(payload); } private static class BasicConsumer implements Consumer { diff --git a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java index 39e1338bc46..d14ffda42cc 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java @@ -7,9 +7,7 @@ import java.net.URI; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.assertj.core.api.Assertions.assertThat; public class DockerClientConfigUtilsTest { @@ -23,7 +21,7 @@ public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() { client, URI.create("unix:///var/run/docker.sock") ); - assertEquals("localhost", actual); + assertThat(actual).isEqualTo("localhost"); } @Test @@ -32,7 +30,7 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() { client, URI.create("http://12.23.34.45") ); - assertEquals("12.23.34.45", actual); + assertThat(actual).isEqualTo("12.23.34.45"); } @Test @@ -41,7 +39,7 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() { client, URI.create("tcp://12.23.34.45") ); - assertEquals("12.23.34.45", actual); + assertThat(actual).isEqualTo("12.23.34.45"); } @Test @@ -50,11 +48,11 @@ public void getDockerHostIpAddressShouldReturnNullWhenUnsupportedUriScheme() { client, URI.create("gopher://12.23.34.45") ); - assertNull(actual); + assertThat(actual).isNull(); } @Test(timeout = 5_000) public void getDefaultGateway() { - assertNotNull(DockerClientConfigUtils.getDefaultGateway()); + assertThat(DockerClientConfigUtils.getDefaultGateway()).isNotNull(); } } diff --git a/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java index 96fdfa4010b..0bdf969688b 100644 --- a/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java +++ b/core/src/test/java/org/testcontainers/images/AgeBasedPullPolicyTest.java @@ -8,8 +8,7 @@ import java.time.temporal.ChronoUnit; import java.util.UUID; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class AgeBasedPullPolicyTest { @@ -20,9 +19,9 @@ public void shouldPull() { ImageData imageData = ImageData.builder().createdAt(Instant.now().minus(2, ChronoUnit.HOURS)).build(); AgeBasedPullPolicy oneHour = new AgeBasedPullPolicy(Duration.of(1L, ChronoUnit.HOURS)); - assertTrue(oneHour.shouldPullCached(imageName, imageData)); + assertThat(oneHour.shouldPullCached(imageName, imageData)).isTrue(); AgeBasedPullPolicy fiveHours = new AgeBasedPullPolicy(Duration.of(5L, ChronoUnit.HOURS)); - assertFalse(fiveHours.shouldPullCached(imageName, imageData)); + assertThat(fiveHours.shouldPullCached(imageName, imageData)).isFalse(); } } diff --git a/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java index cd4509965e6..f8c66860022 100644 --- a/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java +++ b/core/src/test/java/org/testcontainers/images/ParsedDockerfileTest.java @@ -6,7 +6,7 @@ import java.nio.file.Paths; import java.util.Arrays; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class ParsedDockerfileTest { @@ -15,11 +15,9 @@ public void doesSimpleParsing() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("FROM someimage", "RUN something") ); - assertEquals( - "extracts a single image name", - Sets.newHashSet("someimage"), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("extracts a single image name") + .isEqualTo(Sets.newHashSet("someimage")); } @Test @@ -27,11 +25,9 @@ public void isCaseInsensitive() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("from someimage", "RUN something") ); - assertEquals( - "extracts a single image name", - Sets.newHashSet("someimage"), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("extracts a single image name") + .isEqualTo(Sets.newHashSet("someimage")); } @Test @@ -39,11 +35,9 @@ public void handlesTags() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("FROM someimage:tag", "RUN something") ); - assertEquals( - "retains tags in image names", - Sets.newHashSet("someimage:tag"), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("retains tags in image names") + .isEqualTo(Sets.newHashSet("someimage:tag")); } @Test @@ -51,11 +45,9 @@ public void handlesDigests() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("FROM someimage@sha256:abc123", "RUN something") ); - assertEquals( - "retains digests in image names", - Sets.newHashSet("someimage@sha256:abc123"), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("retains digests in image names") + .isEqualTo(Sets.newHashSet("someimage@sha256:abc123")); } @Test @@ -63,11 +55,9 @@ public void ignoringCommentedFromLines() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("FROM someimage", "#FROM somethingelse") ); - assertEquals( - "ignores commented from lines", - Sets.newHashSet("someimage"), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("ignores commented from lines") + .isEqualTo(Sets.newHashSet("someimage")); } @Test @@ -75,11 +65,9 @@ public void ignoringBuildStageNames() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("FROM someimage --as=base", "RUN something", "FROM nextimage", "RUN something") ); - assertEquals( - "ignores build stage names and allows multiple images to be extracted", - Sets.newHashSet("someimage", "nextimage"), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("ignores build stage names and allows multiple images to be extracted") + .isEqualTo(Sets.newHashSet("someimage", "nextimage")); } @Test @@ -87,7 +75,9 @@ public void ignoringPlatformArgs() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("FROM --platform=linux/amd64 someimage", "RUN something") ); - assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("ignores platform args") + .isEqualTo(Sets.newHashSet("someimage")); } @Test @@ -95,7 +85,9 @@ public void ignoringExtraPlatformArgs() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("FROM --platform=linux/amd64 --somethingelse=value someimage", "RUN something") ); - assertEquals("ignores platform args", Sets.newHashSet("someimage"), parsedDockerfile.getDependencyImageNames()); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("ignores platform args") + .isEqualTo(Sets.newHashSet("someimage")); } @Test @@ -103,20 +95,16 @@ public void handlesGracefullyIfNoFromLine() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile( Arrays.asList("RUN something", "# is this even a valid Dockerfile?") ); - assertEquals( - "handles invalid Dockerfiles gracefully", - Sets.newHashSet(), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("handles invalid Dockerfiles gracefully") + .isEqualTo(Sets.newHashSet()); } @Test public void handlesGracefullyIfDockerfileNotFound() { final ParsedDockerfile parsedDockerfile = new ParsedDockerfile(Paths.get("nonexistent.Dockerfile")); - assertEquals( - "handles missing Dockerfiles gracefully", - Sets.newHashSet(), - parsedDockerfile.getDependencyImageNames() - ); + assertThat(parsedDockerfile.getDependencyImageNames()) + .as("handles missing Dockerfiles gracefully") + .isEqualTo(Sets.newHashSet()); } } diff --git a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java index 592d46f33d1..9e4ac66fb53 100644 --- a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java +++ b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java @@ -9,9 +9,7 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class RemoteDockerImageTest { @@ -19,7 +17,7 @@ public class RemoteDockerImageTest { public void toStringContainsOnlyImageName() { String imageName = Base58.randomString(8).toLowerCase(); RemoteDockerImage remoteDockerImage = new RemoteDockerImage(DockerImageName.parse(imageName)); - assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); + assertThat(remoteDockerImage.toString()).contains("imageName=" + imageName); } @Test @@ -28,7 +26,7 @@ public void toStringWithExceptionContainsOnlyImageNameFuture() { imageNameFuture.completeExceptionally(new RuntimeException("arbitrary")); RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture); - assertThat(remoteDockerImage.toString(), containsString("imageName=java.lang.RuntimeException: arbitrary")); + assertThat(remoteDockerImage.toString()).contains("imageName=java.lang.RuntimeException: arbitrary"); } @Test(timeout = 5000L) @@ -36,17 +34,17 @@ public void toStringDoesntResolveImageNameFuture() { CompletableFuture imageNameFuture = new CompletableFuture<>(); // verify that we've set up the test properly - assertFalse(imageNameFuture.isDone()); + assertThat(imageNameFuture).isNotDone(); RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture); - assertThat(remoteDockerImage.toString(), containsString("imageName=")); + assertThat(remoteDockerImage.toString()).contains("imageName="); // Make sure the act of calling toString doesn't resolve the imageNameFuture - assertFalse(imageNameFuture.isDone()); + assertThat(imageNameFuture).isNotDone(); String imageName = Base58.randomString(8).toLowerCase(); imageNameFuture.complete(imageName); - assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); + assertThat(remoteDockerImage.toString()).contains("imageName=" + imageName); } @Test(timeout = 5000L) @@ -62,17 +60,17 @@ protected String resolve() { }; // verify that we've set up the test properly - assertFalse(imageNameFuture.isDone()); + assertThat(imageNameFuture).isNotDone(); RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture); - assertThat(remoteDockerImage.toString(), containsString("imageName=")); + assertThat(remoteDockerImage.toString()).contains("imageName="); // Make sure the act of calling toString doesn't resolve the imageNameFuture - assertFalse(imageNameFuture.isDone()); - assertFalse(resolved.get()); + assertThat(imageNameFuture).isNotDone(); + assertThat(resolved).isFalse(); // Trigger resolve imageNameFuture.get(); - assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); + assertThat(remoteDockerImage.toString()).contains("imageName=" + imageName); } } diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index 08545535e6b..45feb85b359 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -13,8 +13,7 @@ import java.net.Socket; import java.util.concurrent.TimeUnit; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; +import static org.assertj.core.api.Assertions.assertThat; /** * Test of {@link FixedHostPortGenericContainer}. Note that this is not an example of typical use (usually, a container @@ -68,14 +67,12 @@ public void testFixedHostPortMapping() throws IOException { ) { echoServer.start(); - assertThat( - "Port mapping does not seem to match given fixed port", - echoServer.getMappedPort(TEST_PORT), - equalTo(unusedHostPort) - ); + assertThat(echoServer.getMappedPort(TEST_PORT)) + .as("Port mapping does not seem to match given fixed port") + .isEqualTo(unusedHostPort); final String content = this.readResponse(echoServer, unusedHostPort); - assertThat("Returned echo from fixed port does not match expected", content, equalTo(TEST_RESPONSE)); + assertThat(content).as("Returned echo from fixed port does not match expected").isEqualTo(TEST_RESPONSE); } } diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java index 45809f95627..23ad3802c1b 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/AbstractWaitStrategyTest.java @@ -13,7 +13,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.junit.Assert.assertTrue; /** * Common test methods for {@link WaitStrategy} implementations. @@ -124,9 +123,8 @@ protected void waitUntilReadyAndSucceed(GenericContainer container) { // start() blocks until successful or timeout container.start(); - assertTrue( - String.format("Expected container to be ready after timeout of %sms", WAIT_TIMEOUT_MILLIS), - ready.get() - ); + assertThat(ready) + .as(String.format("Expected container to be ready after timeout of %sms", WAIT_TIMEOUT_MILLIS)) + .isTrue(); } } diff --git a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java index 972bf2ab66a..37bbe985bac 100644 --- a/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/junit/wait/strategy/HttpWaitStrategyTest.java @@ -11,8 +11,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; +import static org.assertj.core.api.Assertions.assertThat; /** * Tests for {@link HttpWaitStrategy}. @@ -55,8 +54,8 @@ public void testWaitUntilReadyWithSuccessWithCustomHeaders() { String logs = container.getLogs(); - assertThat(logs, containsString("foo: bar")); - assertThat(logs, containsString("baz: boo")); + assertThat(logs).contains("foo: bar"); + assertThat(logs).contains("baz: boo"); } } diff --git a/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java b/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java index fb3c7e05c0b..cd95d8a5f3d 100644 --- a/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java +++ b/core/src/test/java/org/testcontainers/utility/ComparableVersionTest.java @@ -7,7 +7,7 @@ import java.util.Arrays; -import static org.junit.Assert.assertArrayEquals; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Parameterized.class) public class ComparableVersionTest { @@ -23,7 +23,7 @@ public ComparableVersionTest(final String given, final int[] expected) { @Test public void shouldParseVersions() { - assertArrayEquals(expected, ComparableVersion.parseVersion(given)); + assertThat(ComparableVersion.parseVersion(given)).containsExactly(expected); } @Parameters(name = "Parsed version: {0}={1}") diff --git a/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java b/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java index 0978003f815..90f7745edd7 100644 --- a/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java +++ b/core/src/test/java/org/testcontainers/utility/DefaultImageNameSubstitutorTest.java @@ -5,8 +5,7 @@ import org.junit.Test; import org.mockito.Mockito; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; public class DefaultImageNameSubstitutorTest { @@ -34,7 +33,7 @@ public void testConfigurationLookup() { final DockerImageName substitute = underTest.apply(ORIGINAL_IMAGE); - assertEquals("match is found", SUBSTITUTE_IMAGE, substitute); - assertTrue("compatibility is automatically set", substitute.isCompatibleWith(ORIGINAL_IMAGE)); + assertThat(substitute).as("match is found").isEqualTo(SUBSTITUTE_IMAGE); + assertThat(substitute.isCompatibleWith(ORIGINAL_IMAGE)).as("compatibility is automatically set").isTrue(); } } diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java index e9aac2ed475..0bb1b3f75ca 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java @@ -1,17 +1,12 @@ package org.testcontainers.utility; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.containsString; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class DockerImageNameCompatibilityTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testPlainImage() { DockerImageName subject = DockerImageName.parse("foo"); @@ -98,10 +93,9 @@ public void testAssertMethodAcceptsCompatible() { @Test public void testAssertMethodRejectsIncompatible() { - thrown.expect(IllegalStateException.class); - thrown.expectMessage(containsString("Failed to verify that image 'foo' is a compatible substitute for 'bar'")); - DockerImageName subject = DockerImageName.parse("foo"); - subject.assertCompatibleWith(DockerImageName.parse("bar")); + assertThatThrownBy(() -> subject.assertCompatibleWith(DockerImageName.parse("bar"))) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Failed to verify that image 'foo' is a compatible substitute for 'bar'"); } } diff --git a/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java b/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java index 36196aaf4c1..304bbc4190d 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerStatusTest.java @@ -11,8 +11,7 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; /** @@ -63,24 +62,24 @@ public static Object[][] parameters() { @Test public void testRunning() throws Exception { - assertTrue(DockerStatus.isContainerRunning(running, minimumDuration, now)); - assertTrue(DockerStatus.isContainerRunning(runningVariant, minimumDuration, now)); - assertFalse(DockerStatus.isContainerRunning(shortRunning, minimumDuration, now)); - assertFalse(DockerStatus.isContainerRunning(created, minimumDuration, now)); - assertFalse(DockerStatus.isContainerRunning(createdVariant, minimumDuration, now)); - assertFalse(DockerStatus.isContainerRunning(exited, minimumDuration, now)); - assertFalse(DockerStatus.isContainerRunning(paused, minimumDuration, now)); + assertThat(DockerStatus.isContainerRunning(running, minimumDuration, now)).isTrue(); + assertThat(DockerStatus.isContainerRunning(runningVariant, minimumDuration, now)).isTrue(); + assertThat(DockerStatus.isContainerRunning(shortRunning, minimumDuration, now)).isFalse(); + assertThat(DockerStatus.isContainerRunning(created, minimumDuration, now)).isFalse(); + assertThat(DockerStatus.isContainerRunning(createdVariant, minimumDuration, now)).isFalse(); + assertThat(DockerStatus.isContainerRunning(exited, minimumDuration, now)).isFalse(); + assertThat(DockerStatus.isContainerRunning(paused, minimumDuration, now)).isFalse(); } @Test public void testStopped() throws Exception { - assertFalse(DockerStatus.isContainerStopped(running)); - assertFalse(DockerStatus.isContainerStopped(runningVariant)); - assertFalse(DockerStatus.isContainerStopped(shortRunning)); - assertFalse(DockerStatus.isContainerStopped(created)); - assertFalse(DockerStatus.isContainerStopped(createdVariant)); - assertTrue(DockerStatus.isContainerStopped(exited)); - assertFalse(DockerStatus.isContainerStopped(paused)); + assertThat(DockerStatus.isContainerStopped(running)).isFalse(); + assertThat(DockerStatus.isContainerStopped(runningVariant)).isFalse(); + assertThat(DockerStatus.isContainerStopped(shortRunning)).isFalse(); + assertThat(DockerStatus.isContainerStopped(created)).isFalse(); + assertThat(DockerStatus.isContainerStopped(createdVariant)).isFalse(); + assertThat(DockerStatus.isContainerStopped(exited)).isTrue(); + assertThat(DockerStatus.isContainerStopped(paused)).isFalse(); } private String buildTimestamp(Instant instant) { diff --git a/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java b/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java index 30367975d1e..2741edb5cee 100644 --- a/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java +++ b/core/src/test/java/org/testcontainers/utility/FilterRegistryTest.java @@ -13,9 +13,7 @@ import java.util.List; import java.util.Map.Entry; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class FilterRegistryTest { @@ -38,7 +36,7 @@ public void registerReturnsTrueIfAcknowledgementIsReadFromInputStream() throws I boolean successful = registry.register(FILTERS); - assertTrue(successful); + assertThat(successful).isTrue(); } @Test @@ -47,7 +45,7 @@ public void registerReturnsFalseIfNoAcknowledgementIsReadFromInputStream() throw boolean successful = registry.register(FILTERS); - assertFalse(successful); + assertThat(successful).isFalse(); } @Test @@ -57,7 +55,7 @@ public void registerWritesUrlEncodedFiltersAndNewlineToOutputStream() throws IOE registry.register(FILTERS); - assertEquals(URL_ENCODED_FILTERS + NEW_LINE, new String(outputStream.toByteArray())); + assertThat(new String(outputStream.toByteArray())).isEqualTo(URL_ENCODED_FILTERS + NEW_LINE); } private static InputStream inputStream(byte[] bytes) { diff --git a/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java b/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java index 60f57a28b3e..77c5d528ba4 100644 --- a/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java +++ b/core/src/test/java/org/testcontainers/utility/ResourceReaperTest.java @@ -20,7 +20,6 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; public class ResourceReaperTest { @@ -81,7 +80,7 @@ private Map runProcess(Consumer processExecutor processExecutorConsumer.accept(processExecutor); ProcessResult result = processExecutor.execute(); - assertEquals(0, result.getExitValue()); + assertThat(result.getExitValue()).isEqualTo(0); String labelsJson = Stream .of(result.outputUTF8().split("\n")) diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index 218ed90e5e0..a32f23ca8c2 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -12,7 +12,7 @@ import java.io.IOException; import java.util.Objects; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class CmdModifierTest { @@ -43,13 +43,13 @@ public class CmdModifierTest { @Test public void testHostnameModified() throws IOException, InterruptedException { final Container.ExecResult execResult = theCache.execInContainer("hostname"); - assertEquals("the-cache", execResult.getStdout().trim()); + assertThat(execResult.getStdout().trim()).isEqualTo("the-cache"); } @Test public void testMemoryLimitModified() throws IOException, InterruptedException { final Container.ExecResult execResult = memoryLimitedRedis.execInContainer("cat", getMemoryLimitFilePath()); - assertEquals(String.valueOf(memoryInBytes), execResult.getStdout().trim()); + assertThat(execResult.getStdout().trim()).isEqualTo(String.valueOf(memoryInBytes)); } private String getMemoryLimitFilePath() { diff --git a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java b/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java index 80292465521..3cab77770dc 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java @@ -5,7 +5,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class CommandsTest { @@ -18,6 +18,6 @@ public class CommandsTest { @Test public void testStartupCommandOverrideApplied() { - assertTrue(redisWithCustomPort.isRunning()); // good enough to check that the container started listening + assertThat(redisWithCustomPort.isRunning()).isTrue(); // good enough to check that the container started listening } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java index 0f6269968dd..d98e09ff036 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java @@ -5,7 +5,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class ContainerCreationTest { @@ -39,7 +39,7 @@ public class ContainerCreationTest { @Test public void testStartup() { - assertTrue(redis.isRunning()); // good enough to check that the container started listening - assertTrue(alpine.isRunning()); // good enough to check that the container started listening + assertThat(redis.isRunning()).isTrue(); // good enough to check that the container started listening + assertThat(alpine.isRunning()).isTrue(); // good enough to check that the container started listening } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java b/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java index 6534a35a00f..7116f375283 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java @@ -4,7 +4,7 @@ import org.junit.Test; import org.testcontainers.containers.GenericContainer; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class DependsOnTest { @@ -19,7 +19,7 @@ public class DependsOnTest { @Test public void testContainersAllStarted() { - assertTrue(redis.isRunning()); - assertTrue(nginx.isRunning()); + assertThat(redis.isRunning()).isTrue(); + assertThat(nginx.isRunning()).isTrue(); } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java index 7548ae4a613..7ccb0f2cc54 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java @@ -8,7 +8,7 @@ import java.io.IOException; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class ExecTest { @@ -26,8 +26,8 @@ public void testSimpleExec() throws IOException, InterruptedException { Container.ExecResult lsResult = container.execInContainer("ls", "-al", "/"); String stdout = lsResult.getStdout(); int exitCode = lsResult.getExitCode(); - assertTrue(stdout.contains("somefile.txt")); - assertTrue(exitCode == 0); + assertThat(stdout).contains("somefile.txt"); + assertThat(exitCode).isZero(); // } } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java b/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java index 22bf0332a9d..3e80133411a 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java @@ -13,7 +13,7 @@ import java.io.OutputStream; import java.net.InetSocketAddress; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class HostPortExposedTest { @@ -62,6 +62,6 @@ public void testContainerRunningAgainstExposedHostPort() { // } final String pageSource = webDriver.getPageSource(); - assertTrue(pageSource.contains("Hello World!")); + assertThat(pageSource).contains("Hello World!"); } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java b/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java index bdc0d3ced8a..0b2b166d1d9 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java @@ -8,7 +8,7 @@ import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class WaitStrategiesTest { @@ -69,8 +69,8 @@ public class WaitStrategiesTest { @Test public void testContainersAllStarted() { - assertTrue(nginx.isRunning()); - assertTrue(nginxWithHttpWait.isRunning()); - assertTrue(containerWithLogWait.isRunning()); + assertThat(nginx.isRunning()).isTrue(); + assertThat(nginxWithHttpWait.isRunning()).isTrue(); + assertThat(containerWithLogWait.isRunning()).isTrue(); } } diff --git a/docs/examples/junit4/redis/build.gradle b/docs/examples/junit4/redis/build.gradle index ea36761b716..7ab7cddc88f 100644 --- a/docs/examples/junit4/redis/build.gradle +++ b/docs/examples/junit4/redis/build.gradle @@ -5,4 +5,5 @@ dependencies { testImplementation "junit:junit:4.13.2" testImplementation project(":testcontainers") + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java index 1d3d178975f..0f219397bdc 100644 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java @@ -6,7 +6,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class RedisBackedCacheIntTest { @@ -33,6 +33,6 @@ public void testSimplePutAndGet() { underTest.put("test", "example"); String retrieved = underTest.get("test"); - assertEquals("example", retrieved); + assertThat(retrieved).isEqualTo("example"); } } diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java index f837b3af0d5..e3f52403c48 100644 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java +++ b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java @@ -4,7 +4,7 @@ import org.junit.Ignore; import org.junit.Test; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @Ignore("This test class is deliberately invalid, as it relies on a non-existent local Redis") public class RedisBackedCacheIntTestStep0 { @@ -22,6 +22,6 @@ public void testSimplePutAndGet() { underTest.put("test", "example"); String retrieved = underTest.get("test"); - assertEquals("example", retrieved); + assertThat(retrieved).isEqualTo("example"); } } diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index ab32d55df91..1865f70f801 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -12,5 +12,6 @@ dependencies { testImplementation 'org.postgresql:postgresql:42.4.1' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:postgresql' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java index b84b2a9e2c9..6e4186698e7 100644 --- a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java @@ -5,7 +5,7 @@ import org.junit.rules.RuleChain; import org.testcontainers.containers.PostgreSQLContainer; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * Tests for RedmineClient. @@ -33,9 +33,6 @@ public void canGetIssueCount() throws Exception { RedmineClient redmineClient = new RedmineClient( redmineContainer.getRedmineUrl()); - assertEquals( - "The issue count can be retrieved.", - 0, - redmineClient.getIssueCount()); + assertThat(redmineClient.getIssueCount()).as("The issue count can be retrieved.").isZero(); } } diff --git a/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java index d151e1a3f24..bc7aeed10bd 100644 --- a/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java +++ b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java @@ -20,7 +20,7 @@ import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.fail; // junitExample { @Testcontainers diff --git a/modules/cassandra/build.gradle b/modules/cassandra/build.gradle index 385001db8f8..ff110637ced 100644 --- a/modules/cassandra/build.gradle +++ b/modules/cassandra/build.gradle @@ -9,5 +9,7 @@ configurations.all { dependencies { api project(":database-commons") api "com.datastax.cassandra:cassandra-driver-core:3.10.0" + testImplementation 'com.datastax.oss:java-driver-core:4.14.1' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java index d1ad581bcc0..d8f21fc3068 100644 --- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java @@ -9,9 +9,7 @@ import org.testcontainers.containers.wait.CassandraQueryWaitStrategy; import org.testcontainers.utility.DockerImageName; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Eugeny Karpov @@ -30,8 +28,8 @@ public void testSimple() { try (CassandraContainer cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE)) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, BASIC_QUERY); - assertTrue("Query was not applied", resultSet.wasApplied()); - assertNotNull("Result set has no release_version", resultSet.one().getString(0)); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + assertThat(resultSet.one().getString(0)).as("Result set has release_version").isNotNull(); } } @@ -45,8 +43,8 @@ public void testSpecificVersion() { ) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, BASIC_QUERY); - assertTrue("Query was not applied", resultSet.wasApplied()); - assertEquals("Cassandra has wrong version", cassandraVersion, resultSet.one().getString(0)); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + assertThat(resultSet.one().getString(0)).as("Cassandra has right version").isEqualTo(cassandraVersion); } } @@ -58,12 +56,10 @@ public void testConfigurationOverride() { ) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, "SELECT cluster_name FROM system.local"); - assertTrue("Query was not applied", resultSet.wasApplied()); - assertEquals( - "Cassandra configuration is not overridden", - TEST_CLUSTER_NAME_IN_CONF, - resultSet.one().getString(0) - ); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + assertThat(resultSet.one().getString(0)) + .as("Cassandra configuration is overridden") + .isEqualTo(TEST_CLUSTER_NAME_IN_CONF); } } @@ -110,7 +106,7 @@ public void testCassandraQueryWaitStrategy() { ) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer, BASIC_QUERY); - assertTrue("Query was not applied", resultSet.wasApplied()); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); } } @@ -120,17 +116,17 @@ public void testCassandraGetCluster() { try (CassandraContainer cassandraContainer = new CassandraContainer<>()) { cassandraContainer.start(); ResultSet resultSet = performQuery(cassandraContainer.getCluster(), BASIC_QUERY); - assertTrue("Query was not applied", resultSet.wasApplied()); - assertNotNull("Result set has no release_version", resultSet.one().getString(0)); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + assertThat(resultSet.one().getString(0)).as("Result set has release_version").isNotNull(); } } private void testInitScript(CassandraContainer cassandraContainer) { ResultSet resultSet = performQuery(cassandraContainer, "SELECT * FROM keySpaceTest.catalog_category"); - assertTrue("Query was not applied", resultSet.wasApplied()); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); Row row = resultSet.one(); - assertEquals("Inserted row is not in expected state", 1, row.getLong(0)); - assertEquals("Inserted row is not in expected state", "test_category", row.getString(1)); + assertThat(row.getLong(0)).as("Inserted row is in expected state").isEqualTo(1); + assertThat(row.getString(1)).as("Inserted row is in expected state").isEqualTo("test_category"); } private ResultSet performQuery(CassandraContainer cassandraContainer, String cql) { diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java index 78f3fd2a664..502f2ca8e67 100644 --- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver3Test.java @@ -6,7 +6,7 @@ import org.junit.Rule; import org.junit.Test; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; public class CassandraDriver3Test { @@ -31,7 +31,7 @@ public void testCassandraGetContactPoint() { KeyspaceMetadata keyspace = session.getMetadata().getKeyspaces().get(CqlIdentifier.fromCql("test")); - assertNotNull("Failed to create test keyspace", keyspace); + assertThat(keyspace).as("keyspace created").isNotNull(); } } } diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java index 3a05bc723bc..a4fb8c87b8e 100644 --- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraDriver4Test.java @@ -6,7 +6,7 @@ import org.junit.Rule; import org.junit.Test; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; public class CassandraDriver4Test { @@ -29,7 +29,7 @@ public void testCassandraGetContactPoint() { KeyspaceMetadata keyspace = session.getMetadata().getKeyspaces().get(CqlIdentifier.fromCql("test")); - assertNotNull("Failed to create test keyspace", keyspace); + assertThat(keyspace).as("test keyspace created").isNotNull(); } } } diff --git a/modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java b/modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java index e29ff7ffbd8..c0c022d31bb 100644 --- a/modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java +++ b/modules/consul/src/test/java/org/testcontainers/consul/ConsulContainerTest.java @@ -4,9 +4,6 @@ import com.ecwid.consul.v1.Response; import com.ecwid.consul.v1.kv.model.GetValue; import io.restassured.RestAssured; -import org.assertj.core.api.Assertions; -import org.hamcrest.CoreMatchers; -import org.hamcrest.MatcherAssert; import org.junit.ClassRule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; @@ -17,6 +14,8 @@ import java.util.HashMap; import java.util.Map; +import static org.assertj.core.api.Assertions.assertThat; + /** * This test shows the pattern to use the ConsulContainer @ClassRule for a junit test. It also has tests that ensure * the properties were added correctly by reading from Consul with the CLI and over HTTP. @@ -31,21 +30,19 @@ public class ConsulContainerTest { public void readFirstPropertyPathWithCli() throws IOException, InterruptedException { GenericContainer.ExecResult result = consulContainer.execInContainer("consul", "kv", "get", "config/testing1"); final String output = result.getStdout().replaceAll("\\r?\\n", ""); - MatcherAssert.assertThat(output, CoreMatchers.containsString("value123")); + assertThat(output).contains("value123"); } @Test - public void readFirstSecretPathOverHttpApi() throws InterruptedException { - RestAssured + public void readFirstSecretPathOverHttpApi() { + io.restassured.response.Response response = RestAssured .given() .when() .get("http://" + getHostAndPort() + "/v1/kv/config/testing1") - .then() - .assertThat() - .body( - "[0].Value", - CoreMatchers.equalTo(Base64.getEncoder().encodeToString("value123".getBytes(StandardCharsets.UTF_8))) - ); + .andReturn(); + + assertThat(response.body().jsonPath().getString("[0].Value")) + .isEqualTo(Base64.getEncoder().encodeToString("value123".getBytes(StandardCharsets.UTF_8))); } @Test @@ -62,13 +59,13 @@ public void writeAndReadMultipleValuesUsingClient() { // Write operation properties.forEach((key, value) -> { Response writeResponse = consulClient.setKVValue(key, value); - Assertions.assertThat(writeResponse.getValue()).isTrue(); + assertThat(writeResponse.getValue()).isTrue(); }); // Read operation properties.forEach((key, value) -> { Response readResponse = consulClient.getKVValue(key); - Assertions.assertThat(readResponse.getValue().getDecodedValue()).isEqualTo(value); + assertThat(readResponse.getValue().getDecodedValue()).isEqualTo(value); }); } diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 10970df542e..6cdacbcf77a 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -7,4 +7,5 @@ dependencies { testImplementation 'com.couchbase.client:java-client:3.3.3' testImplementation 'org.awaitility:awaitility:4.2.0' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java index 1bdbe2ab1db..691dc1307ef 100644 --- a/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java +++ b/modules/couchbase/src/test/java/org/testcontainers/couchbase/CouchbaseContainerTest.java @@ -27,10 +27,9 @@ import java.time.Duration; import java.util.function.Consumer; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThrows; public class CouchbaseContainerTest { @@ -66,7 +65,7 @@ public void testBasicContainerUsageForEnterpriseContainer() { JsonObject fooObject = collection.get("foo").contentAsObject(); - assertEquals("value", fooObject.getString("key")); + assertThat(fooObject.getString("key")).isEqualTo("value"); } ); } @@ -92,7 +91,7 @@ public void testBasicContainerUsageForCommunityContainer() { JsonObject fooObject = collection.get("foo").contentAsObject(); - assertEquals("value", fooObject.getString("key")); + assertThat(fooObject.getString("key")).isEqualTo("value"); } ); } @@ -118,7 +117,7 @@ public void testBucketIsFlushableIfEnabled() { cluster.buckets().flushBucket(bucketDefinition.getName()); - await().untilAsserted(() -> assertFalse(collection.exists("foo").exists())); + await().untilAsserted(() -> assertThat(collection.exists("foo").exists()).isFalse()); } ); } @@ -134,12 +133,10 @@ public void testFailureIfCommunityUsedWithAnalytics() { CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) .withEnabledServices(CouchbaseService.KV, CouchbaseService.ANALYTICS) ) { - assertThrows( - ContainerLaunchException.class, - () -> { + assertThatThrownBy(() -> { setUpClient(container, cluster -> {}); - } - ); + }) + .isInstanceOf(ContainerLaunchException.class); } } @@ -153,12 +150,10 @@ public void testFailureIfCommunityUsedWithEventing() { CouchbaseContainer container = new CouchbaseContainer(COUCHBASE_IMAGE_COMMUNITY) .withEnabledServices(CouchbaseService.KV, CouchbaseService.EVENTING) ) { - assertThrows( - ContainerLaunchException.class, - () -> { + assertThatThrownBy(() -> { setUpClient(container, cluster -> {}); - } - ); + }) + .isInstanceOf(ContainerLaunchException.class); } } diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index a7ff4e66729..2a75c343653 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -5,4 +5,5 @@ dependencies { compileOnly 'org.influxdb:influxdb-java:2.23' testImplementation 'org.influxdb:influxdb-java:2.23' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java index c7fc71a3a19..bcf3d21f25b 100644 --- a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java +++ b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerTest.java @@ -4,9 +4,7 @@ import org.junit.ClassRule; import org.junit.Test; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class InfluxDBContainerTest { @@ -19,28 +17,28 @@ public class InfluxDBContainerTest { public void getUrl() { String actual = influxDBContainer.getUrl(); - assertThat(actual, notNullValue()); + assertThat(actual).isNotNull(); } @Test public void getNewInfluxDB() { InfluxDB actual = influxDBContainer.getNewInfluxDB(); - assertThat(actual, notNullValue()); - assertThat(actual.ping(), notNullValue()); + assertThat(actual).isNotNull(); + assertThat(actual.ping()).isNotNull(); } @Test public void getLivenessCheckPort() { Integer actual = influxDBContainer.getLivenessCheckPort(); - assertThat(actual, notNullValue()); + assertThat(actual).isNotNull(); } @Test public void isRunning() { boolean actual = influxDBContainer.isRunning(); - assertThat(actual, is(true)); + assertThat(actual).isTrue(); } } diff --git a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java index a7ae347e7cc..7a34bbb4fd6 100644 --- a/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java +++ b/modules/influxdb/src/test/java/org/testcontainers/containers/InfluxDBContainerWithUserTest.java @@ -9,11 +9,7 @@ import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class InfluxDBContainerWithUserTest { @@ -35,20 +31,20 @@ public class InfluxDBContainerWithUserTest { public void describeDatabases() { InfluxDB actual = influxDBContainer.getNewInfluxDB(); - assertThat(actual, notNullValue()); - assertThat(actual.describeDatabases(), hasItem(DATABASE)); + assertThat(actual).isNotNull(); + assertThat(actual.describeDatabases()).contains(DATABASE); } @Test public void checkVersion() { InfluxDB actual = influxDBContainer.getNewInfluxDB(); - assertThat(actual, notNullValue()); + assertThat(actual).isNotNull(); - assertThat(actual.ping(), notNullValue()); - assertThat(actual.ping().getVersion(), is(TEST_VERSION)); + assertThat(actual.ping()).isNotNull(); + assertThat(actual.ping().getVersion()).isEqualTo(TEST_VERSION); - assertThat(actual.version(), is(TEST_VERSION)); + assertThat(actual.version()).isEqualTo(TEST_VERSION); } @Test @@ -67,9 +63,9 @@ public void queryForWriteAndRead() { Query query = new Query("SELECT idle FROM cpu", DATABASE); QueryResult actual = influxDB.query(query); - assertThat(actual, notNullValue()); - assertThat(actual.getError(), nullValue()); - assertThat(actual.getResults(), notNullValue()); - assertThat(actual.getResults().size(), is(1)); + assertThat(actual).isNotNull(); + assertThat(actual.getError()).isNull(); + assertThat(actual.getResults()).isNotNull(); + assertThat(actual.getResults()).hasSize(1); } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java index 5b4d223cd36..4edd5d449ba 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/ContainerDatabaseDriverTest.java @@ -1,7 +1,6 @@ package org.testcontainers.jdbc; import org.hamcrest.CoreMatchers; -import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -11,6 +10,8 @@ import java.sql.SQLException; import java.util.Properties; +import static org.assertj.core.api.Assertions.assertThat; + public class ContainerDatabaseDriverTest { private static final String PLAIN_POSTGRESQL_JDBC_URL = "jdbc:postgresql://localhost:5432/test"; @@ -22,7 +23,7 @@ public class ContainerDatabaseDriverTest { public void shouldNotTryToConnectToNonMatchingJdbcUrlDirectly() throws SQLException { ContainerDatabaseDriver driver = new ContainerDatabaseDriver(); Connection connection = driver.connect(PLAIN_POSTGRESQL_JDBC_URL, new Properties()); - Assert.assertNull(connection); + assertThat(connection).isNull(); } @Test diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java index 186d4095b0d..ee6d1f1a841 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/PostgresContainerTests.java @@ -8,7 +8,7 @@ import java.sql.ResultSet; import java.sql.Statement; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @Testcontainers class PostgresContainerTests { @@ -35,7 +35,7 @@ void waits_until_postgres_accepts_jdbc_connections() throws Exception { resultSet.next(); int resultSetInt = resultSet.getInt(1); - assertEquals(1, resultSetInt); + assertThat(resultSetInt).isEqualTo(1); } } } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java index 09b816be56e..b64f2f3c328 100644 --- a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/TestLifecycleAwareExceptionCapturingTest.java @@ -6,8 +6,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; // The order of @ExtendsWith and @Testcontainers is crucial in order for the tests @@ -32,7 +31,7 @@ void failing_test_should_pass_throwable_to_testContainer() { @Order(2) void should_have_captured_thrownException() { Throwable capturedThrowable = startedTestContainer.getCapturedThrowable(); - assertTrue(capturedThrowable instanceof AssumptionViolatedException); - assertEquals("got: , expected: is ", capturedThrowable.getMessage()); + assertThat(capturedThrowable).isInstanceOf(AssumptionViolatedException.class); + assertThat(capturedThrowable.getMessage()).isEqualTo("got: , expected: is "); } } diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index a678d30eb80..b879b27f0e6 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -22,7 +22,6 @@ import com.amazonaws.services.sqs.model.CreateQueueResult; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; -import org.junit.Assert; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.runners.Enclosed; @@ -320,7 +319,7 @@ private String runAwsCliAgainstDockerNetworkContainer(String command) throws Exc ) .split(" "); final Container.ExecResult execResult = awsCliInDockerNetwork.execInContainer(commandParts); - Assert.assertEquals(0, execResult.getExitCode()); + assertThat(execResult.getExitCode()).isEqualTo(0); final String logs = execResult.getStdout() + execResult.getStderr(); log.info(logs); diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index 7f9725bf0e8..6e4b5208298 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -4,4 +4,5 @@ dependencies { api project(':testcontainers') testImplementation("org.mongodb:mongodb-driver-sync:4.7.1") + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index 6c98978f20a..ff6d0d6ccba 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -13,10 +13,7 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; -import static org.hamcrest.Matchers.endsWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class MongoDBContainerTest { @@ -35,7 +32,7 @@ public void shouldExecuteTransactions() { // } final String mongoRsUrl = mongoDBContainer.getReplicaSetUrl(); - assertNotNull(mongoRsUrl); + assertThat(mongoRsUrl).isNotNull(); final String connectionString = mongoDBContainer.getConnectionString(); final MongoClient mongoSyncClientBase = MongoClients.create(connectionString); final MongoClient mongoSyncClient = MongoClients.create(mongoRsUrl); @@ -76,7 +73,7 @@ public void shouldExecuteTransactions() { try { final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions); - assertEquals(trxResult, trxResultActual); + assertThat(trxResultActual).isEqualTo(trxResult); } catch (RuntimeException re) { throw new IllegalStateException(re.getMessage(), re); } finally { @@ -98,7 +95,7 @@ public void shouldTestDatabaseName() { try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))) { mongoDBContainer.start(); final String databaseName = "my-db"; - assertThat(mongoDBContainer.getReplicaSetUrl(databaseName), endsWith(databaseName)); + assertThat(mongoDBContainer.getReplicaSetUrl(databaseName)).endsWith(databaseName); } } } diff --git a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java index b48bd67efc9..b7afba041de 100644 --- a/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java +++ b/modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java @@ -8,8 +8,8 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class SimpleOracleTest extends AbstractContainerDatabaseTest { @@ -20,15 +20,15 @@ public class SimpleOracleTest extends AbstractContainerDatabaseTest { private void runTest(OracleContainer container, String databaseName, String username, String password) throws SQLException { //Test config was honored - assertEquals(databaseName, container.getDatabaseName()); - assertEquals(username, container.getUsername()); - assertEquals(password, container.getPassword()); + assertThat(container.getDatabaseName()).isEqualTo(databaseName); + assertThat(container.getUsername()).isEqualTo(username); + assertThat(container.getPassword()).isEqualTo(password); //Test we can get a connection container.start(); ResultSet resultSet = performQuery(container, "SELECT 1 FROM dual"); int resultSetInt = resultSet.getInt(1); - assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } @Test @@ -38,7 +38,7 @@ public void testDefaultSettings() throws SQLException { // Match against the last '/' String urlSuffix = oracle.getJdbcUrl().split("(\\/)(?!.*\\/)", 2)[1]; - assertEquals("xepdb1", urlSuffix); + assertThat(urlSuffix).isEqualTo("xepdb1"); } } @@ -81,7 +81,7 @@ public void testSID() throws SQLException { // Match against the last ':' String urlSuffix = oracle.getJdbcUrl().split("(\\:)(?!.*\\:)", 2)[1]; - assertEquals("xe", urlSuffix); + assertThat(urlSuffix).isEqualTo("xe"); } } diff --git a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java index a54108ea1a2..721186807aa 100644 --- a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java +++ b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java @@ -1,6 +1,5 @@ package org.testcontainers.containers; -import org.junit.Assert; import org.junit.Test; import org.testcontainers.PrestoTestImages; @@ -13,9 +12,7 @@ import java.util.Arrays; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * @author findepi @@ -31,8 +28,10 @@ public void testSimple() throws Exception { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") ) { - assertTrue("No result", resultSet.next()); - assertEquals("Presto version", PrestoContainer.DEFAULT_TAG, resultSet.getString("node_version")); + assertThat(resultSet.next()).as("has result").isTrue(); + assertThat(resultSet.getString("node_version")) + .as("Presto version") + .isEqualTo(PrestoContainer.DEFAULT_TAG); } } } @@ -48,12 +47,10 @@ public void testSpecificVersion() throws Exception { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") ) { - assertTrue("No result", resultSet.next()); - assertEquals( - "Presto version", - PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), - resultSet.getString("node_version") - ); + assertThat(resultSet.next()).as("has result").isTrue(); + assertThat(resultSet.getString("node_version")) + .as("Presto version") + .isEqualTo(PrestoTestImages.PRESTO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart()); } } } @@ -86,7 +83,7 @@ public void testQueryMemoryAndTpch() throws SQLException { while (resultSet.next()) { actualElements.add(resultSet.getInt("element")); } - Assert.assertEquals(Arrays.asList(2, 4, 42, 42, 42), actualElements); + assertThat(actualElements).isEqualTo(Arrays.asList(2, 4, 42, 42, 42)); } } } @@ -102,9 +99,9 @@ public void testInitScript() throws Exception { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table") ) { - assertTrue("No result", resultSet.next()); - assertEquals("Value", 12345678909324L, resultSet.getObject("a")); - assertFalse("Too many result", resultSet.next()); + assertThat(resultSet.next()).as("has result").isTrue(); + assertThat(resultSet.getObject("a")).as("Value").isEqualTo(12345678909324L); + assertThat(resultSet.next()).as("only has one result").isFalse(); } } } @@ -117,47 +114,39 @@ public void testTcJdbcUri() throws Exception { ) ) { // Verify metadata with tc: JDBC connection URI - assertEquals( - connection.getMetaData().getDatabaseMajorVersion(), - Integer.parseInt(PrestoContainer.DEFAULT_TAG) - ); + assertThat(Integer.parseInt(PrestoContainer.DEFAULT_TAG)) + .isEqualTo(connection.getMetaData().getDatabaseMajorVersion()); // Verify transactions with tc: JDBC connection URI - assertTrue("Is autocommit", connection.getAutoCommit()); + assertThat(connection.getAutoCommit()).as("Is autocommit").isTrue(); connection.setAutoCommit(false); - assertFalse("Is autocommit", connection.getAutoCommit()); - assertEquals( - "Transaction isolation", - Connection.TRANSACTION_READ_UNCOMMITTED, - connection.getTransactionIsolation() - ); + assertThat(connection.getAutoCommit()).as("Is autocommit").isFalse(); + assertThat(connection.getTransactionIsolation()) + .as("Transaction isolation") + .isEqualTo(Connection.TRANSACTION_READ_UNCOMMITTED); try (Statement statement = connection.createStatement()) { - assertEquals( - "Update result", - 0, - statement.executeUpdate("CREATE TABLE memory.default.test_tc(a bigint)") - ); + assertThat(statement.executeUpdate("CREATE TABLE memory.default.test_tc(a bigint)")) + .as("Update result") + .isEqualTo(0); try ( ResultSet resultSet = statement.executeQuery( "SELECT sum(cast(node_version AS bigint)) AS v FROM system.runtime.nodes" ) ) { - assertTrue(resultSet.next()); - assertEquals(PrestoContainer.DEFAULT_TAG, resultSet.getString("v")); - assertFalse(resultSet.next()); + assertThat(resultSet.next()).isTrue(); + assertThat(resultSet.getString("v")).isEqualTo(PrestoContainer.DEFAULT_TAG); + assertThat(resultSet.next()).isFalse(); } connection.commit(); } finally { connection.rollback(); } connection.setAutoCommit(true); - assertTrue("Is autocommit", connection.getAutoCommit()); - assertEquals( - "Transaction isolation should be retained", - Connection.TRANSACTION_READ_UNCOMMITTED, - connection.getTransactionIsolation() - ); + assertThat(connection.getAutoCommit()).as("Is autocommit").isTrue(); + assertThat(connection.getTransactionIsolation()) + .as("Transaction isolation should be retained") + .isEqualTo(Connection.TRANSACTION_READ_UNCOMMITTED); } } } diff --git a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java index 0d8daaad219..aa894810930 100644 --- a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java @@ -15,8 +15,7 @@ import java.util.Collection; import java.util.List; -import static org.hamcrest.Matchers.hasItem; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Parameterized.class) @Value @@ -68,6 +67,6 @@ public void recordingFileThatShouldDescribeTheTestResultAtThePresentTime() throw ) ); - assertThat(expectedPossibleFileNames, hasItem(recordingFile)); + assertThat(expectedPossibleFileNames).contains(recordingFile); } } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java index b2b7d8d6b1c..d0bdb796181 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java @@ -25,8 +25,7 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(Enclosed.class) public class ChromeRecordingWebDriverContainerTest extends BaseWebDriverContainerTest { @@ -56,7 +55,7 @@ public void recordingTestThatShouldBeRecordedAndRetainedInFlvFormatAsDefault() t .withNetwork(NETWORK) ) { File[] files = runSimpleExploreInContainer(chrome, "PASSED-.*\\.flv"); - assertEquals("Recorded file not found", 1, files.length); + assertThat(files).as("Recorded file found").hasSize(1); } } @@ -98,7 +97,7 @@ public void recordingTestShouldHaveFlvExtension() throws InterruptedException { .withNetwork(NETWORK) ) { File[] files = runSimpleExploreInContainer(chrome, "PASSED-.*\\.flv"); - assertEquals("Recorded file not found", 1, files.length); + assertThat(files).as("Recorded file found").hasSize(1); } } @@ -116,7 +115,7 @@ public void recordingTestShouldHaveMp4Extension() throws InterruptedException { .withNetwork(NETWORK) ) { File[] files = runSimpleExploreInContainer(chrome, "PASSED-.*\\.mp4"); - assertEquals("Recorded file not found", 1, files.length); + assertThat(files).as("Recorded file found").hasSize(1); } } @@ -152,10 +151,10 @@ public void recordingTestThatShouldHaveCorrectDuration() throws IOException, Int .start(); String ffmpegOutput = container.getLogs(); - assertTrue( - "Duration is incorrect in:\n " + ffmpegOutput, - ffmpegOutput.contains("Duration: 00:") && !(ffmpegOutput.contains("Duration: 00:00:00.00")) - ); + assertThat(ffmpegOutput) + .as("Duration starts with 00:") + .contains("Duration: 00:") + .doesNotContain("Duration: 00:00:00.00"); } } } @@ -216,7 +215,7 @@ public String getFilesystemFriendlyName() { ); String[] files = vncRecordingDirectory.getRoot().list(new PatternFilenameFilter("FAILED-.*\\.flv")); - assertEquals("Recorded file not found", 1, files.length); + assertThat(files).as("recorded file count").hasSize(1); } } diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index 5a6326f3844..f8e2a99888d 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:4.9.3' testImplementation 'org.apache.solr:solr-solrj:8.11.1' - + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java index 9b561e5cda9..94a02acf579 100644 --- a/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java +++ b/modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java @@ -10,9 +10,7 @@ import java.io.IOException; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Simon Schneider @@ -36,8 +34,8 @@ public void solrCloudTest() throws IOException, SolrServerException { try (SolrContainer container = new SolrContainer(SOLR_IMAGE)) { container.start(); SolrPingResponse response = getClient(container).ping("dummy"); - assertThat(response.getStatus(), is(0)); - assertThat(response.jsonStr(), containsString("zkConnected\":true")); + assertThat(response.getStatus()).isZero(); + assertThat(response.jsonStr()).contains("zkConnected\":true"); } } @@ -46,8 +44,8 @@ public void solrStandaloneTest() throws IOException, SolrServerException { try (SolrContainer container = new SolrContainer(SOLR_IMAGE).withZookeeper(false)) { container.start(); SolrPingResponse response = getClient(container).ping("dummy"); - assertThat(response.getStatus(), is(0)); - assertThat(response.jsonStr(), containsString("zkConnected\":null")); + assertThat(response.getStatus()).isZero(); + assertThat(response.jsonStr()).contains("zkConnected\":null"); } } diff --git a/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java b/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java index c4833f14224..714c9854f39 100644 --- a/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java +++ b/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java @@ -1,7 +1,5 @@ package org.testcontainers.junit.tidb; -import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; import org.testcontainers.TiDBTestImages; import org.testcontainers.db.AbstractContainerDatabaseTest; @@ -10,6 +8,8 @@ import java.sql.ResultSet; import java.sql.SQLException; +import static org.assertj.core.api.Assertions.assertThat; + public class SimpleTiDBTest extends AbstractContainerDatabaseTest { @Test @@ -20,7 +20,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(tidb, "SELECT 1"); int resultSetInt = resultSet.getInt(1); - Assert.assertEquals("A basic SELECT query succeeds", 1, resultSetInt); + assertThat(resultSetInt).isEqualTo(1); } } @@ -34,7 +34,7 @@ public void testExplicitInitScript() throws SQLException { ResultSet resultSet = performQuery(tidb, "SELECT foo FROM bar"); String firstColumnValue = resultSet.getString(1); - Assert.assertEquals("Value from init script should equal real value", "hello world", firstColumnValue); + assertThat(firstColumnValue).isEqualTo("hello world"); } } @@ -45,8 +45,8 @@ public void testWithAdditionalUrlParamInJdbcUrl() { try { tidb.start(); String jdbcUrl = tidb.getJdbcUrl(); - Assert.assertThat(jdbcUrl, Matchers.containsString("?")); - Assert.assertThat(jdbcUrl, Matchers.containsString("sslmode=disable")); + assertThat(jdbcUrl).contains("?"); + assertThat(jdbcUrl).contains("sslmode=disable"); } finally { tidb.stop(); } diff --git a/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java index 97bbdf6dedd..a58944946f0 100644 --- a/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java +++ b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java @@ -7,9 +7,7 @@ import java.sql.ResultSet; import java.sql.Statement; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class TrinoContainerTest { @@ -22,8 +20,10 @@ public void testSimple() throws Exception { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") ) { - assertTrue("No result", resultSet.next()); - assertEquals("Trino version", TrinoContainer.DEFAULT_TAG, resultSet.getString("node_version")); + assertThat(resultSet.next()).as("results").isTrue(); + assertThat(resultSet.getString("node_version")) + .as("Trino version") + .isEqualTo(TrinoContainer.DEFAULT_TAG); } } } @@ -37,12 +37,10 @@ public void testSpecificVersion() throws Exception { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes") ) { - assertTrue("No result", resultSet.next()); - assertEquals( - "Trino version", - TrinoTestImages.TRINO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart(), - resultSet.getString("node_version") - ); + assertThat(resultSet.next()).as("results").isTrue(); + assertThat(resultSet.getString("node_version")) + .as("Trino version") + .isEqualTo(TrinoTestImages.TRINO_PREVIOUS_VERSION_TEST_IMAGE.getVersionPart()); } } } @@ -57,9 +55,9 @@ public void testInitScript() throws Exception { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table") ) { - assertTrue("No result", resultSet.next()); - assertEquals("Value", 12345678909324L, resultSet.getObject("a")); - assertFalse("Too many result", resultSet.next()); + assertThat(resultSet.next()).as("results").isTrue(); + assertThat(resultSet.getObject("a")).as("Value").isEqualTo(12345678909324L); + assertThat(resultSet.next()).as("results").isFalse(); } } } diff --git a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java index 22310bf7a23..f7a7cd49eaf 100644 --- a/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java +++ b/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java @@ -1,5 +1,6 @@ package org.testcontainers.vault; +import io.restassured.response.Response; import org.junit.ClassRule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; @@ -7,8 +8,7 @@ import java.io.IOException; import static io.restassured.RestAssured.given; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * This test shows the pattern to use the VaultContainer @ClassRule for a junit test. It also has tests that ensure @@ -42,7 +42,7 @@ public void readFirstSecretPathWithCli() throws IOException, InterruptedExceptio "secret/testing1" ); final String output = result.getStdout().replaceAll("\\r?\\n", ""); - assertThat(output, containsString("password123")); + assertThat(output).contains("password123"); } @Test @@ -56,49 +56,45 @@ public void readSecondSecretPathWithCli() throws IOException, InterruptedExcepti ); final String output = result.getStdout().replaceAll("\\r?\\n", ""); System.out.println("output = " + output); - assertThat(output, containsString("password1")); - assertThat(output, containsString("password2")); - assertThat(output, containsString("password3")); - assertThat(output, containsString("password4")); + assertThat(output).contains("password1"); + assertThat(output).contains("password2"); + assertThat(output).contains("password3"); + assertThat(output).contains("password4"); } @Test public void readFirstSecretPathOverHttpApi() throws InterruptedException { - given() + Response response = given() .header("X-Vault-Token", VAULT_TOKEN) .when() .get("http://" + getHostAndPort() + "/v1/secret/data/testing1") - .then() - .assertThat() - .body("data.data.top_secret", equalTo("password123")); + .thenReturn(); + assertThat(response.body().jsonPath().getString("data.data.top_secret")).isEqualTo("password123"); } @Test public void readSecondSecretPathOverHttpApi() throws InterruptedException { - given() + Response response = given() .header("X-Vault-Token", VAULT_TOKEN) .when() .get("http://" + getHostAndPort() + "/v1/secret/data/testing2") - .then() - .assertThat() - .body("data.data.secret_one", containsString("password1")) - .assertThat() - .body("data.data.secret_two", containsString("password2")) - .assertThat() - .body("data.data.secret_three", hasItem("password3")) - .assertThat() - .body("data.data.secret_four", containsString("password4")); + .andReturn(); + + assertThat(response.body().jsonPath().getString("data.data.secret_one")).contains("password1"); + assertThat(response.body().jsonPath().getString("data.data.secret_two")).contains("password2"); + assertThat(response.body().jsonPath().getList("data.data.secret_three")).contains("password3"); + assertThat(response.body().jsonPath().getString("data.data.secret_four")).contains("password4"); } @Test public void readTransitKeyOverHttpApi() throws InterruptedException { - given() + Response response = given() .header("X-Vault-Token", VAULT_TOKEN) .when() .get("http://" + getHostAndPort() + "/v1/transit/keys/my-key") - .then() - .assertThat() - .body("data.name", equalTo("my-key")); + .thenReturn(); + + assertThat(response.body().jsonPath().getString("data.name")).isEqualTo("my-key"); } private String getHostAndPort() { diff --git a/test-support/build.gradle b/test-support/build.gradle index bd85b585b0f..ecf9a0bc60e 100644 --- a/test-support/build.gradle +++ b/test-support/build.gradle @@ -1,4 +1,5 @@ dependencies { implementation 'junit:junit:4.13.2' implementation 'org.slf4j:slf4j-api:1.7.30' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java b/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java index 14a3d4c018c..60a311922d0 100644 --- a/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java +++ b/test-support/src/test/java/org/testcontainers/testsupport/FlakyRuleTest.java @@ -6,8 +6,8 @@ import java.lang.annotation.Annotation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class FlakyRuleTest { @@ -33,7 +33,9 @@ public void testIgnoresMethodWithoutAnnotation() throws Throwable { rule.apply(statement, description).evaluate(); fail("Should not reach here"); } catch (Exception ignored) {} - assertEquals("The statement should only be invoked once, even if it throws", 1, statement.invocationCount); + assertThat(statement.invocationCount) + .as("The statement should only be invoked once, even if it throws") + .isEqualTo(1); } @Test @@ -45,7 +47,7 @@ public void testRetriesMethodWithAnnotationUntilFailure() throws Throwable { rule.apply(statement, description).evaluate(); fail("Should not reach here"); } catch (Exception ignored) {} - assertEquals("The statement should be invoked three times", 3, statement.invocationCount); + assertThat(statement.invocationCount).as("The statement should be invoked three times").isEqualTo(3); } @Test @@ -57,7 +59,7 @@ public void testCustomRetryCount() throws Throwable { rule.apply(statement, description).evaluate(); fail("Should not reach here"); } catch (Exception ignored) {} - assertEquals("The statement should be invoked ten times", 10, statement.invocationCount); + assertThat(statement.invocationCount).as("The statement should be invoked ten times").isEqualTo(10); } @Test @@ -68,11 +70,9 @@ public void testRetriesMethodWithAnnotationUntilSuccess() throws Throwable { rule.apply(statement, description).evaluate(); - assertEquals( - "The statement should be invoked three times, and succeed the third time", - 3, - statement.invocationCount - ); + assertThat(statement.invocationCount) + .as("The statement should be invoked three times, and succeed the third time") + .isEqualTo(3); } @Test @@ -83,7 +83,7 @@ public void testDoesNotRetryMethodWithAnnotationIfNotThrowing() throws Throwable rule.apply(statement, description).evaluate(); - assertEquals("The statement should be invoked once", 1, statement.invocationCount); + assertThat(statement.invocationCount).as("The statement should be invoked once").isEqualTo(1); } @Test @@ -94,7 +94,9 @@ public void testTreatsExpiredAnnotationAsNoAnnotation() throws Throwable { rule.apply(statement, description).evaluate(); fail("Should not reach here"); } catch (Exception ignored) {} - assertEquals("The statement should only be invoked once, even if it throws", 1, statement.invocationCount); + assertThat(statement.invocationCount) + .as("The statement should only be invoked once, even if it throws") + .isEqualTo(1); } @Test @@ -105,7 +107,9 @@ public void testThrowsOnInvalidDateFormat() throws Throwable { rule.apply(statement, description).evaluate(); fail("Should not reach here"); } catch (IllegalArgumentException ignored) {} - assertEquals("The statement should not be invoked if the annotation is invalid", 0, statement.invocationCount); + assertThat(statement.invocationCount) + .as("The statement should not be invoked if the annotation is invalid") + .isEqualTo(0); } @Test @@ -116,7 +120,9 @@ public void testThrowsOnInvalidGitHubUrl() throws Throwable { rule.apply(statement, description).evaluate(); fail("Should not reach here"); } catch (IllegalArgumentException ignored) {} - assertEquals("The statement should not be invoked if the annotation is invalid", 0, statement.invocationCount); + assertThat(statement.invocationCount) + .as("The statement should not be invoked if the annotation is invalid") + .isEqualTo(0); } private Description newDescriptionWithAnnotation(String reviewDate, String gitHubUrl) { From 9275bc51e20e0e7bf937f48d2850a9865cb41948 Mon Sep 17 00:00:00 2001 From: Matt Hornung Date: Tue, 16 Aug 2022 10:06:59 -0500 Subject: [PATCH 2144/4969] Make JUnit5 TestcontainersExtension public (#5285) This allows more flexible and programmatic usage of the `TestcontainersExtension` Fixes #2045 --- .../testcontainers/junit/jupiter/TestcontainersExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java index 47ed56d9ac5..5a11b927ec0 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java @@ -32,7 +32,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -class TestcontainersExtension +public class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition { private static final Namespace NAMESPACE = Namespace.create(TestcontainersExtension.class); From df5e1eec19a133dd922498b0634fdd712bcdd153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 16 Aug 2022 11:02:34 -0500 Subject: [PATCH 2145/4969] Drop usage of `org.junit.platform.commons.util` (#5729) Classes from `org.junit.platform.commons.util` are used for internal use in JUnit Jupiter. This commit introduces replacements. --- .../FilesystemFriendlyNameGenerator.java | 3 +- .../jupiter/TestcontainersExtension.java | 28 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java index a8612fc1516..fe5ddcf32e0 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/FilesystemFriendlyNameGenerator.java @@ -1,7 +1,6 @@ package org.testcontainers.junit.jupiter; import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.platform.commons.util.StringUtils; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; @@ -14,7 +13,7 @@ class FilesystemFriendlyNameGenerator { static String filesystemFriendlyNameOf(ExtensionContext context) { String contextId = context.getUniqueId(); try { - return (StringUtils.isBlank(contextId)) + return (contextId == null || contextId.trim().isEmpty()) ? UNKNOWN_NAME : URLEncoder.encode(contextId, StandardCharsets.UTF_8.toString()); } catch (UnsupportedEncodingException e) { diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java index 5a11b927ec0..757083dc322 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java @@ -13,9 +13,9 @@ import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; import org.junit.platform.commons.support.AnnotationSupport; -import org.junit.platform.commons.util.AnnotationUtils; -import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.support.ReflectionSupport; import org.testcontainers.DockerClientFactory; import org.testcontainers.lifecycle.Startable; import org.testcontainers.lifecycle.TestDescription; @@ -131,7 +131,7 @@ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext con private Optional findTestcontainers(ExtensionContext context) { Optional current = Optional.of(context); while (current.isPresent()) { - Optional testcontainers = AnnotationUtils.findAnnotation( + Optional testcontainers = AnnotationSupport.findAnnotation( current.get().getRequiredTestClass(), Testcontainers.class ); @@ -169,26 +169,26 @@ private Set collectParentTestInstances(final ExtensionContext context) { } private List findSharedContainers(Class testClass) { - return ReflectionUtils - .findFields(testClass, isSharedContainer(), ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) + return ReflectionSupport + .findFields(testClass, isSharedContainer(), HierarchyTraversalMode.TOP_DOWN) .stream() .map(f -> getContainerInstance(null, f)) .collect(Collectors.toList()); } private Predicate isSharedContainer() { - return isContainer().and(ReflectionUtils::isStatic); + return isContainer().and(ModifierSupport::isStatic); } private Stream findRestartContainers(Object testInstance) { - return ReflectionUtils - .findFields(testInstance.getClass(), isRestartContainer(), ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) + return ReflectionSupport + .findFields(testInstance.getClass(), isRestartContainer(), HierarchyTraversalMode.TOP_DOWN) .stream() .map(f -> getContainerInstance(testInstance, f)); } private Predicate isRestartContainer() { - return isContainer().and(ReflectionUtils::isNotStatic); + return isContainer().and(ModifierSupport::isNotStatic); } private static Predicate isContainer() { @@ -211,10 +211,10 @@ private static Predicate isContainer() { private static StoreAdapter getContainerInstance(final Object testInstance, final Field field) { try { field.setAccessible(true); - Startable containerInstance = Preconditions.notNull( - (Startable) field.get(testInstance), - "Container " + field.getName() + " needs to be initialized" - ); + Startable containerInstance = (Startable) field.get(testInstance); + if (containerInstance == null) { + throw new ExtensionConfigurationException("Container " + field.getName() + " needs to be initialized"); + } return new StoreAdapter(field.getDeclaringClass(), field.getName(), containerInstance); } catch (IllegalAccessException e) { throw new ExtensionConfigurationException("Can not access container defined in field " + field.getName()); From 18304642dcbbd5db229bc4390d431e9208be88d0 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Thu, 18 Aug 2022 15:01:50 +0200 Subject: [PATCH 2146/4969] Enforce UTF-8 as Javadoc encoding (#5738) * Use com.gradle:common-custom-user-data-gradle-plugin:1.8 (instead of 1.8.0) --- build.gradle | 1 + examples/settings.gradle | 2 +- settings.gradle | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 0ded70ad71a..a53bd19298d 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ subprojects { targetCompatibility = 1.8 compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' + javadoc.options.encoding = 'UTF-8' repositories { mavenCentral() diff --git a/examples/settings.gradle b/examples/settings.gradle index 83ba91e8321..9ed079cd7b8 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -7,7 +7,7 @@ buildscript { dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.0" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8" } } diff --git a/settings.gradle b/settings.gradle index bd51349bb05..2beb91dea01 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.0" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8" } } From 9fb5db16a6af38257256fd04e452737e0f1ac15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 18 Aug 2022 12:09:55 -0500 Subject: [PATCH 2147/4969] Add Pull Request Template (#5735) It provides some useful information about what to take into account when submitting a PR. Co-authored-by: Kevin Wittek --- .github/pull_request_template.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..643177f08a9 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ + From 20fdee2da625aa3c12d1212ea0b370f299901e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 18 Aug 2022 18:06:21 -0500 Subject: [PATCH 2148/4969] Add `Transferable.of(String, int)` (#5741) The new method adds similar capability of `Transferable.of(byte[], int)` but for `String`. --- core/build.gradle | 6 ++++++ .../testcontainers/images/builder/Transferable.java | 4 ++++ .../containers/GenericContainerTest.java | 13 +++++++++++++ 3 files changed, 23 insertions(+) diff --git a/core/build.gradle b/core/build.gradle index c210ed48510..aa4c6eabf22 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -113,3 +113,9 @@ tasks.generatePomFileForMavenJavaPublication.finalizedBy( ] } ) + +tasks.japicmp { + methodExcludes = [ + "org.testcontainers.images.builder.Transferable#of(java.lang.String,int)" + ] +} diff --git a/core/src/main/java/org/testcontainers/images/builder/Transferable.java b/core/src/main/java/org/testcontainers/images/builder/Transferable.java index e98dbc2ad11..292a70d6ac7 100644 --- a/core/src/main/java/org/testcontainers/images/builder/Transferable.java +++ b/core/src/main/java/org/testcontainers/images/builder/Transferable.java @@ -16,6 +16,10 @@ static Transferable of(String string) { return of(string.getBytes(StandardCharsets.UTF_8)); } + static Transferable of(String string, int fileMode) { + return of(string.getBytes(StandardCharsets.UTF_8), fileMode); + } + static Transferable of(byte[] bytes) { return of(bytes, DEFAULT_FILE_MODE); } diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 1967ad95135..12f5810bc27 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -84,6 +84,19 @@ public void shouldCopyTransferableAsFile() { } } + @Test + public void shouldCopyTransferableAsFileWithFileMode() { + try ( + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) + .withStartupCheckStrategy(new NoopStartupCheckStrategy()) + .withCopyToContainer(Transferable.of("test", 0777), "/tmp/test") + .waitingFor(new WaitForExitedState(state -> state.getExitCodeLong() > 0)) + .withCommand("sh", "-c", "ls -ll /tmp | grep '\\-rwxrwxrwx\\|test' && exit 100") + ) { + assertThatThrownBy(container::start).hasStackTraceContaining("Container exited with code 100"); + } + } + @Test public void shouldCopyTransferableAfterMountableFile() { try ( From 8b55a3e63ae2a5dfbf4f916d7fc9f6eb008b2f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 18 Aug 2022 18:35:59 -0500 Subject: [PATCH 2149/4969] Add Redpanda module (#5740) New module uses `docker.redpanda.com/vectorized/redpanda:v22.2.1` docker image as a base giving the `--mode dev-container` flag added in that version. Co-authored-by: Sergei Egorov --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 + .github/labeler.yml | 2 + docs/modules/redpanda.md | 38 +++++ mkdocs.yml | 1 + modules/redpanda/build.gradle | 8 ++ .../redpanda/RedpandaContainer.java | 60 ++++++++ .../redpanda/RedpandaContainerTest.java | 130 ++++++++++++++++++ .../src/test/resources/logback-test.xml | 16 +++ 11 files changed, 263 insertions(+) create mode 100644 docs/modules/redpanda.md create mode 100644 modules/redpanda/build.gradle create mode 100644 modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java create mode 100644 modules/redpanda/src/test/java/org/testcontainers/redpanda/RedpandaContainerTest.java create mode 100644 modules/redpanda/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 5aca9e624b3..163c5455b1e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -42,6 +42,7 @@ body: - Presto - Pulsar - RabbitMQ + - Redpanda - Selenium - Solr - TiDB diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index ba5b1f88006..b753332073b 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -42,6 +42,7 @@ body: - Presto - Pulsar - RabbitMQ + - Redpanda - Selenium - Solr - TiDB diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 981f5613a1e..91031adfeee 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -42,6 +42,7 @@ body: - Presto - Pulsar - RabbitMQ + - Redpanda - Selenium - Solr - TiDB diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 22437e15825..4c270ef762c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -187,6 +187,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/redpanda" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/selenium" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index cf75af99d26..492991a9947 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -69,6 +69,8 @@ - modules/r2dbc/* "modules/rabbitmq": - modules/rabbitmq/* +"modules/redpanda": + - modules/redpanda/* "modules/selenium": - modules/selenium/* "modules/solr": diff --git a/docs/modules/redpanda.md b/docs/modules/redpanda.md new file mode 100644 index 00000000000..8749c9c87f5 --- /dev/null +++ b/docs/modules/redpanda.md @@ -0,0 +1,38 @@ +# Redpanda + +Testcontainers can be used to automatically instantiate and manage [Redpanda](https://redpanda.com/) containers. +More precisely Testcontainers uses the official Docker images for [Redpanda](https://hub.docker.com/r/vectorized/redpanda/) + +!!! note + This module uses features provided in `docker.redpanda.com/vectorized/redpanda`. + +## Example + +Create a `Redpanda` to use it in your tests: + +[Creating a Redpanda](../../modules/redpanda/src/test/java/org/testcontainers/redpanda/RedpandaContainerTest.java) inside_block:constructorWithVersion + + +Now your tests or any other process running on your machine can get access to running Redpanda broker by using the following bootstrap server location: + + +[Bootstrap Servers](../../modules/redpanda/src/test/java/org/testcontainers/redpanda/RedpandaContainerTest.java) inside_block:getBootstrapServers + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" +```groovy +testImplementation "org.testcontainers:redpanda:{{latest_version}}" +``` +=== "Maven" +```xml + + org.testcontainers + redpanda + {{latest_version}} + test + +``` diff --git a/mkdocs.yml b/mkdocs.yml index a836e0a2ff7..42011817a5c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -78,6 +78,7 @@ nav: - modules/nginx.md - modules/pulsar.md - modules/rabbitmq.md + - modules/redpanda.md - modules/solr.md - modules/toxiproxy.md - modules/vault.md diff --git a/modules/redpanda/build.gradle b/modules/redpanda/build.gradle new file mode 100644 index 00000000000..5750e873bf6 --- /dev/null +++ b/modules/redpanda/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: Redpanda" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.apache.kafka:kafka-clients:3.2.1' + testImplementation 'org.assertj:assertj-core:3.23.1' +} diff --git a/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java b/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java new file mode 100644 index 00000000000..cbb7db1e7c1 --- /dev/null +++ b/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java @@ -0,0 +1,60 @@ +package org.testcontainers.redpanda; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.Transferable; +import org.testcontainers.utility.ComparableVersion; +import org.testcontainers.utility.DockerImageName; + +/** + * Testcontainers implementation for Redpanda. + */ +public class RedpandaContainer extends GenericContainer { + + private static final String REDPANDA_FULL_IMAGE_NAME = "docker.redpanda.com/vectorized/redpanda"; + + private static final DockerImageName REDPANDA_IMAGE = DockerImageName.parse(REDPANDA_FULL_IMAGE_NAME); + + private static final int REDPANDA_PORT = 9092; + + private static final String STARTER_SCRIPT = "/testcontainers_start.sh"; + + public RedpandaContainer(String image) { + this(DockerImageName.parse(image)); + } + + public RedpandaContainer(DockerImageName imageName) { + super(imageName); + imageName.assertCompatibleWith(REDPANDA_IMAGE); + + boolean isLessThanBaseVersion = new ComparableVersion(imageName.getVersionPart()).isLessThan("v22.2.1"); + if (REDPANDA_FULL_IMAGE_NAME.equals(imageName.getUnversionedPart()) && isLessThanBaseVersion) { + throw new IllegalArgumentException("Redpanda version must be >= v22.2.1"); + } + + withExposedPorts(REDPANDA_PORT); + withCreateContainerCmdModifier(cmd -> { + cmd.withEntrypoint("sh"); + }); + waitingFor(Wait.forLogMessage(".*Started Kafka API server.*", 1)); + withCommand("-c", "while [ ! -f " + STARTER_SCRIPT + " ]; do sleep 0.1; done; " + STARTER_SCRIPT); + } + + @Override + protected void containerIsStarting(InspectContainerResponse containerInfo) { + super.containerIsStarting(containerInfo); + + String command = "#!/bin/bash\n"; + + command += "/usr/bin/rpk redpanda start --mode dev-container "; + command += "--kafka-addr PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 "; + command += "--advertise-kafka-addr PLAINTEXT://kafka:29092,OUTSIDE://" + getHost() + ":" + getMappedPort(9092); + + copyFileToContainer(Transferable.of(command, 0777), STARTER_SCRIPT); + } + + public String getBootstrapServers() { + return String.format("PLAINTEXT://%s:%s", getHost(), getMappedPort(REDPANDA_PORT)); + } +} diff --git a/modules/redpanda/src/test/java/org/testcontainers/redpanda/RedpandaContainerTest.java b/modules/redpanda/src/test/java/org/testcontainers/redpanda/RedpandaContainerTest.java new file mode 100644 index 00000000000..086bf43364b --- /dev/null +++ b/modules/redpanda/src/test/java/org/testcontainers/redpanda/RedpandaContainerTest.java @@ -0,0 +1,130 @@ +package org.testcontainers.redpanda; + +import com.google.common.collect.ImmutableMap; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.Test; +import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.utility.DockerImageName; + +import java.time.Duration; +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +public class RedpandaContainerTest { + + private static final String REDPANDA_IMAGE = "docker.redpanda.com/vectorized/redpanda:v22.2.1"; + + private static final DockerImageName REDPANDA_DOCKER_IMAGE = DockerImageName.parse(REDPANDA_IMAGE); + + @Test + public void testUsage() throws Exception { + try (RedpandaContainer container = new RedpandaContainer(REDPANDA_DOCKER_IMAGE)) { + container.start(); + testKafkaFunctionality(container.getBootstrapServers()); + } + } + + @Test + public void testUsageWithStringImage() throws Exception { + try ( + // constructorWithVersion { + RedpandaContainer container = new RedpandaContainer("docker.redpanda.com/vectorized/redpanda:v22.2.1") + // } + ) { + container.start(); + testKafkaFunctionality( + // getBootstrapServers { + container.getBootstrapServers() + // } + ); + } + } + + @Test + public void testNotCompatibleVersion() { + assertThatThrownBy(() -> new RedpandaContainer("docker.redpanda.com/vectorized/redpanda:v21.11.19")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Redpanda version must be >= v22.2.1"); + } + + private void testKafkaFunctionality(String bootstrapServers) throws Exception { + testKafkaFunctionality(bootstrapServers, 1, 1); + } + + private void testKafkaFunctionality(String bootstrapServers, int partitions, int rf) throws Exception { + try ( + AdminClient adminClient = AdminClient.create( + ImmutableMap.of(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers) + ); + KafkaProducer producer = new KafkaProducer<>( + ImmutableMap.of( + ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ProducerConfig.CLIENT_ID_CONFIG, + UUID.randomUUID().toString() + ), + new StringSerializer(), + new StringSerializer() + ); + KafkaConsumer consumer = new KafkaConsumer<>( + ImmutableMap.of( + ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ConsumerConfig.GROUP_ID_CONFIG, + "tc-" + UUID.randomUUID(), + ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, + "earliest" + ), + new StringDeserializer(), + new StringDeserializer() + ); + ) { + String topicName = "messages-" + UUID.randomUUID(); + + Collection topics = Collections.singletonList(new NewTopic(topicName, partitions, (short) rf)); + adminClient.createTopics(topics).all().get(30, TimeUnit.SECONDS); + + consumer.subscribe(Collections.singletonList(topicName)); + + producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); + + Unreliables.retryUntilTrue( + 10, + TimeUnit.SECONDS, + () -> { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + + if (records.isEmpty()) { + return false; + } + + assertThat(records) + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + + return true; + } + ); + + consumer.unsubscribe(); + } + } +} diff --git a/modules/redpanda/src/test/resources/logback-test.xml b/modules/redpanda/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/redpanda/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 5f486d9c5e3e6a0c8ca7a270bd1c033cf0292c23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:27 +0000 Subject: [PATCH 2150/4969] Bump postgresql from 42.4.1 to 42.4.2 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.4.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.4.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index 1fc5dac8d8a..fbd2415e53c 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.4.1' + testImplementation 'org.postgresql:postgresql:42.4.2' testImplementation 'org.assertj:assertj-core:3.23.1' } From e8f7c19278c3d12c84097c868a64bb2e969ca298 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:29 +0000 Subject: [PATCH 2151/4969] Bump postgresql from 42.4.1 to 42.4.2 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.4.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.4.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 08afd67839d..dd1d0c7ed6e 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0' - testRuntimeOnly 'org.postgresql:postgresql:42.4.1' + testRuntimeOnly 'org.postgresql:postgresql:42.4.2' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' } From ba585921f607a12b770bacbda3d6bc1be7fa0f44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:29 +0000 Subject: [PATCH 2152/4969] Bump google-cloud-pubsub from 1.120.11 to 1.120.12 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.120.11 to 1.120.12. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.120.11...v1.120.12) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index e7bc4065d82..bb79bfbbcc2 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.11.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.0' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.11' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.12' testImplementation 'com.google.cloud:google-cloud-spanner:6.28.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.3' testImplementation 'org.assertj:assertj-core:3.23.1' From 87b0a80d69b674d727b1cc216e13e3b0819e07aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:30 +0000 Subject: [PATCH 2153/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.281 to 1.12.285. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.281...1.12.285) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 81ec1f9deb5..8b548d5b91f 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.281' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.281' testImplementation 'org.assertj:assertj-core:3.23.1' } From 6c7b68c88dcb01a67f56dc9c7d701deca3b1b718 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:31 +0000 Subject: [PATCH 2154/4969] Bump trino-jdbc from 392 to 393 in /modules/trino Bumps trino-jdbc from 392 to 393. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index 09b5b8cb16c..e5b7efee873 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:392' + testImplementation 'io.trino:trino-jdbc:393' compileOnly 'org.jetbrains:annotations:23.0.0' } From 42ddd6b86bcfd1e5f54b594b22f8b13e2ac86c24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:32 +0000 Subject: [PATCH 2155/4969] Bump postgresql from 42.4.1 to 42.4.2 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.4.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.4.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index f769bf9b07c..0c5035df549 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.4.1' + testImplementation 'org.postgresql:postgresql:42.4.2' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' From c4462e6d05390988b871b9bce277b9e14733c179 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:37 +0000 Subject: [PATCH 2156/4969] Bump s3 from 2.17.253 to 2.17.256 in /modules/localstack Bumps s3 from 2.17.253 to 2.17.256. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 76090d2f6dd..23f4d045cba 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.273' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.282' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.281' - testImplementation 'software.amazon.awssdk:s3:2.17.253' + testImplementation 'software.amazon.awssdk:s3:2.17.256' testImplementation 'org.assertj:assertj-core:3.23.1' } From 23d93d52d6414a02772e3768aa6bd70671e333f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:40 +0000 Subject: [PATCH 2157/4969] Bump release-drafter/release-drafter from 5.20.0 to 5.20.1 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.20.0 to 5.20.1. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/ac463ffd9cc4c6ad5682af93dc3e3591c4657ee3...06a49bf28488e030d35ca2ac6dbf7f408a481779) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index fb0780d781f..94af563bcda 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -18,6 +18,6 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@ac463ffd9cc4c6ad5682af93dc3e3591c4657ee3 # v5.19.0 + - uses: release-drafter/release-drafter@06a49bf28488e030d35ca2ac6dbf7f408a481779 # v5.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From aa1512123425260157c313ccd4e8011a436dbc50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:41 +0000 Subject: [PATCH 2158/4969] Bump aws-java-sdk-s3 from 1.12.281 to 1.12.285 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.281 to 1.12.285. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.281...1.12.285) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 76090d2f6dd..65128d624bc 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.281' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.273' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.285' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.282' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.281' testImplementation 'software.amazon.awssdk:s3:2.17.253' From d100185f041aae612e19c11df7223d2f214f56ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:43 +0000 Subject: [PATCH 2159/4969] Bump peter-evans/create-pull-request from 4.0.4 to 4.1.1 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.0.4 to 4.1.1. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/923ad837f191474af6b1721408744feb989a4c27...18f90432bedd2afd6a825469ffd38aa24712a91d) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index b2736c42590..070fa2c55d4 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -23,7 +23,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27 # v3.10.1 + uses: peter-evans/create-pull-request@18f90432bedd2afd6a825469ffd38aa24712a91d # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From 1850fa7ca123cc7ee5e375d8867b2d80881b2b66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:36:47 +0000 Subject: [PATCH 2160/4969] Bump postgresql from 42.4.1 to 42.4.2 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.4.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.4.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 1865f70f801..5b690597eaf 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220320' - testImplementation 'org.postgresql:postgresql:42.4.1' + testImplementation 'org.postgresql:postgresql:42.4.2' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:postgresql' testImplementation 'org.assertj:assertj-core:3.23.1' From b82ae5c02cddb455d13c7525785799295b767b4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Aug 2022 02:15:39 +0000 Subject: [PATCH 2161/4969] Bump aws-java-sdk-logs from 1.12.281 to 1.12.285 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.281 to 1.12.285. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.281...1.12.285) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 6c19c73b3be..ed6f57fb6d2 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.282' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.281' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.285' testImplementation 'software.amazon.awssdk:s3:2.17.256' testImplementation 'org.assertj:assertj-core:3.23.1' } From 3bb9afa1d42e968297c285ca46f80b49f0142a9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Aug 2022 02:15:44 +0000 Subject: [PATCH 2162/4969] Bump postgresql from 42.4.1 to 42.4.2 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.4.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.4.2) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 304e0b98dc4..543824ea8f6 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.4.1' + testRuntimeOnly 'org.postgresql:postgresql:42.4.2' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testCompileClasspath 'org.jetbrains:annotations:23.0.0' From 917f451cd04f313f923682fb19ddcc7255d403ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Aug 2022 14:48:41 +0000 Subject: [PATCH 2163/4969] Bump aws-java-sdk-sqs from 1.12.282 to 1.12.285 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.282 to 1.12.285. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.282...1.12.285) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ed6f57fb6d2..ad43f6f9c08 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.282' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.285' testImplementation 'software.amazon.awssdk:s3:2.17.256' testImplementation 'org.assertj:assertj-core:3.23.1' From dcf416cdc31c59131819f73e92e382e0b5c368af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 19 Aug 2022 11:35:54 -0500 Subject: [PATCH 2164/4969] Fix type/docs label (#5759) Only consider files with `.md` extension. --- .github/labeler.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 492991a9947..85144b7d7f9 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -85,4 +85,5 @@ - modules/trino/* "modules/vault": - modules/vault/* -"type/docs": docs/**/* +"type/docs": + - docs/**/*.md From 017d937dc7d2d847f2f412ba37c3db226c4623d5 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Mon, 22 Aug 2022 16:48:59 +0200 Subject: [PATCH 2165/4969] Update GHA runner image to latest Ubuntu (#5761) `ubuntu-latest` means `ubuntu-20.04` at the time of the commit. It should always be a LTS version. --- .github/workflows/ci-docker-wormhole.yml | 2 +- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci-rootless.yml | 2 +- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/update-docs-version.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index e27e4d8d611..ace645e1bb1 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -9,7 +9,7 @@ permissions: jobs: in-docker_test: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build with Gradle diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index f23fc66e889..70917663e25 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -15,7 +15,7 @@ permissions: jobs: find_gradle_jobs: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -45,7 +45,7 @@ jobs: strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index 348cf5aaaf7..334fe69e9c4 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -9,7 +9,7 @@ permissions: jobs: test: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 288e9329824..ee1b64b6429 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - id: thundra_test_initializer uses: thundra-io/thundra-test-init-action@v1 find_gradle_jobs: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -51,7 +51,7 @@ jobs: strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 29a0b920922..fedef1c4a52 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ permissions: jobs: release: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 070fa2c55d4..443ba11788f 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -13,7 +13,7 @@ jobs: contents: write # for peter-evans/create-pull-request to create branch pull-requests: write # for peter-evans/create-pull-request to create a PR if: github.repository == 'testcontainers/testcontainers-java' - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: From d568e9d2d865f9ec530839d8957941a764825118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 23 Aug 2022 13:18:24 -0500 Subject: [PATCH 2166/4969] Add samples section (#5763) List examples provided in testcontainers by providing an specific section in the docs. Co-authored-by: Kevin Wittek --- docs/examples.md | 16 ++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 17 insertions(+) create mode 100644 docs/examples.md diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000000..abd5e410c21 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,16 @@ +# Examples + +Examples of different use cases provided by Testcontainers can be found below: + +- [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/kafka-cluster) +- [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/linked-container) +- [MongoDB](https://github.com/testcontainers/testcontainers-java/tree/master/examples/mongodb-container) +- [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/master/examples/neo4j-container) +- [Redis](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache) +- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) +- [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) +- [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/master/examples/singleton-container) +- [Solr](https://github.com/testcontainers/testcontainers-java/tree/master/examples/solr-container) +- [Spring Boot](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot) +- [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot-kotlin-redis) +- [TestNG](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache-testng) diff --git a/mkdocs.yml b/mkdocs.yml index 42011817a5c..87b19de4f0a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,6 +88,7 @@ nav: - test_framework_integration/junit_5.md - test_framework_integration/spock.md - test_framework_integration/manual_lifecycle_control.md + - Examples: examples.md - System Requirements: - supported_docker_environment/index.md - Continuous Integration: From 7044cde703809ff1d2330923cd30ceecf6845f47 Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Tue, 23 Aug 2022 23:02:11 +0200 Subject: [PATCH 2167/4969] [couchbase] only expose ports for enabled services (#4595) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changeset is a minor cleanup, but it makes sense to only actually expose the ports for the services which are enabled and not all of them all the time. Co-authored-by: Eddú Meléndez --- .../couchbase/CouchbaseContainer.java | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 4f190a5413c..8603a0b0787 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -241,22 +241,7 @@ public String getConnectionString() { protected void configure() { super.configure(); - addExposedPorts( - MGMT_PORT, - MGMT_SSL_PORT, - VIEW_PORT, - VIEW_SSL_PORT, - QUERY_PORT, - QUERY_SSL_PORT, - SEARCH_PORT, - SEARCH_SSL_PORT, - ANALYTICS_PORT, - ANALYTICS_SSL_PORT, - KV_PORT, - KV_SSL_PORT, - EVENTING_PORT, - EVENTING_SSL_PORT - ); + exposePorts(); WaitAllStrategy waitStrategy = new WaitAllStrategy(); @@ -319,6 +304,34 @@ protected void configure() { waitingFor(waitStrategy); } + /** + * Configures the exposed ports based on the enabled services. + *

+ * Note that the MGMT_PORTs are always enabled since there must always be a cluster + * manager. Also, the View engine ports are implicitly available on the same nodes + * where the KV service is enabled - it is not possible to configure them individually. + */ + private void exposePorts() { + addExposedPorts(MGMT_PORT, MGMT_SSL_PORT); + + if (enabledServices.contains(CouchbaseService.KV)) { + addExposedPorts(KV_PORT, KV_SSL_PORT); + addExposedPorts(VIEW_PORT, VIEW_SSL_PORT); + } + if (enabledServices.contains(CouchbaseService.ANALYTICS)) { + addExposedPorts(ANALYTICS_PORT, ANALYTICS_SSL_PORT); + } + if (enabledServices.contains(CouchbaseService.QUERY)) { + addExposedPorts(QUERY_PORT, QUERY_SSL_PORT); + } + if (enabledServices.contains(CouchbaseService.SEARCH)) { + addExposedPorts(SEARCH_PORT, SEARCH_SSL_PORT); + } + if (enabledServices.contains(CouchbaseService.EVENTING)) { + addExposedPorts(EVENTING_PORT, EVENTING_SSL_PORT); + } + } + @Override protected void containerIsStarting(final InspectContainerResponse containerInfo) { logger().debug("Couchbase container is starting, performing configuration."); From 62fc6a9cd3a1ab9af19d59612977968e50e9192e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 24 Aug 2022 04:20:13 -0500 Subject: [PATCH 2168/4969] Upgrade spring-boot version to 2.7.3 in examples (#5764) `driver.findElementsByTagName()` is not available anymore in 2.7.3 --- examples/selenium-container/build.gradle | 2 +- .../src/test/java/SeleniumContainerTest.java | 5 +++-- examples/spring-boot-kotlin-redis/build.gradle | 4 ++-- examples/spring-boot/build.gradle | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index dc10798a060..6183b89e1d6 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.4' + id 'org.springframework.boot' version '2.7.3' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/selenium-container/src/test/java/SeleniumContainerTest.java b/examples/selenium-container/src/test/java/SeleniumContainerTest.java index 32411b98ed9..c28c9bc54cb 100644 --- a/examples/selenium-container/src/test/java/SeleniumContainerTest.java +++ b/examples/selenium-container/src/test/java/SeleniumContainerTest.java @@ -2,12 +2,13 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.context.WebServerInitializedEvent; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; @@ -43,7 +44,7 @@ public void simplePlainSeleniumTest() { RemoteWebDriver driver = chrome.getWebDriver(); driver.get("http://host.testcontainers.internal:" + port + "/foo.html"); - List hElement = driver.findElementsByTagName("h"); + List hElement = driver.findElements(By.tagName("h")); assertThat(hElement).as("The h element is found").isNotEmpty(); } diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 383491eb32d..180d6780c8f 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.6.4" + id("org.springframework.boot") version "2.7.3" id("org.jetbrains.kotlin.jvm") version "1.7.10" id("org.jetbrains.kotlin.plugin.spring") version "1.7.10" } @@ -25,4 +25,4 @@ compileKotlin { jvmTarget = "1.8" freeCompilerArgs = ["-Xjsr305=strict"] } -} \ No newline at end of file +} diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 650b5a60d98..52a4a63386a 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.6.4' + id 'org.springframework.boot' version '2.7.3' } apply plugin: 'io.spring.dependency-management' From d5ff8c362b36a7a3e1b9ee22b0b1cecce9675f43 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 24 Aug 2022 11:55:45 +0200 Subject: [PATCH 2169/4969] Revert "Update GHA runner image to latest Ubuntu (#5761)" (#5766) This reverts commit 017d937dc7d2d847f2f412ba37c3db226c4623d5. Necessary to fix CI for the Azure module. --- .github/workflows/ci-docker-wormhole.yml | 2 +- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci-rootless.yml | 2 +- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/update-docs-version.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index ace645e1bb1..e27e4d8d611 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -9,7 +9,7 @@ permissions: jobs: in-docker_test: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 - name: Build with Gradle diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 70917663e25..f23fc66e889 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -15,7 +15,7 @@ permissions: jobs: find_gradle_jobs: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -45,7 +45,7 @@ jobs: strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index 334fe69e9c4..348cf5aaaf7 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -9,7 +9,7 @@ permissions: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 strategy: fail-fast: false matrix: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee1b64b6429..288e9329824 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - id: thundra_test_initializer uses: thundra-io/thundra-test-init-action@v1 find_gradle_jobs: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -51,7 +51,7 @@ jobs: strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fedef1c4a52..29a0b920922 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ permissions: jobs: release: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 443ba11788f..070fa2c55d4 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -13,7 +13,7 @@ jobs: contents: write # for peter-evans/create-pull-request to create branch pull-requests: write # for peter-evans/create-pull-request to create a PR if: github.repository == 'testcontainers/testcontainers-java' - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 with: From f6399608f53aece84a813386ee13d1c4360e813b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 25 Aug 2022 01:55:37 -0500 Subject: [PATCH 2170/4969] Add link to GH Discussions to Issue forms (#5767) --- .github/ISSUE_TEMPLATE/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d27b0d086e9..418d5a62fe9 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,3 +3,6 @@ contact_links: - name: Need help or have a question? url: https://slack.testcontainers.org/ about: Visit our slack channel. + - name: Have a question or want to drive a Community conversation? + url: https://github.com/testcontainers/testcontainers-java/discussions/ + about: Visit our Discussions page. From 1b961d8518339ddcfbb44081c59466260a5aec42 Mon Sep 17 00:00:00 2001 From: Aidan Do <43259657+REslim30@users.noreply.github.com> Date: Fri, 26 Aug 2022 01:43:26 +0930 Subject: [PATCH 2171/4969] Set default elasticsearch heap size to 2GB (#5684) Co-authored-by: Kevin Wittek --- .../elasticsearch/ElasticsearchContainer.java | 8 +++ .../elasticsearch-default-memory-vm.options | 2 + .../ElasticsearchContainerTest.java | 50 +++++++++++++++++++ .../resources/test-custom-memory-jvm.options | 2 + 4 files changed, 62 insertions(+) create mode 100644 modules/elasticsearch/src/main/resources/elasticsearch-default-memory-vm.options create mode 100644 modules/elasticsearch/src/test/resources/test-custom-memory-jvm.options diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index f8b9f779519..edef04e001e 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.Base58; @@ -98,6 +99,13 @@ public ElasticsearchContainer(final DockerImageName dockerImageName) { logger().info("Starting an elasticsearch container using [{}]", dockerImageName); withNetworkAliases("elasticsearch-" + Base58.randomString(6)); withEnv("discovery.type", "single-node"); + // Sets default memory of elasticsearch instance to 2GB + // Spaces are deliberate to allow user to define additional jvm options as elasticsearch resolves option files lexicographically + withClasspathResourceMapping( + "elasticsearch-default-memory-vm.options", + "/usr/share/elasticsearch/config/jvm.options.d/ elasticsearch-default-memory-vm.options", + BindMode.READ_ONLY + ); addExposedPorts(ELASTICSEARCH_DEFAULT_PORT, ELASTICSEARCH_DEFAULT_TCP_PORT); this.isAtLeastMajorVersion8 = new ComparableVersion(dockerImageName.getVersionPart()).isGreaterThanOrEqualTo("8.0.0"); diff --git a/modules/elasticsearch/src/main/resources/elasticsearch-default-memory-vm.options b/modules/elasticsearch/src/main/resources/elasticsearch-default-memory-vm.options new file mode 100644 index 00000000000..10db7b96157 --- /dev/null +++ b/modules/elasticsearch/src/main/resources/elasticsearch-default-memory-vm.options @@ -0,0 +1,2 @@ +-Xms2147483648 +-Xmx2147483648 diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 1e1e70b5d75..7ee81c82759 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -19,6 +19,7 @@ import org.junit.After; import org.junit.Test; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.BindMode; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.RemoteDockerImage; @@ -375,6 +376,46 @@ public void testElasticsearch8SecureByDefaultFailsSilentlyOnLatestImages() throw } } + @Test + public void testElasticsearchDefaultMaxHeapSize() throws Exception { + long defaultHeapSize = 2147483648L; + + try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)) { + container.start(); + assertElasticsearchContainerHasHeapSize(container, defaultHeapSize); + } + } + + @Test + public void testElasticsearchCustomMaxHeapSizeInEnvironmentVariable() throws Exception { + long customHeapSize = 1574961152; + + try ( + ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) + .withEnv("ES_JAVA_OPTS", String.format("-Xms%d -Xmx%d", customHeapSize, customHeapSize)) + ) { + container.start(); + assertElasticsearchContainerHasHeapSize(container, customHeapSize); + } + } + + @Test + public void testElasticsearchCustomMaxHeapSizeInJvmOptionsFile() throws Exception { + long customHeapSize = 1574961152; + + try ( + ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE) + .withClasspathResourceMapping( + "test-custom-memory-jvm.options", + "/usr/share/elasticsearch/config/jvm.options.d/a-user-defined-jvm.options", + BindMode.READ_ONLY + ); + ) { + container.start(); + assertElasticsearchContainerHasHeapSize(container, customHeapSize); + } + } + private void tagImage(String sourceImage, String targetImage, String targetTag) throws InterruptedException { DockerClient dockerClient = DockerClientFactory.instance().client(); dockerClient @@ -438,4 +479,13 @@ private RestClient getAnonymousClient(ElasticsearchContainer container) { return anonymousClient; } + + private void assertElasticsearchContainerHasHeapSize(ElasticsearchContainer container, long heapSizeInBytes) + throws Exception { + Response response = getClient(container).performRequest(new Request("GET", "/_nodes/_all/jvm")); + String responseBody = EntityUtils.toString(response.getEntity()); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(responseBody).contains("\"heap_init_in_bytes\":" + heapSizeInBytes); + assertThat(responseBody).contains("\"heap_max_in_bytes\":" + heapSizeInBytes); + } } diff --git a/modules/elasticsearch/src/test/resources/test-custom-memory-jvm.options b/modules/elasticsearch/src/test/resources/test-custom-memory-jvm.options new file mode 100644 index 00000000000..e3fe586284e --- /dev/null +++ b/modules/elasticsearch/src/test/resources/test-custom-memory-jvm.options @@ -0,0 +1,2 @@ +-Xms1574961152 +-Xmx1574961152 From a18cab6cea2502c8bbb1f4eb7e4b11a6e6d4749d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 26 Aug 2022 01:07:43 -0600 Subject: [PATCH 2172/4969] Add .sdkmanrc with 8.0.345-tem (#5772) `.sdkmanrc` is used by sdkman to automatically switch to the version declared in the file via env command --- .sdkmanrc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .sdkmanrc diff --git a/.sdkmanrc b/.sdkmanrc new file mode 100644 index 00000000000..95cd27dd1ad --- /dev/null +++ b/.sdkmanrc @@ -0,0 +1,3 @@ +# Enable auto-env through the sdkman_auto_env config +# Add key=value pairs of SDKs to use below +java=8.0.345-tem From bd22f1e0fbf9a165881d68f6c33e1e4813e2014f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 26 Aug 2022 09:46:51 -0600 Subject: [PATCH 2173/4969] Add compatibility with MongoDB 6 (#5771) MongoDB 6 removed `mongo` shell and `mongosh` is recommended. See [here](https://www.mongodb.com/docs/manual/release-notes/6.0-compatibility/#legacy-mongo-shell-removed) Closes #5768 --- .../org/testcontainers/containers/MongoDBContainer.java | 8 +++++++- .../testcontainers/containers/MongoDBContainerTest.java | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 81bb59fd69d..cd2294e09ac 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -5,6 +5,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; import java.io.IOException; @@ -29,6 +30,8 @@ public class MongoDBContainer extends GenericContainer { private static final String MONGODB_DATABASE_NAME_DEFAULT = "test"; + private final boolean isAtLeastVersion6; + /** * @deprecated use {@link MongoDBContainer(DockerImageName)} instead */ @@ -45,6 +48,8 @@ public MongoDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + this.isAtLeastVersion6 = new ComparableVersion(dockerImageName.getVersionPart()).isGreaterThanOrEqualTo("6.0"); + withExposedPorts(MONGODB_INTERNAL_PORT); withCommand("--replSet", "docker-rs"); waitingFor(Wait.forLogMessage("(?i).*waiting for connections.*", 1)); @@ -87,7 +92,8 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { } private String[] buildMongoEvalCommand(final String command) { - return new String[] { "mongo", "--eval", command }; + String cmd = this.isAtLeastVersion6 ? "mongosh" : "mongo"; + return new String[] { cmd, "--eval", command }; } private void checkMongoNodeExitCode(final Container.ExecResult execResult) { diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index ff6d0d6ccba..acaa6c8e5d8 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -98,4 +98,11 @@ public void shouldTestDatabaseName() { assertThat(mongoDBContainer.getReplicaSetUrl(databaseName)).endsWith(databaseName); } } + + @Test + public void supportsMongoDB_6() { + try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:6.0.1")) { + mongoDBContainer.start(); + } + } } From 84e9a66d31caddc89cd123e6aeaa175d5d946e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Sat, 27 Aug 2022 02:03:39 -0600 Subject: [PATCH 2174/4969] Exclude `org.testcontainers.shaded.*` package and upgrade deps (#5775) Add general japicmp's package exclusion. Also, shadow and test dependencies below are upgraded: * Upgrade okhttp version to 4.10.0 * Upgrade javassist version to 3.29.0-GA * Upgrade zip4j version to 2.11.1 * Upgrade kubernetes-client version to 6.0.0 --- gradle/japicmp.gradle | 3 +++ modules/azure/build.gradle | 2 +- modules/couchbase/build.gradle | 2 +- modules/hivemq/build.gradle | 4 ++-- modules/k3s/build.gradle | 2 +- .../java/org/testcontainers/k3s/Fabric8K3sContainerTest.java | 4 ++-- modules/mockserver/build.gradle | 2 +- .../containers/MockServerContainerRuleTest.java | 2 +- modules/solr/build.gradle | 2 +- 9 files changed, 13 insertions(+), 10 deletions(-) diff --git a/gradle/japicmp.gradle b/gradle/japicmp.gradle index 3c438d340f0..541736a8321 100644 --- a/gradle/japicmp.gradle +++ b/gradle/japicmp.gradle @@ -25,6 +25,9 @@ tasks.japicmp { onlyBinaryIncompatibleModified = true htmlOutputFile = file("$buildDir/reports/japi.html") + packageExcludes = [ + "org.testcontainers.shaded.*", + ] } // do not run on Windows by default // TODO investigate zip issue on Windows diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index f8a7193571e..252eb895d37 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Azure" dependencies { api project(':testcontainers') // TODO use JDK's HTTP client and/or Apache HttpClient5 - shaded 'com.squareup.okhttp3:okhttp:3.14.9' + shaded 'com.squareup.okhttp3:okhttp:4.10.0' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.azure:azure-cosmos:4.34.0' diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 6cdacbcf77a..5950aac7655 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Couchbase" dependencies { api project(':testcontainers') // TODO use JDK's HTTP client and/or Apache HttpClient5 - shaded 'com.squareup.okhttp3:okhttp:3.14.9' + shaded 'com.squareup.okhttp3:okhttp:4.10.0' testImplementation 'com.couchbase.client:java-client:3.3.3' testImplementation 'org.awaitility:awaitility:4.2.0' diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index a85288f9fbd..9595b3e66b6 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -6,10 +6,10 @@ dependencies { shaded("org.apache.commons:commons-lang3:3.12.0") shaded("commons-io:commons-io:2.11.0") - shaded("org.javassist:javassist:3.28.0-GA") + shaded("org.javassist:javassist:3.29.0-GA") shaded("org.jboss.shrinkwrap:shrinkwrap-api:1.2.6") shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") - shaded("net.lingala.zip4j:zip4j:2.10.0") + shaded("net.lingala.zip4j:zip4j:2.11.1") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") testImplementation(project(":junit-jupiter")) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 2223909f051..8c6792c42e0 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -8,7 +8,7 @@ dependencies { // Any >2.8 version here is not compatible with jackson-databind 2.8.x. shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' - testImplementation 'io.fabric8:kubernetes-client:5.12.2' + testImplementation 'io.fabric8:kubernetes-client:6.0.0' testImplementation 'io.kubernetes:client-java:16.0.0' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java index 6f9550eab2a..42b08444555 100644 --- a/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java +++ b/modules/k3s/src/test/java/org/testcontainers/k3s/Fabric8K3sContainerTest.java @@ -10,7 +10,7 @@ import io.fabric8.kubernetes.api.model.ProbeBuilder; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.DefaultKubernetesClient; -import io.fabric8.kubernetes.client.dsl.Readiable; +import io.fabric8.kubernetes.client.dsl.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.testcontainers.containers.output.Slf4jLogConsumer; @@ -55,7 +55,7 @@ public void shouldStartAndHaveListableNode() { client.pods().inNamespace("default").withName("helloworld").waitUntilReady(30, TimeUnit.SECONDS); assertThat(client.pods().inNamespace("default").withName("helloworld")) - .extracting(Readiable::isReady) + .extracting(Resource::isReady) .isEqualTo(true); } } diff --git a/modules/mockserver/build.gradle b/modules/mockserver/build.gradle index 2156ef045cd..df46295df21 100644 --- a/modules/mockserver/build.gradle +++ b/modules/mockserver/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: MockServer" dependencies { api project(':testcontainers') - testImplementation 'org.mock-server:mockserver-client-java:5.5.4' + testImplementation 'org.mock-server:mockserver-client-java:5.13.2' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java index 84d472f5e75..0e4fa102b2e 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java @@ -12,7 +12,7 @@ public class MockServerContainerRuleTest { public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse( - "jamesdbloom/mockserver:mockserver-5.5.4" + "jamesdbloom/mockserver:mockserver-5.13.2" ); // creatingProxy { diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index f8e2a99888d..72ab2997dea 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Solr" dependencies { api project(':testcontainers') // TODO use JDK's HTTP client and/or Apache HttpClient5 - shaded 'com.squareup.okhttp3:okhttp:4.9.3' + shaded 'com.squareup.okhttp3:okhttp:4.10.0' testImplementation 'org.apache.solr:solr-solrj:8.11.1' testImplementation 'org.assertj:assertj-core:3.23.1' From 42a7441f59bdaa6315af202dfe7afa7e7b579be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 29 Aug 2022 09:05:39 -0600 Subject: [PATCH 2175/4969] Run mongosh or mongo if cmd exists (#5774) Previously, the command execution relied on the image version which is different when building custom images. Instead, `mongosh` or `mongo` is executed if it is present within the PATH. --- .../containers/MongoDBContainer.java | 12 +-- .../containers/MongoDBContainerTest.java | 92 ++++++++++--------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index cd2294e09ac..ae93e4121d3 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -5,7 +5,6 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; import java.io.IOException; @@ -30,8 +29,6 @@ public class MongoDBContainer extends GenericContainer { private static final String MONGODB_DATABASE_NAME_DEFAULT = "test"; - private final boolean isAtLeastVersion6; - /** * @deprecated use {@link MongoDBContainer(DockerImageName)} instead */ @@ -48,8 +45,6 @@ public MongoDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); - this.isAtLeastVersion6 = new ComparableVersion(dockerImageName.getVersionPart()).isGreaterThanOrEqualTo("6.0"); - withExposedPorts(MONGODB_INTERNAL_PORT); withCommand("--replSet", "docker-rs"); waitingFor(Wait.forLogMessage("(?i).*waiting for connections.*", 1)); @@ -92,8 +87,11 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { } private String[] buildMongoEvalCommand(final String command) { - String cmd = this.isAtLeastVersion6 ? "mongosh" : "mongo"; - return new String[] { cmd, "--eval", command }; + return new String[] { + "sh", + "-c", + "mongosh mongo --eval \"" + command + "\" || mongo --eval \"" + command + "\"", + }; } private void checkMongoNodeExitCode(final Container.ExecResult execResult) { diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index acaa6c8e5d8..dd59420f937 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -30,56 +30,59 @@ public void shouldExecuteTransactions() { // startingMongoDBContainer { mongoDBContainer.start(); // } + executeTx(mongoDBContainer); + } + } - final String mongoRsUrl = mongoDBContainer.getReplicaSetUrl(); - assertThat(mongoRsUrl).isNotNull(); - final String connectionString = mongoDBContainer.getConnectionString(); - final MongoClient mongoSyncClientBase = MongoClients.create(connectionString); - final MongoClient mongoSyncClient = MongoClients.create(mongoRsUrl); - mongoSyncClient - .getDatabase("mydb1") - .getCollection("foo") - .withWriteConcern(WriteConcern.MAJORITY) - .insertOne(new Document("abc", 0)); - mongoSyncClient - .getDatabase("mydb2") - .getCollection("bar") - .withWriteConcern(WriteConcern.MAJORITY) - .insertOne(new Document("xyz", 0)); - mongoSyncClientBase - .getDatabase("mydb3") - .getCollection("baz") - .withWriteConcern(WriteConcern.MAJORITY) - .insertOne(new Document("def", 0)); + private void executeTx(MongoDBContainer mongoDBContainer) { + final String mongoRsUrl = mongoDBContainer.getReplicaSetUrl(); + assertThat(mongoRsUrl).isNotNull(); + final String connectionString = mongoDBContainer.getConnectionString(); + final MongoClient mongoSyncClientBase = MongoClients.create(connectionString); + final MongoClient mongoSyncClient = MongoClients.create(mongoRsUrl); + mongoSyncClient + .getDatabase("mydb1") + .getCollection("foo") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("abc", 0)); + mongoSyncClient + .getDatabase("mydb2") + .getCollection("bar") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("xyz", 0)); + mongoSyncClientBase + .getDatabase("mydb3") + .getCollection("baz") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("def", 0)); - final ClientSession clientSession = mongoSyncClient.startSession(); - final TransactionOptions txnOptions = TransactionOptions - .builder() - .readPreference(ReadPreference.primary()) - .readConcern(ReadConcern.LOCAL) - .writeConcern(WriteConcern.MAJORITY) - .build(); + final ClientSession clientSession = mongoSyncClient.startSession(); + final TransactionOptions txnOptions = TransactionOptions + .builder() + .readPreference(ReadPreference.primary()) + .readConcern(ReadConcern.LOCAL) + .writeConcern(WriteConcern.MAJORITY) + .build(); - final String trxResult = "Inserted into collections in different databases"; + final String trxResult = "Inserted into collections in different databases"; - TransactionBody txnBody = () -> { - final MongoCollection coll1 = mongoSyncClient.getDatabase("mydb1").getCollection("foo"); - final MongoCollection coll2 = mongoSyncClient.getDatabase("mydb2").getCollection("bar"); + TransactionBody txnBody = () -> { + final MongoCollection coll1 = mongoSyncClient.getDatabase("mydb1").getCollection("foo"); + final MongoCollection coll2 = mongoSyncClient.getDatabase("mydb2").getCollection("bar"); - coll1.insertOne(clientSession, new Document("abc", 1)); - coll2.insertOne(clientSession, new Document("xyz", 999)); - return trxResult; - }; + coll1.insertOne(clientSession, new Document("abc", 1)); + coll2.insertOne(clientSession, new Document("xyz", 999)); + return trxResult; + }; - try { - final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions); - assertThat(trxResultActual).isEqualTo(trxResult); - } catch (RuntimeException re) { - throw new IllegalStateException(re.getMessage(), re); - } finally { - clientSession.close(); - mongoSyncClient.close(); - } + try { + final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions); + assertThat(trxResultActual).isEqualTo(trxResult); + } catch (RuntimeException re) { + throw new IllegalStateException(re.getMessage(), re); + } finally { + clientSession.close(); + mongoSyncClient.close(); } } @@ -103,6 +106,7 @@ public void shouldTestDatabaseName() { public void supportsMongoDB_6() { try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:6.0.1")) { mongoDBContainer.start(); + executeTx(mongoDBContainer); } } } From b57cbce1ac6f35d698a0f663a61ec0096981e431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 29 Aug 2022 10:51:21 -0600 Subject: [PATCH 2176/4969] Remove `disque-job-queue` and `mongodb-container` examples (#5782) Examples should provided useful usage of technologies. In this case, `disque-job-queue` seems to provide a not up-to-date image and `mongodb-container` already provides its own module. --- docs/examples.md | 1 - examples/disque-job-queue/build.gradle | 19 ---- .../java/DisqueBackedMailSenderService.java | 73 --------------- .../src/main/java/MailApiClient.java | 11 --- .../src/main/java/MailMessage.java | 12 --- .../src/main/java/MailSenderService.java | 45 ---------- .../test/java/DisqueBackedMailSenderTest.java | 89 ------------------- .../test/java/SingleDisqueInstanceTest.java | 61 ------------- .../src/test/resources/logback-test.xml | 14 --- examples/mongodb-container/build.gradle | 13 --- .../containers/MongoDbContainer.java | 64 ------------- .../containers/MongoDbContainerTest.java | 28 ------ examples/settings.gradle | 2 - 13 files changed, 432 deletions(-) delete mode 100644 examples/disque-job-queue/build.gradle delete mode 100644 examples/disque-job-queue/src/main/java/DisqueBackedMailSenderService.java delete mode 100644 examples/disque-job-queue/src/main/java/MailApiClient.java delete mode 100644 examples/disque-job-queue/src/main/java/MailMessage.java delete mode 100644 examples/disque-job-queue/src/main/java/MailSenderService.java delete mode 100644 examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java delete mode 100644 examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java delete mode 100644 examples/disque-job-queue/src/test/resources/logback-test.xml delete mode 100644 examples/mongodb-container/build.gradle delete mode 100644 examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java delete mode 100644 examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java diff --git a/docs/examples.md b/docs/examples.md index abd5e410c21..2c6036ab2ea 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -4,7 +4,6 @@ Examples of different use cases provided by Testcontainers can be found below: - [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/kafka-cluster) - [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/linked-container) -- [MongoDB](https://github.com/testcontainers/testcontainers-java/tree/master/examples/mongodb-container) - [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/master/examples/neo4j-container) - [Redis](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache) - [Selenium](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) diff --git a/examples/disque-job-queue/build.gradle b/examples/disque-job-queue/build.gradle deleted file mode 100644 index 6c7a453c3e9..00000000000 --- a/examples/disque-job-queue/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id 'java' -} - -repositories { - mavenCentral() -} - -dependencies { - compileOnly "org.projectlombok:lombok:1.18.24" - annotationProcessor "org.projectlombok:lombok:1.18.24" - implementation 'biz.paluch.redis:spinach:0.3' - implementation 'com.google.code.gson:gson:2.9.1' - implementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' - testImplementation 'org.mockito:mockito-all:1.10.19' - testImplementation 'org.testcontainers:testcontainers' - testImplementation 'org.assertj:assertj-core:3.23.1' -} diff --git a/examples/disque-job-queue/src/main/java/DisqueBackedMailSenderService.java b/examples/disque-job-queue/src/main/java/DisqueBackedMailSenderService.java deleted file mode 100644 index d2096106500..00000000000 --- a/examples/disque-job-queue/src/main/java/DisqueBackedMailSenderService.java +++ /dev/null @@ -1,73 +0,0 @@ -import biz.paluch.spinach.DisqueClient; -import biz.paluch.spinach.api.Job; -import biz.paluch.spinach.api.sync.DisqueCommands; -import com.google.gson.Gson; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -/** - * Simple example of how a mail service can be backed by a Disque job queue. - * - * It's assumed that for actual sending (SMTP, HTTP API, etc), this service calls a {@link MailApiClient}. - * However, this can be expected to be quite unreliable, so use of Disque as a backing store helps keep track - * of sent/failed state. - */ -public class DisqueBackedMailSenderService implements MailSenderService { - - private final DisqueCommands disque; - private final Gson gson; - private final MailApiClient mailApiClient; - - public DisqueBackedMailSenderService(DisqueClient client, MailApiClient mailApiClient) { - this.mailApiClient = mailApiClient; - - // Obtain a Disque connection from DisqueClient - disque = client.connect().sync(); - - gson = new Gson(); - } - - @Override - public String enqueueMessage(MailMessage message) { - String messageAsJson = gson.toJson(message); - - // Enqueue the message as JSON, setting a TTL of 1 day (will expire off the queue if not sent by then) - String jobId = disque.addjob("mail", messageAsJson, 1, TimeUnit.DAYS); - - return jobId; - } - - @Override - public Result doScheduledSend() { - - Set succeededJobIds = new HashSet<>(); - Set failedJobIds = new HashSet<>(); - - // Wait up to 100ms for new messages to arrive on the queue - // Retrieve up to 10 messages - // (Ordinarily we'd make these configurable!) - List> jobs = disque.getjobs(100, TimeUnit.MILLISECONDS, 10, "mail"); - - for (Job job : jobs) { - String jsonBody = job.getBody(); - MailMessage message = gson.fromJson(jsonBody, MailMessage.class); - - try { - mailApiClient.send(message); - succeededJobIds.add(job.getId()); - } catch (MailApiClient.MailSendException e) { - failedJobIds.add(job.getId()); - } - } - - // For any failed messages, proactively return to the queue - disque.nack(failedJobIds.toArray(new String[failedJobIds.size()])); - // For any successful jobs, mark as completed - disque.ackjob(succeededJobIds.toArray(new String[succeededJobIds.size()])); - - return new Result(succeededJobIds.size(), failedJobIds.size()); - } -} diff --git a/examples/disque-job-queue/src/main/java/MailApiClient.java b/examples/disque-job-queue/src/main/java/MailApiClient.java deleted file mode 100644 index 61a90112f32..00000000000 --- a/examples/disque-job-queue/src/main/java/MailApiClient.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Created by rnorth on 03/01/2016. - */ -public interface MailApiClient { - - boolean send(MailMessage message) throws MailSendException; - - class MailSendException extends RuntimeException { - - } -} diff --git a/examples/disque-job-queue/src/main/java/MailMessage.java b/examples/disque-job-queue/src/main/java/MailMessage.java deleted file mode 100644 index de167199057..00000000000 --- a/examples/disque-job-queue/src/main/java/MailMessage.java +++ /dev/null @@ -1,12 +0,0 @@ -import lombok.AllArgsConstructor; -import lombok.Data; - -/** - * Created by rnorth on 03/01/2016. - */ -@Data @AllArgsConstructor -public class MailMessage { - public final String subject; - public final String recipient; - public final String body; -} diff --git a/examples/disque-job-queue/src/main/java/MailSenderService.java b/examples/disque-job-queue/src/main/java/MailSenderService.java deleted file mode 100644 index 95237bf2eec..00000000000 --- a/examples/disque-job-queue/src/main/java/MailSenderService.java +++ /dev/null @@ -1,45 +0,0 @@ -import lombok.Data; -import lombok.RequiredArgsConstructor; - -import java.util.concurrent.Callable; - -/** - * Created by rnorth on 03/01/2016. - */ -public interface MailSenderService extends Callable { - - /** - * Enqueue a message to be sent on a subsequent {@link DisqueBackedMailSenderService#doScheduledSend()} - * @param message mail message to be sent - * @return an ID for the enqueued message - */ - String enqueueMessage(MailMessage message); - - /** - * Trigger a scheduled send of mail messages. - * - * TODO: In a real implementation this could be called by a {@link java.util.concurrent.ScheduledExecutorService}, - * probably - * - * @return the result of sending queued messages. - */ - MailSenderService.Result doScheduledSend(); - - /** - * call() implementation to allow MailSenderService to be used as a Callable. Simply delegates to - * the {@link DisqueBackedMailSenderService#doScheduledSend()} method. - * - * @return the result of sending queued messages. - * @throws Exception - */ - default MailSenderService.Result call() throws Exception { - return doScheduledSend(); - } - - @Data - @RequiredArgsConstructor - class Result { - public final int successfulCount; - public final int failedCount; - } -} diff --git a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java b/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java deleted file mode 100644 index dfbab3f9e6a..00000000000 --- a/examples/disque-job-queue/src/test/java/DisqueBackedMailSenderTest.java +++ /dev/null @@ -1,89 +0,0 @@ -import biz.paluch.spinach.DisqueClient; -import biz.paluch.spinach.DisqueURI; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.utility.DockerImageName; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Created by rnorth on 03/01/2016. - */ -public class DisqueBackedMailSenderTest { - - @Rule - public GenericContainer container = new GenericContainer<>(DockerImageName.parse("richnorth/disque:1.0-rc1")) - .withExposedPorts(7711); - private DisqueClient disqueClient; - - private MailSenderService service; - private MailApiClient mockMailApiClient; - - private MailMessage dummyMessage1; - private MailMessage dummyMessage2; - private MailMessage dummyMessage3; - - @Before - public void setup() { - disqueClient = new DisqueClient(DisqueURI.create(container.getHost(), container.getMappedPort(7711))); - mockMailApiClient = mock(MailApiClient.class); - - service = new DisqueBackedMailSenderService(disqueClient, mockMailApiClient); - - dummyMessage1 = new MailMessage("Dummy Message 1", "bob@example.com", "Test body"); - dummyMessage2 = new MailMessage("Dummy Message 2", "bob@example.com", "Test body"); - dummyMessage3 = new MailMessage("Dummy Message 3", "bob@example.com", "Test body"); - } - - @Test - public void testSimpleSuccessfulSending() throws Exception { - service.enqueueMessage(dummyMessage1); - service.enqueueMessage(dummyMessage2); - service.enqueueMessage(dummyMessage3); - - when(mockMailApiClient.send(any(MailMessage.class))).thenReturn(true); - - service.doScheduledSend(); - - verify(mockMailApiClient).send(eq(dummyMessage1)); - verify(mockMailApiClient).send(eq(dummyMessage2)); - verify(mockMailApiClient).send(eq(dummyMessage3)); - } - - @Test - public void testRetryOnFailure() throws Exception { - service.enqueueMessage(dummyMessage1); - service.enqueueMessage(dummyMessage2); - service.enqueueMessage(dummyMessage3); - - when(mockMailApiClient.send(eq(dummyMessage1))).thenThrow(MailApiClient.MailSendException.class).thenReturn(true); - when(mockMailApiClient.send(eq(dummyMessage2))).thenReturn(true); - when(mockMailApiClient.send(eq(dummyMessage3))).thenReturn(true); - - MailSenderService.Result result; - - result = service.doScheduledSend(); - assertThat(result.successfulCount).as("2 messages were 'sent' successfully").isEqualTo(2); - assertThat(result.failedCount).as("1 messages failed").isEqualTo(1); - - result = service.doScheduledSend(); - assertThat(result.successfulCount).as("1 message was 'sent' successfully").isEqualTo(1); - assertThat(result.failedCount).as("0 messages failed").isZero(); - - result = service.doScheduledSend(); - assertThat(result.successfulCount).as("0 messages were 'sent' successfully").isZero(); - assertThat(result.failedCount).as("0 messages failed").isZero(); - - verify(mockMailApiClient, times(2)).send(eq(dummyMessage1)); - verify(mockMailApiClient).send(eq(dummyMessage2)); - verify(mockMailApiClient).send(eq(dummyMessage3)); - } -} diff --git a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java b/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java deleted file mode 100644 index 09830614eb0..00000000000 --- a/examples/disque-job-queue/src/test/java/SingleDisqueInstanceTest.java +++ /dev/null @@ -1,61 +0,0 @@ -import biz.paluch.spinach.DisqueClient; -import biz.paluch.spinach.DisqueURI; -import biz.paluch.spinach.api.AddJobArgs; -import biz.paluch.spinach.api.Job; -import biz.paluch.spinach.api.sync.DisqueCommands; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.utility.DockerImageName; - -import java.util.concurrent.TimeUnit; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Created by rnorth on 03/01/2016. - */ -public class SingleDisqueInstanceTest { - - @Rule - public GenericContainer container = new GenericContainer<>(DockerImageName.parse("richnorth/disque:1.0-rc1")) - .withExposedPorts(7711); - private DisqueCommands connection; - private AddJobArgs retryAfter1Second; - - @Before - public void setup() { - DisqueClient client = new DisqueClient(DisqueURI.create(container.getHost(), container.getMappedPort(7711))); - connection = client.connect().sync(); - retryAfter1Second = AddJobArgs.builder().retry(1, TimeUnit.SECONDS).build(); - } - - @Test - public void testJobStoreAndRetrieve() { - connection.addjob("main_queue", "body", 1, TimeUnit.MINUTES); - - Job job = connection.getjob("main_queue"); - - assertThat(job.getBody()).as("The retrieved job is the same as the one that was added").isEqualTo("body"); - - connection.ackjob(job.getId()); - } - - @Test - public void testFailureToAckJobBeforeTimeout() throws InterruptedException { - connection.addjob("main_queue", "body", 1, TimeUnit.MINUTES, retryAfter1Second); - - Job job = connection.getjob("main_queue"); - - assertThat(job.getBody()).as("The retrieved job is the same as the one that was added").isEqualTo("body"); - - TimeUnit.SECONDS.sleep(2); - - // The timeout specified here is how long the command will wait for a job to appear - Job job2 = connection.getjob(5, TimeUnit.SECONDS, "main_queue"); - - assertThat(job2).as("After re-getting the original job is back on the queue").isNotNull(); - assertThat(job2.getBody()).as("The retrieved job is the same as the one that was added").isEqualTo("body"); - } -} diff --git a/examples/disque-job-queue/src/test/resources/logback-test.xml b/examples/disque-job-queue/src/test/resources/logback-test.xml deleted file mode 100644 index be4ebaed2c8..00000000000 --- a/examples/disque-job-queue/src/test/resources/logback-test.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - %d{HH:mm:ss.SSS} %-5level %logger - %msg%n - - - - - - - diff --git a/examples/mongodb-container/build.gradle b/examples/mongodb-container/build.gradle deleted file mode 100644 index 1ae43055790..00000000000 --- a/examples/mongodb-container/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ -plugins { - id 'java' -} - -repositories { - mavenCentral() -} - -dependencies { - testImplementation 'org.testcontainers:testcontainers' - testImplementation 'junit:junit:4.13.2' - testCompileClasspath 'org.jetbrains:annotations:23.0.0' -} diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java deleted file mode 100644 index c4c07c1f601..00000000000 --- a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainer.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.testcontainers.containers; - -import org.jetbrains.annotations.NotNull; -import org.testcontainers.utility.DockerImageName; - - -/** - * This {@link Container} is based on the official MongoDb ({@code mongo}) image from - * DockerHub. If you need to use a custom MongoDB - * image, you can provide the full image name as well. - * - * @author Stefan Ludwig - */ -public class MongoDbContainer extends GenericContainer { - - /** - * This is the internal port on which MongoDB is running inside the container. - *

- * You can use this constant in case you want to map an explicit public port to it - * instead of the default random port. This can be done using methods like - * {@link #setPortBindings(java.util.List)}. - */ - public static final int MONGODB_PORT = 27017; - public static final String DEFAULT_IMAGE_AND_TAG = "mongo:4.0"; - - /** - * Creates a new {@link MongoDbContainer} with the {@value DEFAULT_IMAGE_AND_TAG} image. - * @deprecated use {@link MongoDbContainer(DockerImageName)} instead - */ - @Deprecated - public MongoDbContainer() { - this(DEFAULT_IMAGE_AND_TAG); - } - - /** - * Creates a new {@link MongoDbContainer} with the given {@code 'image'}. - * - * @param image the image (e.g. {@value DEFAULT_IMAGE_AND_TAG}) to use - * @deprecated use {@link MongoDbContainer(DockerImageName)} instead - */ - public MongoDbContainer(@NotNull String image) { - this(DockerImageName.parse(image)); - } - - /** - * Creates a new {@link MongoDbContainer} with the specified image. - */ - public MongoDbContainer(final DockerImageName dockerImageName) { - super(dockerImageName); - addExposedPort(MONGODB_PORT); - } - - /** - * Returns the actual public port of the internal MongoDB port ({@value MONGODB_PORT}). - * - * @return the public port of this container - * @see #getMappedPort(int) - */ - @NotNull - public Integer getPort() { - return getMappedPort(MONGODB_PORT); - } - -} diff --git a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java b/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java deleted file mode 100644 index 5581c76e675..00000000000 --- a/examples/mongodb-container/src/test/java/org/testcontainers/containers/MongoDbContainerTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.testcontainers.containers; - -import org.junit.Test; -import org.testcontainers.utility.DockerImageName; - -import java.io.IOException; -import java.net.Socket; - - -public class MongoDbContainerTest { - - @Test - public void containerStartsAndPublicPortIsAvailable() { - try (MongoDbContainer container = new MongoDbContainer(DockerImageName.parse("mongo:4.0"))) { - container.start(); - assertThatPortIsAvailable(container); - } - } - - private void assertThatPortIsAvailable(MongoDbContainer container) { - try { - new Socket(container.getHost(), container.getPort()); - } catch (IOException e) { - throw new AssertionError("The expected port " + container.getPort() + " is not available!"); - } - } - -} diff --git a/examples/settings.gradle b/examples/settings.gradle index 9ed079cd7b8..7194134350d 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -19,10 +19,8 @@ rootProject.name = 'testcontainers-examples' includeBuild '..' // explicit include to allow Dependabot to autodiscover subprojects -include 'disque-job-queue' include 'kafka-cluster' include 'linked-container' -include 'mongodb-container' include 'neo4j-container' include 'redis-backed-cache' include 'redis-backed-cache-testng' From ffb88b3d80004ad569caf080c00304584352b9db Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 31 Aug 2022 16:05:28 +0200 Subject: [PATCH 2177/4969] Fix link for Selenium examples (#5786) --- docs/examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples.md b/docs/examples.md index 2c6036ab2ea..918688d86cb 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -6,7 +6,7 @@ Examples of different use cases provided by Testcontainers can be found below: - [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/linked-container) - [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/master/examples/neo4j-container) - [Redis](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache) -- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) +- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/master/examples/selenium-container) - [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) - [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/master/examples/singleton-container) - [Solr](https://github.com/testcontainers/testcontainers-java/tree/master/examples/solr-container) From fc3d60099165c9f73689ee3269370c5347492513 Mon Sep 17 00:00:00 2001 From: Aidan Do <43259657+REslim30@users.noreply.github.com> Date: Thu, 1 Sep 2022 06:08:31 +0930 Subject: [PATCH 2178/4969] Allow `getContainerByServiceName` to receive serviceName without suffix (#5776) Fixes #5773 --- .../containers/DockerComposeContainer.java | 3 ++- .../junit/DockerComposeContainerTest.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 14124d88c28..683e9d9fdf5 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -611,7 +611,8 @@ public SELF withStartupTimeout(Duration startupTimeout) { } public Optional getContainerByServiceName(String serviceName) { - return Optional.ofNullable(serviceInstanceMap.get(serviceName)); + String serviceInstantName = getServiceInstanceName(serviceName); + return Optional.ofNullable(serviceInstanceMap.get(serviceInstantName)); } private void followLogs(String containerId, Consumer consumer) { diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java index c610fc584af..96989af90a4 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerTest.java @@ -44,6 +44,7 @@ public void testGetServicePort() { public void shouldRetrieveContainerByServiceName() { String existingServiceName = "db_1"; Optional result = environment.getContainerByServiceName(existingServiceName); + assertThat(result) .as(String.format("Container should be found by service name %s", existingServiceName)) .isPresent(); @@ -52,6 +53,19 @@ public void shouldRetrieveContainerByServiceName() { .isEqualTo(result.get().getExposedPorts()); } + @Test + public void shouldRetrieveContainerByServiceNameWithoutNumberedSuffix() { + String existingServiceName = "db"; + Optional result = environment.getContainerByServiceName(existingServiceName); + + assertThat(result) + .as(String.format("Container should be found by service name %s", existingServiceName)) + .isPresent(); + assertThat(result.get().getExposedPorts()) + .as("Mapped port for result container was wrong, perhaps wrong container was found") + .isEqualTo(Collections.singletonList(3306)); + } + @Test public void shouldReturnEmptyResultOnNoneExistingService() { String notExistingServiceName = "db_256"; From 3ef2c5177f412135d5c2410abb6bcf31619b20e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:15 +0000 Subject: [PATCH 2179/4969] Bump slf4j-api from 1.7.36 to 2.0.0 in /examples Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.36 to 2.0.0. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.36...v_2.0.0) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 5b690597eaf..46d038e4643 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { mavenCentral() } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.36' + compileOnly 'org.slf4j:slf4j-api:2.0.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220320' testImplementation 'org.postgresql:postgresql:42.4.2' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 9d0fd118f61..799f3f89925 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.36' + compileOnly 'org.slf4j:slf4j-api:2.0.0' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index c5f365b5502..1d840f11871 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:1.7.36' + compileOnly 'org.slf4j:slf4j-api:2.0.0' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 89f067d3a19..d540a8386ab 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:1.7.36' + compileOnly 'org.slf4j:slf4j-api:2.0.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:testcontainers' From b83777389a000df475bd7b033551f20659d2820b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:22 +0000 Subject: [PATCH 2180/4969] Bump postgresql from 42.4.2 to 42.5.0 in /examples Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.2 to 42.5.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.2...REL42.5.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 5b690597eaf..694261f796a 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220320' - testImplementation 'org.postgresql:postgresql:42.4.2' + testImplementation 'org.postgresql:postgresql:42.5.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:postgresql' testImplementation 'org.assertj:assertj-core:3.23.1' From 3b006da54b3f4133564cc6a71eea152320b8ef88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:24 +0000 Subject: [PATCH 2181/4969] Bump aws-java-sdk-s3 from 1.12.285 to 1.12.295 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.285 to 1.12.295. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.285...1.12.295) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ad43f6f9c08..22966424b31 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.285' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.295' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.285' From 605a769acdf745ed13bb9e8b0153b1c82f3b52d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:25 +0000 Subject: [PATCH 2182/4969] Bump slf4j-api from 1.7.36 to 2.0.0 in /core Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.36 to 2.0.0. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.36...v_2.0.0) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index aa4c6eabf22..f37a6478b88 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -61,7 +61,7 @@ configurations.all { dependencies { api 'junit:junit:4.13.2' - api 'org.slf4j:slf4j-api:1.7.36' + api 'org.slf4j:slf4j-api:2.0.0' compileOnly 'org.jetbrains:annotations:23.0.0' testCompileClasspath 'org.jetbrains:annotations:23.0.0' api 'org.apache.commons:commons-compress:1.21' From d8e674fb1ee4b351b33d3f598220a7af100c0eb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:28 +0000 Subject: [PATCH 2183/4969] Bump snakeyaml from 1.30 to 1.31 in /core Bumps [snakeyaml](https://bitbucket.org/snakeyaml/snakeyaml) from 1.30 to 1.31. - [Commits](https://bitbucket.org/snakeyaml/snakeyaml/branches/compare/snakeyaml-1.31..snakeyaml-1.30) --- updated-dependencies: - dependency-name: org.yaml:snakeyaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index aa4c6eabf22..b2f1a71f643 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -80,7 +80,7 @@ dependencies { api 'com.github.docker-java:docker-java-transport-zerodep' - shaded "org.yaml:snakeyaml:1.30" + shaded "org.yaml:snakeyaml:1.31" shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From b6a066fea2d04dcee16f2da3bd9b63dfcf19a7c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:32 +0000 Subject: [PATCH 2184/4969] Bump aws-java-sdk-logs from 1.12.285 to 1.12.295 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.285 to 1.12.295. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.285...1.12.295) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index ad43f6f9c08..2dc763c860f 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.285' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.285' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.295' testImplementation 'software.amazon.awssdk:s3:2.17.256' testImplementation 'org.assertj:assertj-core:3.23.1' } From 05da3a213d12e3aad87379264c89de725c94c7f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:43 +0000 Subject: [PATCH 2185/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.285 to 1.12.295. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.285...1.12.295) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 8b548d5b91f..ac9ff346bea 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.285' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.281' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.295' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.295' testImplementation 'org.assertj:assertj-core:3.23.1' } From 19d604067a49d6a78771008b44d86cf28f12309a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:43 +0000 Subject: [PATCH 2186/4969] Bump postgresql from 42.4.2 to 42.5.0 in /modules/postgresql Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.2 to 42.5.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.2...REL42.5.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 0c5035df549..59515ed7549 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -11,7 +11,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation project(':test-support') - testImplementation 'org.postgresql:postgresql:42.4.2' + testImplementation 'org.postgresql:postgresql:42.5.0' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' From ea3b3ad40ccc19db00580b6911110c56e7b4065c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:48 +0000 Subject: [PATCH 2187/4969] Bump r2dbc-postgresql in /modules/postgresql Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.12.RELEASE to 0.8.13.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.13.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.12.RELEASE...v0.8.13.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 0c5035df549..15a39d97766 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -7,14 +7,14 @@ dependencies { api project(':jdbc') compileOnly project(':r2dbc') - compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' + compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' testImplementation project(':jdbc-test') testImplementation project(':test-support') testImplementation 'org.postgresql:postgresql:42.4.2' testImplementation testFixtures(project(':r2dbc')) - testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE' + testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' compileOnly 'org.jetbrains:annotations:23.0.0' } From f6151a20abb84ab2c2310c7a81f1c29c908f76bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:05:49 +0000 Subject: [PATCH 2188/4969] Bump postgresql from 42.4.2 to 42.5.0 in /modules/junit-jupiter Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.2 to 42.5.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.2...REL42.5.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index dd1d0c7ed6e..5b91bd181fe 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0' - testRuntimeOnly 'org.postgresql:postgresql:42.4.2' + testRuntimeOnly 'org.postgresql:postgresql:42.5.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' } From 236cdf97d814a34814315d215079dea77aad0d78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:06:20 +0000 Subject: [PATCH 2189/4969] Bump transport from 7.17.5 to 7.17.6 in /modules/elasticsearch Bumps [transport](https://github.com/elastic/elasticsearch) from 7.17.5 to 7.17.6. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/main/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v7.17.5...v7.17.6) --- updated-dependencies: - dependency-name: org.elasticsearch.client:transport dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 0e6c5bd7b5d..8d8125eb1e1 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -3,6 +3,6 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.3.3" - testImplementation "org.elasticsearch.client:transport:7.17.5" + testImplementation "org.elasticsearch.client:transport:7.17.6" testImplementation 'org.assertj:assertj-core:3.23.1' } From 4171dd86a8b95b8e991c7415be4d9ce724dec9cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:06:41 +0000 Subject: [PATCH 2190/4969] Bump actions/cache from 3.0.7 to 3.0.8 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.7 to 3.0.8. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.7...v3.0.8) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index f23fc66e889..fe4610368aa 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -25,7 +25,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.7 + uses: actions/cache@v3.0.8 continue-on-error: true with: path: ~/.gradle/caches @@ -53,7 +53,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.7 + uses: actions/cache@v3.0.8 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 288e9329824..9d7749134ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.7 + uses: actions/cache@v3.0.8 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -59,7 +59,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.7 + uses: actions/cache@v3.0.8 continue-on-error: true with: path: ~/.gradle/caches From 6b716358bcdda694d1692d93c0b879e7920451a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:08:37 +0000 Subject: [PATCH 2191/4969] Bump r2dbc-postgresql in /modules/r2dbc Bumps [r2dbc-postgresql](https://github.com/r2dbc/r2dbc-postgresql) from 0.8.12.RELEASE to 0.8.13.RELEASE. - [Release notes](https://github.com/r2dbc/r2dbc-postgresql/releases) - [Changelog](https://github.com/pgjdbc/r2dbc-postgresql/blob/v0.8.13.RELEASE/CHANGELOG) - [Commits](https://github.com/r2dbc/r2dbc-postgresql/compare/v0.8.12.RELEASE...v0.8.13.RELEASE) --- updated-dependencies: - dependency-name: io.r2dbc:r2dbc-postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index f38803104a3..c55b71ddcb2 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -12,7 +12,7 @@ dependencies { api 'io.r2dbc:r2dbc-spi:0.8.1.RELEASE' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.12.RELEASE' + testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' testImplementation project(':postgresql') testFixturesImplementation 'io.projectreactor:reactor-core:3.4.22' From ee8c818c7ba68bf3024a47776351211b824e9e0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:08:38 +0000 Subject: [PATCH 2192/4969] Bump google-cloud-firestore from 3.4.0 to 3.4.2 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.4.0 to 3.4.2. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.4.0...v3.4.2) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index bb79bfbbcc2..6b4d90d5de1 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.11.0' - testImplementation 'com.google.cloud:google-cloud-firestore:3.4.0' + testImplementation 'com.google.cloud:google-cloud-firestore:3.4.2' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.12' testImplementation 'com.google.cloud:google-cloud-spanner:6.28.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.3' From 150b75de98f44c932d9303522ea9d5a4498f2fd0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:08:43 +0000 Subject: [PATCH 2193/4969] Bump google-cloud-spanner from 6.28.0 to 6.29.0 in /modules/gcloud Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.28.0 to 6.29.0. - [Release notes](https://github.com/googleapis/java-spanner/releases) - [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-spanner/compare/v6.28.0...v6.29.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-spanner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index bb79bfbbcc2..e0c20ca6c16 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.11.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.12' - testImplementation 'com.google.cloud:google-cloud-spanner:6.28.0' + testImplementation 'com.google.cloud:google-cloud-spanner:6.29.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.3' testImplementation 'org.assertj:assertj-core:3.23.1' } From f6ffb47903edf311a1b1aefcb501bcafb14cfe70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:08:45 +0000 Subject: [PATCH 2194/4969] Bump logback-classic from 1.2.11 to 1.4.0 in /modules/hivemq Bumps [logback-classic](https://github.com/qos-ch/logback) from 1.2.11 to 1.4.0. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.2.11...v_1.4.0) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 9595b3e66b6..477d5ac98a3 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation("com.hivemq:hivemq-extension-sdk:4.8.3") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") - testImplementation("ch.qos.logback:logback-classic:1.2.11") + testImplementation("ch.qos.logback:logback-classic:1.4.0") testImplementation 'org.assertj:assertj-core:3.23.1' testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0") } From d6f318c01c6e28e47e3ad25d858d8827e6276f29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:08:58 +0000 Subject: [PATCH 2195/4969] Bump kubernetes-client from 6.0.0 to 6.1.1 in /modules/k3s Bumps [kubernetes-client](https://github.com/fabric8io/kubernetes-client) from 6.0.0 to 6.1.1. - [Release notes](https://github.com/fabric8io/kubernetes-client/releases) - [Changelog](https://github.com/fabric8io/kubernetes-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/fabric8io/kubernetes-client/compare/v6.0.0...v6.1.1) --- updated-dependencies: - dependency-name: io.fabric8:kubernetes-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 8c6792c42e0..0778419a3e2 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -8,7 +8,7 @@ dependencies { // Any >2.8 version here is not compatible with jackson-databind 2.8.x. shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' - testImplementation 'io.fabric8:kubernetes-client:6.0.0' + testImplementation 'io.fabric8:kubernetes-client:6.1.1' testImplementation 'io.kubernetes:client-java:16.0.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From bc76fc9086812d557c0e3d700f097f43f2355fbc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:08:59 +0000 Subject: [PATCH 2196/4969] Bump trino-jdbc from 393 to 394 in /modules/trino Bumps trino-jdbc from 393 to 394. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index e5b7efee873..ca2619a8631 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:393' + testImplementation 'io.trino:trino-jdbc:394' compileOnly 'org.jetbrains:annotations:23.0.0' } From 9ef2d12be740b590a6f6a11fdfeff4e234a83fb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:09:10 +0000 Subject: [PATCH 2197/4969] Bump postgresql from 42.4.2 to 42.5.0 in /modules/cockroachdb Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.2 to 42.5.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.2...REL42.5.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index fbd2415e53c..638629ef22a 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.4.2' + testImplementation 'org.postgresql:postgresql:42.5.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From 1693da989b29deb265d58c279fc4de89b79ad7ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:09:19 +0000 Subject: [PATCH 2198/4969] Bump azure-cosmos from 4.34.0 to 4.35.1 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.34.0 to 4.35.1. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.34.0...azure-cosmos_4.35.1) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 252eb895d37..8753606874c 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:4.10.0' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'com.azure:azure-cosmos:4.34.0' + testImplementation 'com.azure:azure-cosmos:4.35.1' } From efa0a8920e6a1d07a76e0eeac0a33127fdaaad7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Sep 2022 03:13:19 +0000 Subject: [PATCH 2199/4969] Bump aws-java-sdk-sqs from 1.12.285 to 1.12.295 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.285 to 1.12.295. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.285...1.12.295) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 5f743a21160..2f727f9072a 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.295' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.285' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.295' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.295' testImplementation 'software.amazon.awssdk:s3:2.17.256' testImplementation 'org.assertj:assertj-core:3.23.1' From 4e7fc5a32949458478100284a20efa36dc9336a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Sep 2022 03:13:23 +0000 Subject: [PATCH 2200/4969] Bump s3 from 2.17.256 to 2.17.266 in /modules/localstack Bumps s3 from 2.17.256 to 2.17.266. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 5f743a21160..47d483fbc6e 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.295' - testImplementation 'software.amazon.awssdk:s3:2.17.256' + testImplementation 'software.amazon.awssdk:s3:2.17.266' testImplementation 'org.assertj:assertj-core:3.23.1' } From 2f7fe4070ffd22bb396aae1202864ce4ab449da6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Sep 2022 03:13:35 +0000 Subject: [PATCH 2201/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 8.3.3 to 8.4.1. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/main/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v8.3.3...v8.4.1) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 8d8125eb1e1..c5591d0d26a 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.3.3" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.4.1" testImplementation "org.elasticsearch.client:transport:7.17.6" testImplementation 'org.assertj:assertj-core:3.23.1' } From d047a1ca3cce7b4f8146abe0faf7d70148b017af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Sep 2022 03:13:38 +0000 Subject: [PATCH 2202/4969] Bump postgresql from 42.4.2 to 42.5.0 in /modules/spock Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.2 to 42.5.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.2...REL42.5.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 543824ea8f6..a437ff5b502 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testRuntimeOnly 'org.postgresql:postgresql:42.4.2' + testRuntimeOnly 'org.postgresql:postgresql:42.5.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' testCompileClasspath 'org.jetbrains:annotations:23.0.0' From 463c45999235b93a1f07acf0984bb630edfc2230 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Sep 2022 03:13:41 +0000 Subject: [PATCH 2203/4969] Bump google-cloud-bigtable from 2.10.3 to 2.11.1 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.10.3 to 2.11.1. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.10.3...v2.11.1) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 6028ef7e7c2..c83d92e551a 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.4.2' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.12' testImplementation 'com.google.cloud:google-cloud-spanner:6.29.0' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.3' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.11.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From caea94d6324aab22bacb522d615e5dc728ba85b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Sep 2022 03:13:42 +0000 Subject: [PATCH 2204/4969] Bump google-cloud-pubsub from 1.120.12 to 1.120.13 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.120.12 to 1.120.13. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.120.12...v1.120.13) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 6028ef7e7c2..cc8187414be 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.11.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.2' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.12' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.13' testImplementation 'com.google.cloud:google-cloud-spanner:6.29.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.10.3' testImplementation 'org.assertj:assertj-core:3.23.1' From ebc22dd2eae53691470e5e4f16b23e3267ce6332 Mon Sep 17 00:00:00 2001 From: Alex <93376818+sashashura@users.noreply.github.com> Date: Fri, 2 Sep 2022 23:39:03 +0200 Subject: [PATCH 2205/4969] Update update-gradle-wrapper.yml (#5821) --- .github/workflows/update-gradle-wrapper.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 5855e609fce..c2fe34cfe19 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -4,8 +4,13 @@ on: schedule: - cron: "0 0 * * *" +permissions: + contents: read + jobs: update-gradle-wrapper: + permissions: + pull-requests: write # for gradle-update/update-gradle-wrapper-action if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest From a01d571ee52ca935021baf2c3d8904a596b99de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 9 Sep 2022 14:08:38 +0200 Subject: [PATCH 2206/4969] docs: fix link to the bounty program (#5831) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83afa8a9ea8..93a87222781 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,4 +10,4 @@ Testcontainers is [in the GitHub Sponsors program](https://github.com/sponsors/t This repository is supported by our sponsors, meaning that issues are eligible to have a 'bounty' attached to them by sponsors. -Please see [the bounty policy page](https://testcontainers.org/bounty) if you are interested, either as a sponsor or as a contributor. \ No newline at end of file +Please see [the bounty policy page](https://www.testcontainers.org/bounty) if you are interested, either as a sponsor or as a contributor. From 0d368f72d898260fc2197564e78b2869d0400ca3 Mon Sep 17 00:00:00 2001 From: Neslihan Wittek <34006979+neslihanedes@users.noreply.github.com> Date: Sun, 11 Sep 2022 00:00:11 +0200 Subject: [PATCH 2207/4969] Fix typos on index.md (#5832) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 3a99c88a5b1..8cc789e41a1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -92,7 +92,7 @@ Using Gradle 5.0 or higher, you can add the following to the `dependencies` sect !!! warning "Shaded dependencies" Testcontainers depends on other libraries (like docker-java) for it to work. Some of them (JUnit, docker-java-{api,transport} and its transitive dependencies, JNA, visible-assertions and others) are part of our public API. - But there are also "private", implementation detail dependencies (e.g. docker-java-core, Guava, OkHttp, etc etc) that are not exposed to public API but prone to conflicts with test code/application under test code. + But there are also "private", implementation detail dependencies (e.g., docker-java-core, Guava, OkHttp, etc.) that are not exposed to public API but prone to conflicts with test code/application under test code. As such, **these libraries are 'shaded' into the core testcontainers JAR** and relocated under `org.testcontainers.shaded` to prevent class conflicts. ## Sponsors From 6e46662311591312eebd59b9d7f22cb13479018b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 13 Sep 2022 10:00:21 -0500 Subject: [PATCH 2208/4969] Improve Issue Templates (#5836) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Be explicit about searching for an existing `bug`, `feature`, `enhancement` and avoid duplications. Co-authored-by: Manuel de la Peña --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/enhancement.yaml | 2 +- .github/ISSUE_TEMPLATE/feature.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 163c5455b1e..9945297ea7a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Thanks for taking the time to fill out this bug report! + Thanks for taking the time to fill out this bug report! Before submitting a `bug`, please make sure there is no existing issue for the one you encountered. - type: dropdown id: module attributes: diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index b753332073b..6d5edab909f 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Please provide the following information + Before submitting an `enhancement`, please make sure there is no existing enhancement for the one you are requesting. If so, please provide the following information: - type: dropdown id: module attributes: diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 91031adfeee..8abeb7d2131 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Please provide the following information + Before submitting a `feature`, please make sure there is no existing feature for the one you are requesting. If so, please provide the following information: - type: dropdown id: module attributes: From 1f3a1f764f5c31a2f5715ed502b417475aacdd98 Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Wed, 14 Sep 2022 15:19:25 +0200 Subject: [PATCH 2209/4969] couchbase: allow to configure bucket replicas and default to 0. (#5840) This change allows the user to configure the number of bucket replicas and defaults it to 0 since most of the time the user ever only needs no replicas since it is a single container. Note: technically this is a behavioral change since before the number of replicas was 1 (if not defined) but this causes issues when testing transactions (as seen in #5835). Fixes #5835 --- .../couchbase/BucketDefinition.java | 30 +++++++++++++++++-- .../couchbase/CouchbaseContainer.java | 1 + 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java index ad666b4ffef..c698855927c 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/BucketDefinition.java @@ -29,10 +29,32 @@ public class BucketDefinition { private int quota = 100; + private int numReplicas = 0; + public BucketDefinition(final String name) { this.name = name; } + /** + * Allows to configure the number of replicas on a bucket (defaults to 0). + *

+ * By default the bucket is initialized with 0 replicas since only a single container is launched. Modifying + * this value can still be useful in some test scenarios (i.e. to test failures with the wrong number of replicas + * and durability requirements on operations). + *

+ * Couchbase buckets can have a maximum of three replicas configured. + * + * @param numReplicas the number of replicas to configure. + * @return this {@link BucketDefinition} for chaining purposes. + */ + public BucketDefinition withReplicas(final int numReplicas) { + if (numReplicas < 0 || numReplicas > 3) { + throw new IllegalArgumentException("The number of replicas must be between 0 and 3 (inclusive)"); + } + this.numReplicas = numReplicas; + return this; + } + /** * Enables flush for this bucket (disabled by default). * @@ -45,9 +67,9 @@ public BucketDefinition withFlushEnabled(final boolean flushEnabled) { } /** - * Sets a custom bucket quota (100MB by default). + * Sets a custom bucket quota (100MiB by default). * - * @param quota the quota to set for the bucket. + * @param quota the quota to set for the bucket in mebibytes. * @return this {@link BucketDefinition} for chaining purposes. */ public BucketDefinition withQuota(final int quota) { @@ -84,4 +106,8 @@ public boolean hasPrimaryIndex() { public int getQuota() { return quota; } + + public int getNumReplicas() { + return numReplicas; + } } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index 8603a0b0787..2817b79d71f 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -573,6 +573,7 @@ private void createBuckets() { .add("name", bucket.getName()) .add("ramQuotaMB", Integer.toString(bucket.getQuota())) .add("flushEnabled", bucket.hasFlushEnabled() ? "1" : "0") + .add("replicaNumber", Integer.toString(bucket.getNumReplicas())) .build(), true ); From 9540652fa46f10f4d4e724787aa5fdf6ca3fbea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 16 Sep 2022 09:09:48 -0500 Subject: [PATCH 2210/4969] Update localstack images in tests (#5783) `atlassian/pipelines-awscli` is deprecated and it recommends to use `amazon/aws-cli`. --- .../localstack/LocalstackContainerTest.java | 17 +++++++---------- .../localstack/LocalstackTestImages.java | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java index b879b27f0e6..d44e98723b7 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java @@ -26,7 +26,6 @@ import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; -import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.Network; @@ -153,12 +152,7 @@ public void sqsTestOverBridgeNetwork() { String fooQueueUrl = queueResult.getQueueUrl(); assertThat(fooQueueUrl) .as("Created queue has external hostname URL") - .contains( - "http://" + - DockerClientFactory.instance().dockerHostIpAddress() + - ":" + - localstack.getMappedPort(LocalStackContainer.PORT) - ); + .contains("http://" + localstack.getHost() + ":" + localstack.getMappedPort(LocalStackContainer.PORT)); sqs.sendMessage(fooQueueUrl, "test"); final long messageCount = sqs @@ -265,14 +259,17 @@ public static class WithNetwork { LocalstackTestImages.AWS_CLI_IMAGE ) .withNetwork(network) - .withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("top")) + .withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("tail")) + .withCommand(" -f /dev/null") .withEnv("AWS_ACCESS_KEY_ID", "accesskey") .withEnv("AWS_SECRET_ACCESS_KEY", "secretkey") .withEnv("AWS_REGION", "eu-west-1"); @Test public void s3TestOverDockerNetwork() throws Exception { - runAwsCliAgainstDockerNetworkContainer("s3api create-bucket --bucket foo"); + runAwsCliAgainstDockerNetworkContainer( + "s3api create-bucket --bucket foo --create-bucket-configuration LocationConstraint=eu-west-1" + ); runAwsCliAgainstDockerNetworkContainer("s3api list-buckets"); runAwsCliAgainstDockerNetworkContainer("s3 ls s3://foo"); } @@ -313,7 +310,7 @@ public void cloudWatchLogsTestOverDockerNetwork() throws Exception { private String runAwsCliAgainstDockerNetworkContainer(String command) throws Exception { final String[] commandParts = String .format( - "/usr/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", + "/usr/local/bin/aws --region eu-west-1 %s --endpoint-url http://localstack:%d --no-verify-ssl", command, LocalStackContainer.PORT ) diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java index 491394bea8a..fe39b56521a 100644 --- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java +++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackTestImages.java @@ -8,5 +8,5 @@ public interface LocalstackTestImages { DockerImageName LOCALSTACK_0_10_IMAGE = LOCALSTACK_IMAGE.withTag("0.10.7"); DockerImageName LOCALSTACK_0_11_IMAGE = LOCALSTACK_IMAGE.withTag("0.11.3"); DockerImageName LOCALSTACK_0_12_IMAGE = LOCALSTACK_IMAGE.withTag("0.12.8"); - DockerImageName AWS_CLI_IMAGE = DockerImageName.parse("atlassian/pipelines-awscli:1.16.302"); + DockerImageName AWS_CLI_IMAGE = DockerImageName.parse("amazon/aws-cli:2.7.27"); } From 9e98addab9cfe076ace39a41c8cfdf4351649756 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 16 Sep 2022 16:42:12 +0200 Subject: [PATCH 2211/4969] Update slf4j in test-support to 2.0.0 (#5848) --- test-support/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-support/build.gradle b/test-support/build.gradle index ecf9a0bc60e..2fae2344a89 100644 --- a/test-support/build.gradle +++ b/test-support/build.gradle @@ -1,5 +1,5 @@ dependencies { implementation 'junit:junit:4.13.2' - implementation 'org.slf4j:slf4j-api:1.7.30' + implementation 'org.slf4j:slf4j-api:2.0.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From 22aa85d24e91a2a380da6d96f21ca03947de9c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Sat, 17 Sep 2022 12:22:45 -0500 Subject: [PATCH 2212/4969] Remove thundra from ci.yml (#5850) Using thundra breaks the gradle cache in `master` branch. --- .github/workflows/ci.yml | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d7749134ce..e1eceab8702 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,14 +14,6 @@ env: GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} jobs: - thundra_test_initializer: - runs-on: ubuntu-latest - outputs: - thundra_agent_testrun_id: ${{ steps.thundra_test_initializer.outputs.thundra_agent_testrun_id }} - steps: - - uses: actions/checkout@v3 - - id: thundra_test_initializer - uses: thundra-io/thundra-test-init-action@v1 find_gradle_jobs: runs-on: ubuntu-18.04 outputs: @@ -47,7 +39,7 @@ jobs: echo $TASKS echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" check: - needs: [find_gradle_jobs, thundra_test_initializer] + needs: [find_gradle_jobs] strategy: fail-fast: false matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} @@ -66,16 +58,6 @@ jobs: key: ${{ runner.os }}-gradle-home-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} - name: Clear existing docker image cache run: docker image prune -af - - name: Thundra Gradle Test Instrumentation - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - uses: thundra-io/thundra-gradle-test-action@v1 - with: - apikey: ${{ secrets.THUNDRA_API_KEY }} - project_id: ${{ secrets.THUNDRA_PROJECT_ID }} - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | - ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} \ - $([[ -f $THUNDRA_GRADLE_INIT_SCRIPT_PATH ]] && echo "--init-script $THUNDRA_GRADLE_INIT_SCRIPT_PATH") - env: - THUNDRA_AGENT_TEST_RUN_ID: ${{ needs.thundra_test_initializer.outputs.thundra_agent_testrun_id }} - THUNDRA_AGENT_REPORT_REST_BASEURL: https://collector.thundra.us/v1 + ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} From 459d2f6b8915b9c0cbcd89b24825d412a6739838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 19 Sep 2022 04:55:58 -0500 Subject: [PATCH 2213/4969] Use `testCompileOnly` instead of `testCompileClasspath` (#5849) `testCompileClasspath` is deprecated. Also, removing `org.jetbrains:annotations` from `selenium` module. --- core/build.gradle | 2 +- modules/selenium/build.gradle | 1 - .../org/testcontainers/junit/BaseWebDriverContainerTest.java | 2 -- modules/spock/build.gradle | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index c9dd720e2a3..4072c25db37 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -63,7 +63,7 @@ dependencies { api 'junit:junit:4.13.2' api 'org.slf4j:slf4j-api:2.0.0' compileOnly 'org.jetbrains:annotations:23.0.0' - testCompileClasspath 'org.jetbrains:annotations:23.0.0' + testCompileOnly 'org.jetbrains:annotations:23.0.0' api 'org.apache.commons:commons-compress:1.21' api ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index 38fab63dc0a..3e5a80a2dfa 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -13,5 +13,4 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.23.1' compileOnly 'org.jetbrains:annotations:23.0.0' - testCompileClasspath 'org.jetbrains:annotations:23.0.0' } diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java index c49e24ba867..0ce20ca9800 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/BaseWebDriverContainerTest.java @@ -1,6 +1,5 @@ package org.testcontainers.junit; -import org.jetbrains.annotations.NotNull; import org.junit.ClassRule; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; @@ -51,7 +50,6 @@ protected void assertBrowserNameIs(BrowserWebDriverContainer rule, String exp assertThat(actual).as(String.format("actual browser name is %s", actual)).isEqualTo(expectedName); } - @NotNull private static RemoteWebDriver setupDriverFromRule(BrowserWebDriverContainer rule) { RemoteWebDriver driver = rule.getWebDriver(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index a437ff5b502..a13a7049e13 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -18,7 +18,7 @@ dependencies { testRuntimeOnly 'org.postgresql:postgresql:42.5.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' - testCompileClasspath 'org.jetbrains:annotations:23.0.0' + testCompileOnly 'org.jetbrains:annotations:23.0.0' } sourceJar { From de1a77ed837ab5b5a542dbd51d40e08391edb129 Mon Sep 17 00:00:00 2001 From: Neslihan Wittek <34006979+neslihanedes@users.noreply.github.com> Date: Mon, 26 Sep 2022 12:04:51 +0200 Subject: [PATCH 2214/4969] Improve consistency of Testcontainers name in docs (#5866) --- docs/contributing_docs.md | 2 +- docs/index.md | 2 +- docs/modules/databases/orientdb.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/contributing_docs.md b/docs/contributing_docs.md index f6f9304a339..2d706dfe407 100644 --- a/docs/contributing_docs.md +++ b/docs/contributing_docs.md @@ -1,6 +1,6 @@ # Contributing to documentation -The testcontainers-java documentation is a static site built with [MkDocs](https://www.mkdocs.org/). +The Testcontainers-java documentation is a static site built with [MkDocs](https://www.mkdocs.org/). We use the [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) theme, which offers a number of useful extensions to MkDocs. In addition we use a [custom plugin](https://github.com/rnorth/mkdocs-codeinclude-plugin) for inclusion of code snippets. diff --git a/docs/index.md b/docs/index.md index 8cc789e41a1..8eb4ddeb2c4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -93,7 +93,7 @@ Using Gradle 5.0 or higher, you can add the following to the `dependencies` sect Testcontainers depends on other libraries (like docker-java) for it to work. Some of them (JUnit, docker-java-{api,transport} and its transitive dependencies, JNA, visible-assertions and others) are part of our public API. But there are also "private", implementation detail dependencies (e.g., docker-java-core, Guava, OkHttp, etc.) that are not exposed to public API but prone to conflicts with test code/application under test code. - As such, **these libraries are 'shaded' into the core testcontainers JAR** and relocated under `org.testcontainers.shaded` to prevent class conflicts. + As such, **these libraries are 'shaded' into the core Testcontainers JAR** and relocated under `org.testcontainers.shaded` to prevent class conflicts. ## Sponsors diff --git a/docs/modules/databases/orientdb.md b/docs/modules/databases/orientdb.md index 4beffefa6c2..57839cd99f0 100644 --- a/docs/modules/databases/orientdb.md +++ b/docs/modules/databases/orientdb.md @@ -10,7 +10,7 @@ Note that it's based on the [official Docker image](https://hub.docker.com/_/ori ## Usage example -Declare your Testcontainer as a `@ClassRule` or `@Rule` in a JUnit 4 test or as static or member attribute of a JUnit 5 test annotated with `@Container` as you would with other Testcontainers. +Declare your Testcontainers instance as a `@ClassRule` or `@Rule` in a JUnit 4 test or as static or member attribute of a JUnit 5 test annotated with `@Container` as you would with other Testcontainers. You can call `getDbUrl()` OrientDB container and build the `ODatabaseSession` by your own, but a more useful `getSession()` method is provided. On the JVM you would most likely use the [Java driver](https://github.com/). @@ -39,7 +39,7 @@ The following example uses the JUnit 5 extension `@Testcontainers` and demonstra } ``` -You are not limited to Unit tests and can of course use an instance of the OrientDB Testcontainer in vanilla Java code as well. +You are not limited to Unit tests and can of course use an instance of the OrientDB Testcontainers implementation in vanilla Java code as well. ## Adding this module to your project dependencies From 9847d5930bb0faea9d14f606c583919d4e2d2113 Mon Sep 17 00:00:00 2001 From: Aidan Do <43259657+REslim30@users.noreply.github.com> Date: Mon, 26 Sep 2022 21:20:45 +0930 Subject: [PATCH 2215/4969] Fix: ContainerDatabaseDriver does not register Properties object (#5829) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- .../containers/JdbcDatabaseContainer.java | 24 +++++++--- .../jdbc/ContainerDatabaseDriver.java | 2 +- .../MySQLDatabaseContainerDriverTest.java | 44 +++++++++++++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLDatabaseContainerDriverTest.java diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index aa397929497..88c418e73cb 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -216,9 +216,23 @@ public Driver getJdbcDriverInstance() throws NoDriverFoundException { * @throws SQLException if there is a repeated failure to create the connection */ public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException { - final Properties info = new Properties(); - info.put("user", this.getUsername()); - info.put("password", this.getPassword()); + return createConnection(queryString, new Properties()); + } + + /** + * Creates a connection to the underlying containerized database instance. + * + * @param queryString query string parameters that should be appended to the JDBC connection URL. + * The '?' character must be included + * @param info additional properties to be passed to the JDBC driver + * @return a Connection + * @throws SQLException if there is a repeated failure to create the connection + */ + public Connection createConnection(String queryString, Properties info) + throws SQLException, NoDriverFoundException { + Properties properties = new Properties(info); + properties.put("user", this.getUsername()); + properties.put("password", this.getPassword()); final String url = constructUrlForConnection(queryString); final Driver jdbcDriverInstance = getJdbcDriverInstance(); @@ -234,10 +248,10 @@ public Connection createConnection(String queryString) throws SQLException, NoDr "Trying to create JDBC connection using {} to {} with properties: {}", jdbcDriverInstance.getClass().getName(), url, - info + properties ); - return jdbcDriverInstance.connect(url, info); + return jdbcDriverInstance.connect(url, properties); } catch (SQLException e) { lastException = e; Thread.sleep(100L); diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java index 23ed9d78b25..a3fed34f24c 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java @@ -127,7 +127,7 @@ public synchronized Connection connect(String url, final Properties info) throws /* Create a connection using the delegated driver. The container must be ready to accept connections. */ - Connection connection = container.createConnection(queryString); + Connection connection = container.createConnection(queryString, info); /* If this container has not been initialized, AND diff --git a/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLDatabaseContainerDriverTest.java b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLDatabaseContainerDriverTest.java new file mode 100644 index 00000000000..7155e49dd48 --- /dev/null +++ b/modules/mysql/src/test/java/org/testcontainers/jdbc/mysql/MySQLDatabaseContainerDriverTest.java @@ -0,0 +1,44 @@ +package org.testcontainers.jdbc.mysql; + +import org.junit.Test; +import org.testcontainers.jdbc.ContainerDatabaseDriver; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MySQLDatabaseContainerDriverTest { + + @Test + public void shouldRespectBothUrlPropertiesAndParameterProperties() throws SQLException { + ContainerDatabaseDriver driver = new ContainerDatabaseDriver(); + String url = "jdbc:tc:mysql:5.7.22://hostname/databasename?padCharsWithSpace=true"; + Properties properties = new Properties(); + properties.setProperty("maxRows", "1"); + + try (Connection connection = driver.connect(url, properties)) { + try (Statement statement = connection.createStatement()) { + statement.execute("CREATE TABLE arbitrary_table (length_5_string CHAR(5))"); + statement.execute("INSERT INTO arbitrary_table VALUES ('abc')"); + statement.execute("INSERT INTO arbitrary_table VALUES ('123')"); + + // Check that maxRows is set + try (ResultSet resultSet = statement.executeQuery("SELECT * FROM arbitrary_table")) { + resultSet.next(); + assertThat(resultSet.isFirst()).isTrue(); + assertThat(resultSet.isLast()).isTrue(); + } + + // Check that pad with chars is set + try (ResultSet resultSet = statement.executeQuery("SELECT * FROM arbitrary_table")) { + assertThat(resultSet.next()).isTrue(); + assertThat(resultSet.getString(1)).isEqualTo("abc "); + } + } + } + } +} From f54a29a48419b4fb14ef1fc024a656e918d994ae Mon Sep 17 00:00:00 2001 From: Aidan Do <43259657+REslim30@users.noreply.github.com> Date: Wed, 28 Sep 2022 19:40:08 +0930 Subject: [PATCH 2216/4969] `getLivenessCheckPortNumbers()` should return mapped port (#5734) Co-authored-by: Kevin Wittek --- .../org/testcontainers/containers/Db2Container.java | 8 ++++++-- .../org/testcontainers/junit/db2/SimpleDb2Test.java | 6 ++++++ .../containers/MSSQLServerContainer.java | 3 +-- .../junit/mssqlserver/SimpleMSSQLServerTest.java | 7 +++++++ .../org/testcontainers/containers/MySQLContainer.java | 8 ++++++-- .../testcontainers/junit/mysql/SimpleMySQLTest.java | 6 ++++++ .../org/testcontainers/containers/NginxContainer.java | 8 ++++++-- .../java/org/testcontainers/junit/SimpleNginxTest.java | 6 ++++++ .../testcontainers/containers/PostgreSQLContainer.java | 8 ++++++-- .../junit/postgresql/SimplePostgreSQLTest.java | 7 +++++++ .../org/testcontainers/containers/PrestoContainer.java | 8 ++++++-- .../testcontainers/containers/PrestoContainerTest.java | 7 +++++++ .../java/org/testcontainers/tidb/TiDBContainer.java | 8 ++++++-- .../org/testcontainers/junit/tidb/SimpleTiDBTest.java | 10 ++++++++++ .../org/testcontainers/containers/TrinoContainer.java | 8 ++++++-- .../testcontainers/containers/TrinoContainerTest.java | 6 ++++++ 16 files changed, 98 insertions(+), 16 deletions(-) diff --git a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java index 29e2ce8aa07..333a2e709c3 100644 --- a/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java +++ b/modules/db2/src/main/java/org/testcontainers/containers/Db2Container.java @@ -6,7 +6,6 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; -import java.util.HashSet; import java.util.Set; public class Db2Container extends JdbcDatabaseContainer { @@ -54,9 +53,14 @@ public Db2Container(final DockerImageName dockerImageName) { addExposedPort(DB2_PORT); } + /** + * @return the ports on which to check if the container is ready + * @deprecated use {@link #getLivenessCheckPortNumbers()} instead + */ @Override + @Deprecated protected Set getLivenessCheckPorts() { - return new HashSet<>(getMappedPort(DB2_PORT)); + return super.getLivenessCheckPorts(); } @Override diff --git a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java index 2c2c4cb2f09..ae35a8ee77c 100644 --- a/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java +++ b/modules/db2/src/test/java/org/testcontainers/junit/db2/SimpleDb2Test.java @@ -21,6 +21,7 @@ public void testSimple() throws SQLException { int resultSetInt = resultSet.getInt(1); assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + assertHasCorrectExposedAndLivenessCheckPorts(db2); } } @@ -37,4 +38,9 @@ public void testWithAdditionalUrlParamInJdbcUrl() { assertThat(jdbcUrl).contains(":sslConnection=false;"); } } + + private void assertHasCorrectExposedAndLivenessCheckPorts(Db2Container db2) { + assertThat(db2.getExposedPorts()).containsExactly(Db2Container.DB2_PORT); + assertThat(db2.getLivenessCheckPortNumbers()).containsExactly(db2.getMappedPort(Db2Container.DB2_PORT)); + } } diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java index 532316fb967..8ab3c1113a2 100644 --- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java +++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java @@ -1,6 +1,5 @@ package org.testcontainers.containers; -import com.google.common.collect.Sets; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.LicenseAcceptance; @@ -64,7 +63,7 @@ public MSSQLServerContainer(final DockerImageName dockerImageName) { @Override public Set getLivenessCheckPortNumbers() { - return Sets.newHashSet(MS_SQL_SERVER_PORT); + return super.getLivenessCheckPortNumbers(); } @Override diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java index 15edbaa2ca1..2827544cade 100644 --- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java +++ b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java @@ -25,6 +25,7 @@ public void testSimple() throws SQLException { int resultSetInt = resultSet.getInt(1); assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + assertHasCorrectExposedAndLivenessCheckPorts(mssqlServer); } } @@ -64,4 +65,10 @@ public void testSetupDatabase() throws SQLException { assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(3); } } + + private void assertHasCorrectExposedAndLivenessCheckPorts(MSSQLServerContainer mssqlServer) { + assertThat(mssqlServer.getExposedPorts()).containsExactly(MSSQLServerContainer.MS_SQL_SERVER_PORT); + assertThat(mssqlServer.getLivenessCheckPortNumbers()) + .containsExactly(mssqlServer.getMappedPort(MSSQLServerContainer.MS_SQL_SERVER_PORT)); + } } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java index 14206018954..316e709995c 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLContainer.java @@ -3,7 +3,6 @@ import org.jetbrains.annotations.NotNull; import org.testcontainers.utility.DockerImageName; -import java.util.HashSet; import java.util.Set; /** @@ -56,10 +55,15 @@ public MySQLContainer(final DockerImageName dockerImageName) { addExposedPort(MYSQL_PORT); } + /** + * @return the ports on which to check if the container is ready + * @deprecated use {@link #getLivenessCheckPortNumbers()} instead + */ @NotNull @Override + @Deprecated protected Set getLivenessCheckPorts() { - return new HashSet<>(getMappedPort(MYSQL_PORT)); + return super.getLivenessCheckPorts(); } @Override diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index 146010058ac..f60712e7123 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -57,6 +57,7 @@ public void testSimple() throws SQLException { int resultSetInt = resultSet.getInt(1); assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + assertHasCorrectExposedAndLivenessCheckPorts(mysql); } } @@ -237,4 +238,9 @@ public void testWithAdditionalUrlParamInJdbcUrl() { mysql.stop(); } } + + private void assertHasCorrectExposedAndLivenessCheckPorts(MySQLContainer mysql) { + assertThat(mysql.getExposedPorts()).containsExactly(MySQLContainer.MYSQL_PORT); + assertThat(mysql.getLivenessCheckPortNumbers()).containsExactly(mysql.getMappedPort(MySQLContainer.MYSQL_PORT)); + } } diff --git a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java index 3e7a2062fd0..b97992a5684 100644 --- a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java +++ b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java @@ -6,7 +6,6 @@ import java.net.MalformedURLException; import java.net.URL; -import java.util.Collections; import java.util.Set; /** @@ -42,10 +41,15 @@ public NginxContainer(final DockerImageName dockerImageName) { setCommand("nginx", "-g", "daemon off;"); } + /** + * @return the ports on which to check if the container is ready + * @deprecated use {@link #getLivenessCheckPortNumbers()} instead + */ @NotNull @Override + @Deprecated protected Set getLivenessCheckPorts() { - return Collections.singleton(getMappedPort(80)); + return super.getLivenessCheckPorts(); } public URL getBaseUrl(String scheme, int port) throws MalformedURLException { diff --git a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java index 24e913cf281..abfbb663207 100644 --- a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java +++ b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java @@ -58,6 +58,12 @@ public void testSimple() throws Exception { .as("An HTTP GET from the Nginx server returns the index.html from the custom content directory") .contains("Hello World!"); // } + assertHasCorrectExposedAndLivenessCheckPorts(nginx); + } + + private void assertHasCorrectExposedAndLivenessCheckPorts(NginxContainer nginxContainer) throws Exception { + assertThat(nginxContainer.getExposedPorts()).containsExactly(80); + assertThat(nginxContainer.getLivenessCheckPortNumbers()).containsExactly(nginxContainer.getMappedPort(80)); } private static String responseFromNginx(URL baseUrl) throws IOException { diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index 3b36b61ea77..d3ff65ee351 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -6,7 +6,6 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; -import java.util.Collections; import java.util.Set; /** @@ -62,10 +61,15 @@ public PostgreSQLContainer(final DockerImageName dockerImageName) { addExposedPort(POSTGRESQL_PORT); } + /** + * @return the ports on which to check if the container is ready + * @deprecated use {@link #getLivenessCheckPortNumbers()} instead + */ @NotNull @Override + @Deprecated protected Set getLivenessCheckPorts() { - return Collections.singleton(getMappedPort(POSTGRESQL_PORT)); + return super.getLivenessCheckPorts(); } @Override diff --git a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java index 2a7db242421..84beb779fa4 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java @@ -26,6 +26,7 @@ public void testSimple() throws SQLException { ResultSet resultSet = performQuery(postgres, "SELECT 1"); int resultSetInt = resultSet.getInt(1); assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + assertHasCorrectExposedAndLivenessCheckPorts(postgres); } } @@ -86,4 +87,10 @@ public void testWithAdditionalUrlParamInJdbcUrl() { assertThat(jdbcUrl).contains("charSet=UNICODE"); } } + + private void assertHasCorrectExposedAndLivenessCheckPorts(PostgreSQLContainer postgres) { + assertThat(postgres.getExposedPorts()).containsExactly(PostgreSQLContainer.POSTGRESQL_PORT); + assertThat(postgres.getLivenessCheckPortNumbers()) + .containsExactly(postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT)); + } } diff --git a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java index e73f6cc0f6b..5c89682643a 100644 --- a/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java +++ b/modules/presto/src/main/java/org/testcontainers/containers/PrestoContainer.java @@ -9,7 +9,6 @@ import java.sql.SQLException; import java.time.Duration; import java.time.temporal.ChronoUnit; -import java.util.HashSet; import java.util.Set; /** @@ -56,10 +55,15 @@ public PrestoContainer(final DockerImageName dockerImageName) { addExposedPort(PRESTO_PORT); } + /** + * @return the ports on which to check if the container is ready + * @deprecated use {@link #getLivenessCheckPortNumbers()} instead + */ @NotNull @Override + @Deprecated protected Set getLivenessCheckPorts() { - return new HashSet<>(getMappedPort(PRESTO_PORT)); + return super.getLivenessCheckPorts(); } @Override diff --git a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java index 721186807aa..0e86b587c50 100644 --- a/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java +++ b/modules/presto/src/test/java/org/testcontainers/containers/PrestoContainerTest.java @@ -32,6 +32,7 @@ public void testSimple() throws Exception { assertThat(resultSet.getString("node_version")) .as("Presto version") .isEqualTo(PrestoContainer.DEFAULT_TAG); + assertHasCorrectExposedAndLivenessCheckPorts(prestoSql); } } } @@ -149,4 +150,10 @@ public void testTcJdbcUri() throws Exception { .isEqualTo(Connection.TRANSACTION_READ_UNCOMMITTED); } } + + private void assertHasCorrectExposedAndLivenessCheckPorts(PrestoContainer prestoSql) { + assertThat(prestoSql.getExposedPorts()).containsExactly(PrestoContainer.PRESTO_PORT); + assertThat(prestoSql.getLivenessCheckPortNumbers()) + .containsExactly(prestoSql.getMappedPort(PrestoContainer.PRESTO_PORT)); + } } diff --git a/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java b/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java index f8030fd2422..c78590d8393 100644 --- a/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java +++ b/modules/tidb/src/main/java/org/testcontainers/tidb/TiDBContainer.java @@ -6,7 +6,6 @@ import org.testcontainers.utility.DockerImageName; import java.time.Duration; -import java.util.HashSet; import java.util.Set; /** @@ -51,10 +50,15 @@ public TiDBContainer(final DockerImageName dockerImageName) { ); } + /** + * @return the ports on which to check if the container is ready + * @deprecated use {@link #getLivenessCheckPortNumbers()} instead + */ @NotNull @Override + @Deprecated protected Set getLivenessCheckPorts() { - return new HashSet<>(getMappedPort(TIDB_PORT)); + return super.getLivenessCheckPorts(); } @Override diff --git a/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java b/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java index 714c9854f39..6b4429afe75 100644 --- a/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java +++ b/modules/tidb/src/test/java/org/testcontainers/junit/tidb/SimpleTiDBTest.java @@ -21,6 +21,7 @@ public void testSimple() throws SQLException { int resultSetInt = resultSet.getInt(1); assertThat(resultSetInt).isEqualTo(1); + assertHasCorrectExposedAndLivenessCheckPorts(tidb); } } @@ -51,4 +52,13 @@ public void testWithAdditionalUrlParamInJdbcUrl() { tidb.stop(); } } + + private void assertHasCorrectExposedAndLivenessCheckPorts(TiDBContainer tidb) { + Integer tidbPort = 4000; + Integer restApiPort = 10080; + + assertThat(tidb.getExposedPorts()).containsExactlyInAnyOrder(tidbPort, restApiPort); + assertThat(tidb.getLivenessCheckPortNumbers()) + .containsExactlyInAnyOrder(tidb.getMappedPort(tidbPort), tidb.getMappedPort(restApiPort)); + } } diff --git a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java index 9ed18e96d28..21171fd2c15 100644 --- a/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java +++ b/modules/trino/src/main/java/org/testcontainers/containers/TrinoContainer.java @@ -7,7 +7,6 @@ import java.sql.Connection; import java.sql.SQLException; -import java.util.HashSet; import java.util.Set; public class TrinoContainer extends JdbcDatabaseContainer { @@ -37,10 +36,15 @@ public TrinoContainer(final DockerImageName dockerImageName) { addExposedPort(TRINO_PORT); } + /** + * @return the ports on which to check if the container is ready + * @deprecated use {@link #getLivenessCheckPortNumbers()} instead + */ @NotNull @Override + @Deprecated protected Set getLivenessCheckPorts() { - return new HashSet<>(getMappedPort(TRINO_PORT)); + return super.getLivenessCheckPorts(); } @Override diff --git a/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java index a58944946f0..6ef733ca972 100644 --- a/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java +++ b/modules/trino/src/test/java/org/testcontainers/containers/TrinoContainerTest.java @@ -24,6 +24,7 @@ public void testSimple() throws Exception { assertThat(resultSet.getString("node_version")) .as("Trino version") .isEqualTo(TrinoContainer.DEFAULT_TAG); + assertContainerHasCorrectExposedAndLivenessCheckPorts(trino); } } } @@ -61,4 +62,9 @@ public void testInitScript() throws Exception { } } } + + private void assertContainerHasCorrectExposedAndLivenessCheckPorts(TrinoContainer trino) { + assertThat(trino.getExposedPorts()).containsExactly(8080); + assertThat(trino.getLivenessCheckPortNumbers()).containsExactly(trino.getMappedPort(8080)); + } } From 405ddb7e39443993f8988c4c5782727f0d0b5cc5 Mon Sep 17 00:00:00 2001 From: Dave Maughan Date: Thu, 29 Sep 2022 09:53:46 +0100 Subject: [PATCH 2217/4969] Allow Pulsar default WaitStrategy to honour startup timeout (#5674) --- .../containers/PulsarContainer.java | 22 ++++++++----------- .../containers/PulsarContainerTest.java | 9 ++++++++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 10dc35dc4c8..950149e3226 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -2,12 +2,8 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; -import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.utility.DockerImageName; -import java.util.ArrayList; -import java.util.List; - /** * This container wraps Apache Pulsar running in standalone mode */ @@ -36,6 +32,8 @@ public class PulsarContainer extends GenericContainer { @Deprecated private static final String DEFAULT_TAG = "2.10.0"; + private final WaitAllStrategy waitAllStrategy = new WaitAllStrategy(); + private boolean functionsWorkerEnabled = false; private boolean transactionsEnabled = false; @@ -60,6 +58,7 @@ public PulsarContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DockerImageName.parse("apachepulsar/pulsar")); withExposedPorts(BROKER_PORT, BROKER_HTTP_PORT); + setWaitStrategy(waitAllStrategy); } @Override @@ -98,21 +97,18 @@ protected void setupCommandAndEnv() { final String clusterName = getEnvMap().getOrDefault("PULSAR_PREFIX_clusterName", "standalone"); final String response = String.format("[\"%s\"]", clusterName); - - List waitStrategies = new ArrayList<>(); - waitStrategies.add(Wait.defaultWaitStrategy()); - waitStrategies.add( + waitAllStrategy.withStrategy( Wait.forHttp(ADMIN_CLUSTERS_ENDPOINT).forPort(BROKER_HTTP_PORT).forResponsePredicate(response::equals) ); + if (transactionsEnabled) { withEnv("PULSAR_PREFIX_transactionCoordinatorEnabled", "true"); - waitStrategies.add(Wait.forHttp(TRANSACTION_TOPIC_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT)); + waitAllStrategy.withStrategy( + Wait.forHttp(TRANSACTION_TOPIC_ENDPOINT).forStatusCode(200).forPort(BROKER_HTTP_PORT) + ); } if (functionsWorkerEnabled) { - waitStrategies.add(Wait.forLogMessage(".*Function worker service started.*", 1)); + waitAllStrategy.withStrategy(Wait.forLogMessage(".*Function worker service started.*", 1)); } - final WaitAllStrategy compoundedWaitStrategy = new WaitAllStrategy(); - waitStrategies.forEach(compoundedWaitStrategy::withStrategy); - waitingFor(compoundedWaitStrategy); } } diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index bf9f3d2201f..b054c30d0ac 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -12,6 +12,7 @@ import org.junit.Test; import org.testcontainers.utility.DockerImageName; +import java.time.Duration; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -144,6 +145,14 @@ public void testClusterFullyInitialized() throws Exception { } } + @Test + public void testStartupTimeoutIsHonored() { + try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE).withStartupTimeout(Duration.ZERO)) { + assertThatThrownBy(pulsar::start) + .hasRootCauseMessage("Precondition failed: timeout must be greater than zero"); + } + } + protected void testPulsarFunctionality(String pulsarBrokerUrl) throws Exception { try ( PulsarClient client = PulsarClient.builder().serviceUrl(pulsarBrokerUrl).build(); From 2215e219054ee034583c27f3631154d7ec1b908e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 29 Sep 2022 09:21:07 -0500 Subject: [PATCH 2218/4969] Add Testcontainers icon for JetBrains IDEs (#5870) --- .gitignore | 3 ++- .idea/icon.png | Bin 0 -> 5740 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .idea/icon.png diff --git a/.gitignore b/.gitignore index 95fc6e52000..120181d6e1e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,8 @@ dependency-reduced-pom.xml *.iml ## Directory-based project format: -.idea/ +.idea/* +!.idea/icon.png # if you remove the above rule, at least ignore the following: # User-specific stuff: diff --git a/.idea/icon.png b/.idea/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0f1d8ff443473bd28bed2d1a6a256a9cd76fd7fb GIT binary patch literal 5740 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 DUoGH2 literal 0 HcmV?d00001 From c28fbe029e843b69f9d260ae2d2a0bee01257cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 29 Sep 2022 10:16:33 -0500 Subject: [PATCH 2219/4969] Remove thundra badges --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b1c0014c236..d2fce2e9911 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Testcontainers -[![Thundra Foresight](https://thundra-assets-prod.s3.us-west-2.amazonaws.com/images/badges/thundra-foresight-badge-enabled.svg)](https://foresight.thundra.live/testRuns/5a49cc30-f063-11eb-9a03-0242ac130003) -[![Thundra Foresight Test Results](https://foresight.service.thundra.us/public/api/v1/badge/test/5a49cc30-f063-11eb-9a03-0242ac130003)](https://foresight.thundra.live/testRuns/5a49cc30-f063-11eb-9a03-0242ac130003) [![Revved up by Gradle Enterprise](https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.testcontainers.org/scans) > Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. From b6abcef31196682b48cebb26739d607ca9e39ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 29 Sep 2022 10:18:54 -0500 Subject: [PATCH 2220/4969] Update latest version in mkdocs.yml --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 87b19de4f0a..ab57aeb11d6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -108,4 +108,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.17.3 + latest_version: 1.17.4 From 08f75a5217f601439ef426b059908164a02deba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 29 Sep 2022 10:21:11 -0500 Subject: [PATCH 2221/4969] Upgrade testcontainers version to 1.17.4 in japicmp --- gradle/japicmp.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/japicmp.gradle b/gradle/japicmp.gradle index 541736a8321..6d769bf9286 100644 --- a/gradle/japicmp.gradle +++ b/gradle/japicmp.gradle @@ -3,7 +3,7 @@ configurations { } dependencies { - baseline "org.testcontainers:${project.name}:1.17.3", { + baseline "org.testcontainers:${project.name}:1.17.4", { exclude group: "*", module: "*" } } From ce003ce6c42b423823501503e77d809508c1b502 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:18 +0000 Subject: [PATCH 2222/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.295 to 1.12.313. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.295...1.12.313) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index ac9ff346bea..e9cd2111f82 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.295' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.313' testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.295' testImplementation 'org.assertj:assertj-core:3.23.1' } From d48fef2fab6f82d6707e18fbaaf591e7de606f99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:18 +0000 Subject: [PATCH 2223/4969] Bump snakeyaml from 1.31 to 1.33 in /core Bumps [snakeyaml](https://bitbucket.org/snakeyaml/snakeyaml) from 1.31 to 1.33. - [Commits](https://bitbucket.org/snakeyaml/snakeyaml/branches/compare/snakeyaml-1.33..snakeyaml-1.31) --- updated-dependencies: - dependency-name: org.yaml:snakeyaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4072c25db37..08ca6d777c5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -80,7 +80,7 @@ dependencies { api 'com.github.docker-java:docker-java-transport-zerodep' - shaded "org.yaml:snakeyaml:1.31" + shaded "org.yaml:snakeyaml:1.33" shaded 'org.glassfish.main.external:trilead-ssh2-repackaged:4.1.2' From 052b44a76179a3760b6e2ec2b0a30c17d7e22b4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:23 +0000 Subject: [PATCH 2224/4969] Bump java-driver-core from 4.14.1 to 4.15.0 in /modules/cassandra Bumps [java-driver-core](https://github.com/datastax/java-driver) from 4.14.1 to 4.15.0. - [Release notes](https://github.com/datastax/java-driver/releases) - [Commits](https://github.com/datastax/java-driver/compare/4.14.1...4.15.0) --- updated-dependencies: - dependency-name: com.datastax.oss:java-driver-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/cassandra/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cassandra/build.gradle b/modules/cassandra/build.gradle index ff110637ced..ae115c92a71 100644 --- a/modules/cassandra/build.gradle +++ b/modules/cassandra/build.gradle @@ -10,6 +10,6 @@ dependencies { api project(":database-commons") api "com.datastax.cassandra:cassandra-driver-core:3.10.0" - testImplementation 'com.datastax.oss:java-driver-core:4.14.1' + testImplementation 'com.datastax.oss:java-driver-core:4.15.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From dcf8df081a3077d3300dfdd2f7998e6b6de52e11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:27 +0000 Subject: [PATCH 2225/4969] Bump junit-jupiter-params from 5.9.0 to 5.9.1 in /modules/junit-jupiter Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5b91bd181fe..0ef2ef20ab7 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -13,7 +13,7 @@ dependencies { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1' testRuntimeOnly 'org.postgresql:postgresql:42.5.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' From d1220f453d1350488e65868a266f817980128f96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:35 +0000 Subject: [PATCH 2226/4969] Bump mockito-core from 4.7.0 to 4.8.0 in /modules/junit-jupiter Bumps [mockito-core](https://github.com/mockito/mockito) from 4.7.0 to 4.8.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.7.0...v4.8.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5b91bd181fe..085ad9f1893 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -9,7 +9,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'redis.clients:jedis:4.2.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' - testImplementation ('org.mockito:mockito-core:4.7.0') { + testImplementation ('org.mockito:mockito-core:4.8.0') { exclude(module: 'hamcrest-core') } testImplementation 'org.assertj:assertj-core:3.23.1' From 4c6a67dd0a6858d3c6985350f140e007201a7069 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:37 +0000 Subject: [PATCH 2227/4969] Bump release-drafter/release-drafter from 5.20.1 to 5.21.0 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.20.1 to 5.21.0. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/06a49bf28488e030d35ca2ac6dbf7f408a481779...df69d584deac33d8569990cb6413f82447181076) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 94af563bcda..9315b7c342f 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -18,6 +18,6 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@06a49bf28488e030d35ca2ac6dbf7f408a481779 # v5.19.0 + - uses: release-drafter/release-drafter@df69d584deac33d8569990cb6413f82447181076 # v5.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From c8d841668bcbb2f8aaae2574a69ee20e699008c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:38 +0000 Subject: [PATCH 2228/4969] Bump mockito-core from 4.7.0 to 4.8.0 in /core Bumps [mockito-core](https://github.com/mockito/mockito) from 4.7.0 to 4.8.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.7.0...v4.8.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4072c25db37..ed85a732f24 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -91,7 +91,7 @@ dependencies { testImplementation 'com.rabbitmq:amqp-client:5.15.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.11' - testImplementation ('org.mockito:mockito-core:4.7.0') { + testImplementation ('org.mockito:mockito-core:4.8.0') { exclude(module: 'hamcrest-core') } // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest From 05862eb6321a3bc8bf7ae690106eb5c996cc54df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:39 +0000 Subject: [PATCH 2229/4969] Bump aws-java-sdk-s3 from 1.12.295 to 1.12.313 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.295 to 1.12.313. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.295...1.12.313) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 2b38b50f162..58be6dceae6 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,8 +3,8 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.295' - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.313' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.313' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.295' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.295' testImplementation 'software.amazon.awssdk:s3:2.17.266' From 5ecb572ee3c058d6a4c3253ec80832b32149b6ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:40 +0000 Subject: [PATCH 2230/4969] Bump junit-jupiter-engine from 5.9.0 to 5.9.1 in /modules/junit-jupiter Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5b91bd181fe..e7456adc1e3 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -17,7 +17,7 @@ dependencies { testRuntimeOnly 'org.postgresql:postgresql:42.5.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.1' } test { From 5f4fbf85c585ea828adb8576740852defa9f858c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:42 +0000 Subject: [PATCH 2231/4969] Bump peter-evans/create-pull-request from 4.1.1 to 4.1.3 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.1.1 to 4.1.3. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/18f90432bedd2afd6a825469ffd38aa24712a91d...671dc9c9e0c2d73f07fa45a3eb0220e1622f0c5f) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 070fa2c55d4..983f872c4f8 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -23,7 +23,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@18f90432bedd2afd6a825469ffd38aa24712a91d # v3.10.1 + uses: peter-evans/create-pull-request@671dc9c9e0c2d73f07fa45a3eb0220e1622f0c5f # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From 912b017d04fc4c4204850dffd5b0d53225cd7063 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:43 +0000 Subject: [PATCH 2232/4969] Bump amqp-client from 5.15.0 to 5.16.0 in /core Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.15.0 to 5.16.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.15.0...v5.16.0) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4072c25db37..c9f849a9265 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -88,7 +88,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' testImplementation 'redis.clients:jedis:4.2.3' - testImplementation 'com.rabbitmq:amqp-client:5.15.0' + testImplementation 'com.rabbitmq:amqp-client:5.16.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.11' testImplementation ('org.mockito:mockito-core:4.7.0') { From 81619973fc9a66d98a0198d90158506905864efc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:46 +0000 Subject: [PATCH 2233/4969] Bump junit-jupiter-api from 5.9.0 to 5.9.1 in /modules/junit-jupiter Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 5b91bd181fe..575e367512c 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -2,7 +2,7 @@ description = "Testcontainers :: JUnit Jupiter Extension" dependencies { api project(':testcontainers') - api 'org.junit.jupiter:junit-jupiter-api:5.9.0' + api 'org.junit.jupiter:junit-jupiter-api:5.9.1' testImplementation project(':mysql') testImplementation project(':postgresql') From 785c08e6cba914d8092c8e00edf883e9ed390b76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:48 +0000 Subject: [PATCH 2234/4969] Bump java-client from 3.3.3 to 3.3.4 in /modules/couchbase Bumps [java-client](https://github.com/couchbase/couchbase-jvm-clients) from 3.3.3 to 3.3.4. - [Release notes](https://github.com/couchbase/couchbase-jvm-clients/releases) - [Commits](https://github.com/couchbase/couchbase-jvm-clients/compare/java-client-3.3.3...java-client-3.3.4) --- updated-dependencies: - dependency-name: com.couchbase.client:java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/couchbase/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 5950aac7655..0542a5d68d0 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -5,7 +5,7 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:4.10.0' - testImplementation 'com.couchbase.client:java-client:3.3.3' + testImplementation 'com.couchbase.client:java-client:3.3.4' testImplementation 'org.awaitility:awaitility:4.2.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From aea8f74fee1b1da6f2a01f17741f8a7729f941ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:52 +0000 Subject: [PATCH 2235/4969] Bump tomcat-jdbc from 10.0.23 to 10.1.0 in /modules/jdbc Bumps tomcat-jdbc from 10.0.23 to 10.1.0. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index ba0f845b47d..14c4a431d00 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.23' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.1.0' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation ('org.mockito:mockito-core:4.7.0') { From fa7a2c3536a3006e86245bb3dc82a6d1a39f38df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:55 +0000 Subject: [PATCH 2236/4969] Bump aws-java-sdk-logs from 1.12.295 to 1.12.313 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.295 to 1.12.313. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.295...1.12.313) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 2b38b50f162..8ec3a442bc4 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.295' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.285' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.295' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.295' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.313' testImplementation 'software.amazon.awssdk:s3:2.17.266' testImplementation 'org.assertj:assertj-core:3.23.1' } From fcd3f607bd3e2d0c07da6ef83d4d1687da93028d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:06:58 +0000 Subject: [PATCH 2237/4969] Bump common-custom-user-data-gradle-plugin in /examples Bumps common-custom-user-data-gradle-plugin from 1.8 to 1.8.1. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/settings.gradle b/examples/settings.gradle index 7194134350d..a4e4bddd880 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -7,7 +7,7 @@ buildscript { dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.1" } } From 92f072f3dea0790aebb5273429e9c7be31d1f10d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:02 +0000 Subject: [PATCH 2238/4969] Bump mockito-core from 4.7.0 to 4.8.0 in /modules/jdbc Bumps [mockito-core](https://github.com/mockito/mockito) from 4.7.0 to 4.8.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.7.0...v4.8.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index ba0f845b47d..bf590c08748 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -10,7 +10,7 @@ dependencies { testImplementation 'org.apache.tomcat:tomcat-jdbc:10.0.23' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation ('org.mockito:mockito-core:4.7.0') { + testImplementation ('org.mockito:mockito-core:4.8.0') { exclude(module: 'hamcrest-core') } } From 502a2abf5808e4d102538146c8415dfcf64d9948 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:02 +0000 Subject: [PATCH 2239/4969] Bump trino-jdbc from 394 to 398 in /modules/trino Bumps trino-jdbc from 394 to 398. --- updated-dependencies: - dependency-name: io.trino:trino-jdbc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- modules/trino/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index ca2619a8631..c534f14bd2a 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:394' + testImplementation 'io.trino:trino-jdbc:398' compileOnly 'org.jetbrains:annotations:23.0.0' } From 9f2e2c14c6f7a8cf47e8ac73a0f3b2a40ed62d37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:14 +0000 Subject: [PATCH 2240/4969] Bump google-cloud-pubsub from 1.120.13 to 1.120.18 in /modules/gcloud Bumps [google-cloud-pubsub](https://github.com/googleapis/java-pubsub) from 1.120.13 to 1.120.18. - [Release notes](https://github.com/googleapis/java-pubsub/releases) - [Changelog](https://github.com/googleapis/java-pubsub/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-pubsub/compare/v1.120.13...v1.120.18) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-pubsub dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 044d82cbb21..aa0b151f6f8 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.11.0' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.2' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.13' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.18' testImplementation 'com.google.cloud:google-cloud-spanner:6.29.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.11.1' testImplementation 'org.assertj:assertj-core:3.23.1' From 826657c84ff24b3a8a15ee5bd65fd1bd2a179fee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:16 +0000 Subject: [PATCH 2241/4969] Bump mssql-jdbc from 11.2.0.jre8 to 11.2.1.jre8 in /modules/mssqlserver Bumps [mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 11.2.0.jre8 to 11.2.1.jre8. - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) --- updated-dependencies: - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mssqlserver/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mssqlserver/build.gradle b/modules/mssqlserver/build.gradle index cc05b6ffea4..ef91edc79d1 100644 --- a/modules/mssqlserver/build.gradle +++ b/modules/mssqlserver/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-mssql:0.9.0.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.2.0.jre8' + testImplementation 'com.microsoft.sqlserver:mssql-jdbc:11.2.1.jre8' testImplementation project(':r2dbc') testImplementation 'io.r2dbc:r2dbc-mssql:0.8.7.RELEASE' From 6f8c1a536c2f1f3b4242b75d2c590870ccf005f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:20 +0000 Subject: [PATCH 2242/4969] Bump mariadb-java-client from 3.0.7 to 3.0.8 in /modules/mariadb Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 3.0.7 to 3.0.8. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.0.7...3.0.8) --- updated-dependencies: - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mariadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index 1a11f0fbfb6..b4b3b3b4415 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:1.0.3' testImplementation project(':jdbc-test') - testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.7' + testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.0.8' testImplementation testFixtures(project(':r2dbc')) testImplementation 'org.mariadb:r2dbc-mariadb:1.0.2' From 50c03510cb4e11ad398c726437e0dee26cc2e3b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:23 +0000 Subject: [PATCH 2243/4969] Bump google-cloud-datastore from 2.11.0 to 2.11.4 in /modules/gcloud Bumps [google-cloud-datastore](https://github.com/googleapis/java-datastore) from 2.11.0 to 2.11.4. - [Release notes](https://github.com/googleapis/java-datastore/releases) - [Changelog](https://github.com/googleapis/java-datastore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-datastore/compare/v2.11.0...v2.11.4) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-datastore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 044d82cbb21..2758d755c56 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:2.11.0' + testImplementation 'com.google.cloud:google-cloud-datastore:2.11.4' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.2' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.13' testImplementation 'com.google.cloud:google-cloud-spanner:6.29.0' From 00f10e3d1388819a792efb0fc218ca40015ce6df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:25 +0000 Subject: [PATCH 2244/4969] Bump azure-cosmos from 4.35.1 to 4.36.0 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.35.1 to 4.36.0. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.35.1...azure-cosmos_4.36.0) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 8753606874c..43280db4a88 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:4.10.0' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'com.azure:azure-cosmos:4.35.1' + testImplementation 'com.azure:azure-cosmos:4.36.0' } From 54493fb3c9fe995682890c05997d8b831335678b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:31 +0000 Subject: [PATCH 2245/4969] Bump reactor-core from 3.4.22 to 3.4.23 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.22 to 3.4.23. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.22...v3.4.23) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index c55b71ddcb2..9126ff0a347 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.22' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.23' testFixturesImplementation 'org.assertj:assertj-core:3.23.1' } From 569ae4c8112b2c95ef7dab82e6f5db6c763bb51b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:32 +0000 Subject: [PATCH 2246/4969] Bump amqp-client from 5.15.0 to 5.16.0 in /modules/rabbitmq Bumps [amqp-client](https://github.com/rabbitmq/rabbitmq-java-client) from 5.15.0 to 5.16.0. - [Release notes](https://github.com/rabbitmq/rabbitmq-java-client/releases) - [Commits](https://github.com/rabbitmq/rabbitmq-java-client/compare/v5.15.0...v5.16.0) --- updated-dependencies: - dependency-name: com.rabbitmq:amqp-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/rabbitmq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 9825a27a499..6cf03d4f984 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: RabbitMQ" dependencies { api project(":testcontainers") - testImplementation 'com.rabbitmq:amqp-client:5.15.0' + testImplementation 'com.rabbitmq:amqp-client:5.16.0' testImplementation 'org.assertj:assertj-core:3.23.1' compileOnly 'org.jetbrains:annotations:23.0.0' } From 73596740f3ece5f93af4f1b3e8a2f9e24595f227 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:35 +0000 Subject: [PATCH 2247/4969] Bump elasticsearch-rest-client in /modules/elasticsearch Bumps [elasticsearch-rest-client](https://github.com/elastic/elasticsearch) from 8.4.1 to 8.4.2. - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/main/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v8.4.1...v8.4.2) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/elasticsearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index c5591d0d26a..04521b974ea 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.4.1" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.4.2" testImplementation "org.elasticsearch.client:transport:7.17.6" testImplementation 'org.assertj:assertj-core:3.23.1' } From 25af50d16d32e66a4c05299610a23077905828cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:35 +0000 Subject: [PATCH 2248/4969] Bump kafka-clients from 3.2.1 to 3.3.0 in /modules/redpanda Bumps kafka-clients from 3.2.1 to 3.3.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/redpanda/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/redpanda/build.gradle b/modules/redpanda/build.gradle index 5750e873bf6..4d7221711a3 100644 --- a/modules/redpanda/build.gradle +++ b/modules/redpanda/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Redpanda" dependencies { api project(':testcontainers') - testImplementation 'org.apache.kafka:kafka-clients:3.2.1' + testImplementation 'org.apache.kafka:kafka-clients:3.3.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From 9af2f2282caf9f57bfdb1e582405889782097c78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:39 +0000 Subject: [PATCH 2249/4969] Bump common-custom-user-data-gradle-plugin from 1.8 to 1.8.1 Bumps common-custom-user-data-gradle-plugin from 1.8 to 1.8.1. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 2beb91dea01..f0c1d306671 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.11.1" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.1" } } From ea4053bfa065616be0c2c84276279bd60fd16b77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:43 +0000 Subject: [PATCH 2250/4969] Bump rest-assured from 5.1.1 to 5.2.0 in /modules/consul Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 5.1.1 to 5.2.0. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-5.1.1...rest-assured-5.2.0) --- updated-dependencies: - dependency-name: io.rest-assured:rest-assured dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/consul/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/consul/build.gradle b/modules/consul/build.gradle index acb97a47927..a72aefaab5f 100644 --- a/modules/consul/build.gradle +++ b/modules/consul/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':testcontainers') testImplementation 'com.ecwid.consul:consul-api:1.4.5' - testImplementation 'io.rest-assured:rest-assured:5.1.1' + testImplementation 'io.rest-assured:rest-assured:5.2.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From 80ced857e13cad960b7c781f3b1dd70cb54332aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:45 +0000 Subject: [PATCH 2251/4969] Bump rest-assured from 5.1.1 to 5.2.0 in /modules/vault Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 5.1.1 to 5.2.0. - [Release notes](https://github.com/rest-assured/rest-assured/releases) - [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt) - [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-5.1.1...rest-assured-5.2.0) --- updated-dependencies: - dependency-name: io.rest-assured:rest-assured dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/vault/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/build.gradle b/modules/vault/build.gradle index 499286ae72a..c9142936b63 100644 --- a/modules/vault/build.gradle +++ b/modules/vault/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.bettercloud:vault-java-driver:5.1.0' - testImplementation 'io.rest-assured:rest-assured:5.1.1' + testImplementation 'io.rest-assured:rest-assured:5.2.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From 29b18d150c2c9f98fb15ec5a38a32f3b4b989833 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:52 +0000 Subject: [PATCH 2252/4969] Bump logback-classic from 1.4.0 to 1.4.1 in /modules/hivemq Bumps [logback-classic](https://github.com/qos-ch/logback) from 1.4.0 to 1.4.1. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.0...v_1.4.1) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 477d5ac98a3..0520440828f 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation("com.hivemq:hivemq-extension-sdk:4.8.3") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") - testImplementation("ch.qos.logback:logback-classic:1.4.0") + testImplementation("ch.qos.logback:logback-classic:1.4.1") testImplementation 'org.assertj:assertj-core:3.23.1' testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0") } From e094aceeef5d76b57018b4dd453c686f4883ed0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:56 +0000 Subject: [PATCH 2253/4969] Bump json from 20220320 to 20220924 in /examples Bumps [json](https://github.com/douglascrockford/JSON-java) from 20220320 to 20220924. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- examples/linked-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 5d9fb93c20d..fe230f3a22e 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:2.0.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0' - implementation 'org.json:json:20220320' + implementation 'org.json:json:20220924' testImplementation 'org.postgresql:postgresql:42.5.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:postgresql' From 942923183b8946b8c4c7edb8d5a24bfbb5748611 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:07:59 +0000 Subject: [PATCH 2254/4969] Bump hivemq-extension-sdk from 4.8.3 to 4.9.0 in /modules/hivemq Bumps [hivemq-extension-sdk](https://github.com/hivemq/hivemq-extension-sdk) from 4.8.3 to 4.9.0. - [Release notes](https://github.com/hivemq/hivemq-extension-sdk/releases) - [Commits](https://github.com/hivemq/hivemq-extension-sdk/compare/4.8.3...4.9.0) --- updated-dependencies: - dependency-name: com.hivemq:hivemq-extension-sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 477d5ac98a3..b6b9a42c425 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -13,7 +13,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") testImplementation(project(":junit-jupiter")) - testImplementation("com.hivemq:hivemq-extension-sdk:4.8.3") + testImplementation("com.hivemq:hivemq-extension-sdk:4.9.0") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.4.0") From 27bb1aef9800f8b33c413133b970c6dbecd4aa1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:08:03 +0000 Subject: [PATCH 2255/4969] Bump junit-jupiter-api from 5.9.0 to 5.9.1 in /modules/hivemq Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 477d5ac98a3..50b857d7ed6 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -11,7 +11,7 @@ dependencies { shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") shaded("net.lingala.zip4j:zip4j:2.11.1") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.1") testImplementation(project(":junit-jupiter")) testImplementation("com.hivemq:hivemq-extension-sdk:4.8.3") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") From f7bd0350106a97eafb53a5ff722b63d63cc5ce67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:08:06 +0000 Subject: [PATCH 2256/4969] Bump org.springframework.boot from 2.7.3 to 2.7.4 in /examples Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.7.3 to 2.7.4. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.7.3...v2.7.4) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/selenium-container/build.gradle | 2 +- examples/spring-boot-kotlin-redis/build.gradle | 2 +- examples/spring-boot/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 6183b89e1d6..feb677dc64a 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.7.3' + id 'org.springframework.boot' version '2.7.4' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 180d6780c8f..6a98573172c 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.7.3" + id("org.springframework.boot") version "2.7.4" id("org.jetbrains.kotlin.jvm") version "1.7.10" id("org.jetbrains.kotlin.plugin.spring") version "1.7.10" } diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index 52a4a63386a..56cd62e34e6 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.7.3' + id 'org.springframework.boot' version '2.7.4' } apply plugin: 'io.spring.dependency-management' From 5c9d06d226bcb23c00eaa02ff94588dd83d582df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:08:07 +0000 Subject: [PATCH 2257/4969] Bump kafka-clients from 3.2.1 to 3.3.0 in /examples Bumps kafka-clients from 3.2.1 to 3.3.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/kafka-cluster/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index c3a79d4058f..08d3734a956 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompileOnly "org.projectlombok:lombok:1.18.24" testAnnotationProcessor "org.projectlombok:lombok:1.18.24" testImplementation 'org.testcontainers:kafka' - testImplementation 'org.apache.kafka:kafka-clients:3.2.1' + testImplementation 'org.apache.kafka:kafka-clients:3.3.0' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' testImplementation 'ch.qos.logback:logback-classic:1.2.11' From 4ec5af3f90e6bb9da32297067e7519a89b61dcb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:08:08 +0000 Subject: [PATCH 2258/4969] Bump junit-jupiter-engine from 5.9.0 to 5.9.1 in /modules/hivemq Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 477d5ac98a3..511e504f8ef 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -18,7 +18,7 @@ dependencies { testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.4.0") testImplementation 'org.assertj:assertj-core:3.23.1' - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.1") } test { From 21e09603751d887da68dc28b0ea431e1758f2beb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:08:16 +0000 Subject: [PATCH 2259/4969] Bump zip4j from 2.11.1 to 2.11.2 in /modules/hivemq Bumps [zip4j](https://github.com/srikanth-lingala/zip4j) from 2.11.1 to 2.11.2. - [Release notes](https://github.com/srikanth-lingala/zip4j/releases) - [Commits](https://github.com/srikanth-lingala/zip4j/compare/v2.11.1...v2.11.2) --- updated-dependencies: - dependency-name: net.lingala.zip4j:zip4j dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 477d5ac98a3..0c336745f77 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -9,7 +9,7 @@ dependencies { shaded("org.javassist:javassist:3.29.0-GA") shaded("org.jboss.shrinkwrap:shrinkwrap-api:1.2.6") shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") - shaded("net.lingala.zip4j:zip4j:2.11.1") + shaded("net.lingala.zip4j:zip4j:2.11.2") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") testImplementation(project(":junit-jupiter")) From ff13685d346a6329268b2b5de0f82b8323117087 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 22:08:17 +0000 Subject: [PATCH 2260/4969] Bump cucumber-junit from 7.6.0 to 7.8.0 in /examples Bumps [cucumber-junit](https://github.com/cucumber/cucumber-jvm) from 7.6.0 to 7.8.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.6.0...v7.8.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index ab0331f81f4..9d0da7a5e33 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -11,6 +11,6 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' testImplementation 'io.cucumber:cucumber-java:7.6.0' - testImplementation 'io.cucumber:cucumber-junit:7.6.0' + testImplementation 'io.cucumber:cucumber-junit:7.8.0' testImplementation 'org.testcontainers:selenium' } From 6b3c7b4fa132021bc443ca09e1322bcc5a2dbb62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 29 Sep 2022 18:09:45 -0500 Subject: [PATCH 2261/4969] Rename main branch (#5847) `main` is the new default branch name. --- .github/workflows/ci-docker-wormhole.yml | 2 +- .github/workflows/ci-examples.yml | 2 +- .github/workflows/ci-rootless.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/release-drafter.yml | 2 +- .github/workflows/update-docs-version.yml | 2 +- RELEASING.md | 2 +- docs/contributing.md | 2 +- docs/examples.md | 22 +++++++++++----------- docs/index.md | 4 ++-- docs/jitpack_dependencies.md | 4 ++-- docs/modules/consul.md | 2 +- docs/modules/databases/jdbc.md | 4 ++-- docs/modules/databases/mssqlserver.md | 4 ++-- docs/modules/gcloud.md | 8 ++++---- docs/modules/vault.md | 4 ++-- docs/modules/webdriver_containers.md | 2 +- 17 files changed, 35 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci-docker-wormhole.yml b/.github/workflows/ci-docker-wormhole.yml index e27e4d8d611..061a004682e 100644 --- a/.github/workflows/ci-docker-wormhole.yml +++ b/.github/workflows/ci-docker-wormhole.yml @@ -2,7 +2,7 @@ name: CI-Docker-Wormhole on: pull_request: {} - push: { branches: [ master ] } + push: { branches: [ main ] } permissions: contents: read diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index fe4610368aa..2cdc9f8ed69 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -2,7 +2,7 @@ name: CI-Examples on: pull_request: {} - push: { branches: [ master ] } + push: { branches: [ main ] } env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index 348cf5aaaf7..50db1655a4a 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -2,7 +2,7 @@ name: CI-Docker-Rootless on: pull_request: {} - push: { branches: [ master ] } + push: { branches: [ main ] } permissions: contents: read diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1eceab8702..80f20fb0c0c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: pull_request: {} - push: { branches: [ master ] } + push: { branches: [ maing ] } permissions: contents: read diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 94af563bcda..46b1e261789 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -3,7 +3,7 @@ name: Release Drafter on: push: branches: - - master + - main pull_request: types: [opened, reopened, synchronize] diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index 070fa2c55d4..2c54f92efcf 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v3 with: - ref: master + ref: main - name: Update latest_version property in mkdocs.yml run: | sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml diff --git a/RELEASING.md b/RELEASING.md index f04839d9d41..8027cb9cc98 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -4,7 +4,7 @@ Testcontainers' release process is semi-automated through GitHub Actions. This d ## Steps -1. Ensure that the master branch is building and that tests are passing. +1. Ensure that the `main` branch is building and that tests are passing. 1. Create a new release on GitHub. **The tag name is used as the version**, so please keep the tag name plain (e.g. 1.2.3). 1. The release triggers a GitHub Action workflow. 1. Log in to [Sonatype](https://oss.sonatype.org/) to check the staging repository. diff --git a/docs/contributing.md b/docs/contributing.md index 01c4fce57b6..1457839a5ec 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -101,7 +101,7 @@ For this, we are using the [gh-combine-prs](https://github.com/rnorth/gh-combine The whole process is as follow: 1. Check that all open Dependabot PRs did succeed their build. If they did not succeed, trigger a rerun if the cause were external factors or else document the reason if obvious. -2. Run the extension from an up-to-date local `master` branch: `gh combine-prs --query "author:app/dependabot"` +2. Run the extension from an up-to-date local `main` branch: `gh combine-prs --query "author:app/dependabot"` 3. Merge conflicts might appear. Just ignore them, we will get those PRs in a future run. 4. Once the build of the combined PR did succeed, temporarily enable merge commits and merge the PR using a merge commit through the GitHub UI. 5. After the merge, disable merge commits again. diff --git a/docs/examples.md b/docs/examples.md index 918688d86cb..14f43d21e23 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -2,14 +2,14 @@ Examples of different use cases provided by Testcontainers can be found below: -- [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/kafka-cluster) -- [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/linked-container) -- [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/master/examples/neo4j-container) -- [Redis](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache) -- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/master/examples/selenium-container) -- [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) -- [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/master/examples/singleton-container) -- [Solr](https://github.com/testcontainers/testcontainers-java/tree/master/examples/solr-container) -- [Spring Boot](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot) -- [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot-kotlin-redis) -- [TestNG](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache-testng) +- [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/kafka-cluster) +- [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/linked-container) +- [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/main/examples/neo4j-container) +- [Redis](https://github.com/testcontainers/testcontainers-java/tree/main/examples/redis-backed-cache) +- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/main/examples/selenium-container) +- [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/main/examples/cucumber) +- [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/main/examples/singleton-container) +- [Solr](https://github.com/testcontainers/testcontainers-java/tree/main/examples/solr-container) +- [Spring Boot](https://github.com/testcontainers/testcontainers-java/tree/main/examples/spring-boot) +- [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/main/examples/spring-boot-kotlin-redis) +- [TestNG](https://github.com/testcontainers/testcontainers-java/tree/main/examples/redis-backed-cache-testng) diff --git a/docs/index.md b/docs/index.md index 8eb4ddeb2c4..383f42c0245 100644 --- a/docs/index.md +++ b/docs/index.md @@ -206,7 +206,7 @@ A huge thank you to our sponsors: ## License -See [LICENSE](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/LICENSE). +See [LICENSE](https://raw.githubusercontent.com/testcontainers/testcontainers-java/main/LICENSE). ## Attributions @@ -218,4 +218,4 @@ This project was initially inspired by a [gist](https://gist.github.com/mosheesh Copyright (c) 2015-2021 Richard North and other authors. -See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/AUTHORS) for contributors. +See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/main/AUTHORS) for contributors. diff --git a/docs/jitpack_dependencies.md b/docs/jitpack_dependencies.md index 23a4c7353ad..30687dcd3bc 100644 --- a/docs/jitpack_dependencies.md +++ b/docs/jitpack_dependencies.md @@ -5,14 +5,14 @@ Use the following dependency description instead: === "Gradle" ```groovy - testImplementation "com.github.testcontainers.testcontainers-java:--artifact name--:master-SNAPSHOT" + testImplementation "com.github.testcontainers.testcontainers-java:--artifact name--:main-SNAPSHOT" ``` === "Maven" ```xml com.github.testcontainers.testcontainers-java --artifact name-- - master-SNAPSHOT + main-SNAPSHOT ``` diff --git a/docs/modules/consul.md b/docs/modules/consul.md index 1580690cad7..d0eafd6b1a8 100644 --- a/docs/modules/consul.md +++ b/docs/modules/consul.md @@ -32,5 +32,5 @@ testImplementation "org.testcontainers:consul:{{latest_version}}" ``` -See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/modules/consul/AUTHORS) for contributors. +See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/main/modules/consul/AUTHORS) for contributors. diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index e3a077333cd..9e976d872ba 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -127,5 +127,5 @@ Note that if you use `@Rule`, you will be given an isolated container for each t Examples/Tests: - * [MySQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java) - * [PostgreSQL](https://github.com/testcontainers/testcontainers-java/blob/master/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java) + * [MySQL](https://github.com/testcontainers/testcontainers-java/blob/main/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java) + * [PostgreSQL](https://github.com/testcontainers/testcontainers-java/blob/main/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java) diff --git a/docs/modules/databases/mssqlserver.md b/docs/modules/databases/mssqlserver.md index 7ddd5350a40..9d0912f2563 100644 --- a/docs/modules/databases/mssqlserver.md +++ b/docs/modules/databases/mssqlserver.md @@ -49,10 +49,10 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: ## License -See [LICENSE](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/modules/mssqlserver/LICENSE). +See [LICENSE](https://raw.githubusercontent.com/testcontainers/testcontainers-java/main/modules/mssqlserver/LICENSE). ## Copyright Copyright (c) 2017 - 2019 G DATA Software AG and other authors. -See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/modules/mssqlserver/AUTHORS) for contributors. +See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/main/modules/mssqlserver/AUTHORS) for contributors. diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 7431ed0de0f..807b81de433 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -53,7 +53,7 @@ And test against the Emulator: See more examples: - * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/main/modules/gcloud/src/test/java/org/testcontainers/containers/DatastoreEmulatorContainerTest.java) * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/datastore-example/src/test/java/com/example/springboot/datastore) ### Firestore @@ -72,7 +72,7 @@ And test against the Emulator: See more examples: - * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java) + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/main/modules/gcloud/src/test/java/org/testcontainers/containers/FirestoreEmulatorContainerTest.java) * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/firestore-example/src/test/java/com/example/springboot/firestore/FirestoreIntegrationTests.java) ### Spanner @@ -103,7 +103,7 @@ And test against the Emulator: See more examples: - * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java) + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/main/modules/gcloud/src/test/java/org/testcontainers/containers/SpannerEmulatorContainerTest.java) * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/spanner-example/src/test/java/com/example/springboot/spanner/SpannerIntegrationTests.java) ### Pub/Sub @@ -134,7 +134,7 @@ And test against the Emulator: See more examples: - * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/master/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) + * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/main/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/pubsub-example/src/test/java/com/example/springboot/pubsub/PubSubIntegrationTests.java) ## Adding this module to your project dependencies diff --git a/docs/modules/vault.md b/docs/modules/vault.md index 577ed91a32f..4a232361464 100644 --- a/docs/modules/vault.md +++ b/docs/modules/vault.md @@ -57,11 +57,11 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: ## License -See [LICENSE](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/modules/vault/LICENSE). +See [LICENSE](https://raw.githubusercontent.com/testcontainers/testcontainers-java/main/modules/vault/LICENSE). ## Copyright Copyright (c) 2017 Capital One Services, LLC and other authors. -See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/master/modules/vault/AUTHORS) for contributors. +See [AUTHORS](https://raw.githubusercontent.com/testcontainers/testcontainers-java/main/modules/vault/AUTHORS) for contributors. diff --git a/docs/modules/webdriver_containers.md b/docs/modules/webdriver_containers.md index ec1dc2a407f..7ff4d2d6304 100644 --- a/docs/modules/webdriver_containers.md +++ b/docs/modules/webdriver_containers.md @@ -81,7 +81,7 @@ Note the factory must implement `org.testcontainers.containers.RecordingFileFact ## More examples -A few different examples are shown in [ChromeWebDriverContainerTest.java](https://github.com/testcontainers/testcontainers-java/blob/master/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java). +A few different examples are shown in [ChromeWebDriverContainerTest.java](https://github.com/testcontainers/testcontainers-java/blob/main/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java). ## Adding this module to your project dependencies From 14687a6cd23d31df43e87216f8d558bb9eb4943d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 30 Sep 2022 09:23:29 -0500 Subject: [PATCH 2262/4969] Reference to GitHub Discussions (#5928) Take advantage of discussions to have previous conversations with contributors before investing time working on PRs or asking general questions. Co-authored-by: Kevin Wittek --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/enhancement.yaml | 2 +- .github/ISSUE_TEMPLATE/feature.yaml | 2 +- docs/contributing.md | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 9945297ea7a..8196451e88f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Thanks for taking the time to fill out this bug report! Before submitting a `bug`, please make sure there is no existing issue for the one you encountered. + Thanks for taking the time to fill out this bug report! Before submitting a `bug`, please make sure there is no existing issue for the one you encountered and it has been discussed with the team via [discussions](https://github.com/testcontainers/testcontainers-java/discussions) or Slack. - type: dropdown id: module attributes: diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 6d5edab909f..9d65e1f12b8 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Before submitting an `enhancement`, please make sure there is no existing enhancement for the one you are requesting. If so, please provide the following information: + Before submitting an `enhancement`, please make sure there is no existing enhancement for the one you are requesting and it has been discussed with the team via [discussions](https://github.com/testcontainers/testcontainers-java/discussions) or Slack. If so, please provide the following information: - type: dropdown id: module attributes: diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 8abeb7d2131..581870d976d 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Before submitting a `feature`, please make sure there is no existing feature for the one you are requesting. If so, please provide the following information: + Before submitting a `feature`, please make sure there is no existing feature for the one you are requesting and it has been discussed with the team via [discussions](https://github.com/testcontainers/testcontainers-java/discussions) or Slack. If so, please provide the following information: - type: dropdown id: module attributes: diff --git a/docs/contributing.md b/docs/contributing.md index 1457839a5ec..c8eac36e03b 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -2,9 +2,9 @@ * Star the project on [Github](https://github.com/testcontainers/testcontainers-java) and help spread the word :) * Join our [Slack group](http://slack.testcontainers.org) -* [Post an issue](https://github.com/testcontainers/testcontainers-java/issues) if you find any bugs +* [Start a discussion](https://github.com/testcontainers/testcontainers-java/discussions) if you have an idea, find a possible bug or have a general question. * Contribute improvements or fixes using a [Pull Request](https://github.com/testcontainers/testcontainers-java/pulls). If you're going to contribute, thank you! Please just be sure to: - * discuss with the authors on an issue ticket prior to doing anything big. + * discuss with the authors prior to doing anything big. * follow the style, naming and structure conventions of the rest of the project. * make commits atomic and easy to merge. * when updating documentation, please see [our guidance for documentation contributions](contributing_docs.md). From f0dd61404fd570b91e71513317bde6a5a2599dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 30 Sep 2022 11:59:54 -0500 Subject: [PATCH 2263/4969] Add banner when Ryuk is disabled (#5929) This banner will warn the user about unexpected behavior if Ryuk is disabled. Co-authored-by: Kevin Wittek --- .../java/org/testcontainers/utility/ResourceReaper.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index ad0c949f6e7..1b99cd2abb4 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -79,6 +79,15 @@ public static synchronized ResourceReaper instance() { //noinspection deprecation instance = new RyukResourceReaper(); } else { + String ryukDisabledMessage = + "\n" + + "********************************************************************************" + + "\n" + + "Ryuk has been disabled. This can cause unexpected behavior in your environment." + + "\n" + + "********************************************************************************"; + LOGGER.warn(ryukDisabledMessage); + instance = new JVMHookResourceReaper(); } } From e2aeb68a45d2a3579e9a5667977789c24463478f Mon Sep 17 00:00:00 2001 From: Hari Ohm Prasath Date: Fri, 30 Sep 2022 10:14:00 -0700 Subject: [PATCH 2264/4969] Test container example for ImmuDB (#5860) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test container example using ImmuDB, performing basic operations Fixes #5594 Co-authored-by: Eddú Meléndez Gonzales --- docs/examples.md | 23 +++---- examples/immudb/build.gradle | 14 +++++ examples/immudb/src/test/java/ImmuDbTest.java | 63 +++++++++++++++++++ examples/settings.gradle | 1 + 4 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 examples/immudb/build.gradle create mode 100644 examples/immudb/src/test/java/ImmuDbTest.java diff --git a/docs/examples.md b/docs/examples.md index 14f43d21e23..cd85226e4be 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -2,14 +2,15 @@ Examples of different use cases provided by Testcontainers can be found below: -- [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/kafka-cluster) -- [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/linked-container) -- [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/main/examples/neo4j-container) -- [Redis](https://github.com/testcontainers/testcontainers-java/tree/main/examples/redis-backed-cache) -- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/main/examples/selenium-container) -- [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/main/examples/cucumber) -- [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/main/examples/singleton-container) -- [Solr](https://github.com/testcontainers/testcontainers-java/tree/main/examples/solr-container) -- [Spring Boot](https://github.com/testcontainers/testcontainers-java/tree/main/examples/spring-boot) -- [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/main/examples/spring-boot-kotlin-redis) -- [TestNG](https://github.com/testcontainers/testcontainers-java/tree/main/examples/redis-backed-cache-testng) +- [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/kafka-cluster) +- [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/linked-container) +- [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/master/examples/neo4j-container) +- [Redis](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache) +- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/master/examples/selenium-container) +- [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) +- [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/master/examples/singleton-container) +- [Solr](https://github.com/testcontainers/testcontainers-java/tree/master/examples/solr-container) +- [Spring Boot](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot) +- [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot-kotlin-redis) +- [TestNG](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache-testng) +- [ImmuDb](https://github.com/testcontainers/testcontainers-java/tree/master/examples/immudb) diff --git a/examples/immudb/build.gradle b/examples/immudb/build.gradle new file mode 100644 index 00000000000..5ff55a2205a --- /dev/null +++ b/examples/immudb/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnly 'org.slf4j:slf4j-api:2.0.0' + implementation 'io.codenotary:immudb4j:0.9.10.2' + testImplementation 'org.testcontainers:testcontainers' + testImplementation 'org.assertj:assertj-core:3.23.1' +} diff --git a/examples/immudb/src/test/java/ImmuDbTest.java b/examples/immudb/src/test/java/ImmuDbTest.java new file mode 100644 index 00000000000..fd515ddd4aa --- /dev/null +++ b/examples/immudb/src/test/java/ImmuDbTest.java @@ -0,0 +1,63 @@ +import io.codenotary.immudb4j.Entry; +import io.codenotary.immudb4j.ImmuClient; +import io.codenotary.immudb4j.exceptions.CorruptedDataException; +import io.codenotary.immudb4j.exceptions.VerificationException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test class for the ImmuDbClient. + */ +public class ImmuDbTest { + + // Default port for the ImmuDb server + private static final int IMMUDB_PORT = 3322; + // Default username for the ImmuDb server + private final String IMMUDB_USER = "immudb"; + // Default password for the ImmuDb server + private final String IMMUDB_PASSWORD = "immudb"; + // Default database name for the ImmuDb server + private final String IMMUDB_DATABASE = "defaultdb"; + + // Test container for the ImmuDb database, with the latest version of the image and exposed port + @ClassRule + public static final GenericContainer immuDbContainer = new GenericContainer<>("codenotary/immudb:1.3") + .withExposedPorts(IMMUDB_PORT).waitingFor( + Wait.forLogMessage(".*Web API server enabled.*", 1) + ); + // ImmuClient used to interact with the DB + private ImmuClient immuClient; + + @Before + public void setUp() { + this.immuClient = ImmuClient.newBuilder() + .withServerUrl(immuDbContainer.getHost()) + .withServerPort(immuDbContainer.getMappedPort(IMMUDB_PORT)) + .build(); + this.immuClient.login(IMMUDB_USER, IMMUDB_PASSWORD); + this.immuClient.useDatabase(IMMUDB_DATABASE); + } + + @Test + public void testGetValue() { + try { + immuClient.set("test1", "test2".getBytes()); + + Entry entry = immuClient.verifiedGet("test1"); + + if (entry != null) { + byte[] value = entry.getValue(); + assertThat(new String(value)).isEqualTo("test2"); + } else { + Assert.fail(); + } + } catch (CorruptedDataException | VerificationException e) { + Assert.fail(); + } + } +} diff --git a/examples/settings.gradle b/examples/settings.gradle index 7194134350d..2a508013928 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -30,6 +30,7 @@ include 'solr-container' include 'spring-boot' include 'cucumber' include 'spring-boot-kotlin-redis' +include 'immudb' ext.isCI = System.getenv("CI") != null From a71b5310185ee69634557557761dfa1ec73a0bee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Sep 2022 17:15:08 +0000 Subject: [PATCH 2265/4969] Bump slf4j-api from 2.0.0 to 2.0.3 in /core Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 2.0.0 to 2.0.3. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_2.0.0...v_2.0.3) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4072c25db37..e1e38eaeb18 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -61,7 +61,7 @@ configurations.all { dependencies { api 'junit:junit:4.13.2' - api 'org.slf4j:slf4j-api:2.0.0' + api 'org.slf4j:slf4j-api:2.0.3' compileOnly 'org.jetbrains:annotations:23.0.0' testCompileOnly 'org.jetbrains:annotations:23.0.0' api 'org.apache.commons:commons-compress:1.21' From a3d94ebf032eeaca9ed3bb5547de48fa405bec19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 01:03:24 +0000 Subject: [PATCH 2266/4969] Bump s3 from 2.17.266 to 2.17.285 in /modules/localstack Bumps s3 from 2.17.266 to 2.17.285. --- updated-dependencies: - dependency-name: software.amazon.awssdk:s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9759d193475..5ef16b2ca58 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.313' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.295' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.313' - testImplementation 'software.amazon.awssdk:s3:2.17.266' + testImplementation 'software.amazon.awssdk:s3:2.17.285' testImplementation 'org.assertj:assertj-core:3.23.1' } From 88f23b5fb5bbd25941617b37639f3c2cf852bb27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 01:03:27 +0000 Subject: [PATCH 2267/4969] Bump aws-java-sdk-sqs from 1.12.295 to 1.12.314 in /modules/localstack Bumps [aws-java-sdk-sqs](https://github.com/aws/aws-sdk-java) from 1.12.295 to 1.12.314. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.295...1.12.314) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-sqs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 9759d193475..2666932fbbc 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.313' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.313' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.295' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.314' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.313' testImplementation 'software.amazon.awssdk:s3:2.17.266' testImplementation 'org.assertj:assertj-core:3.23.1' From 3802c2934ded989bb5a433e5d48a5d036a9042f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 01:03:37 +0000 Subject: [PATCH 2268/4969] Bump google-cloud-firestore from 3.4.2 to 3.5.0 in /modules/gcloud Bumps [google-cloud-firestore](https://github.com/googleapis/java-firestore) from 3.4.2 to 3.5.0. - [Release notes](https://github.com/googleapis/java-firestore/releases) - [Changelog](https://github.com/googleapis/java-firestore/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-firestore/compare/v3.4.2...v3.5.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-firestore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 30c11325653..b52e6ea0dd0 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') testImplementation 'com.google.cloud:google-cloud-datastore:2.11.4' - testImplementation 'com.google.cloud:google-cloud-firestore:3.4.2' + testImplementation 'com.google.cloud:google-cloud-firestore:3.5.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.18' testImplementation 'com.google.cloud:google-cloud-spanner:6.29.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.11.1' From a2b1e15f1b008d100fe8b5761a59153a335627ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 01:03:38 +0000 Subject: [PATCH 2269/4969] Bump kafka-clients from 3.2.1 to 3.3.0 in /modules/kafka Bumps kafka-clients from 3.2.1 to 3.3.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index ebd9c84120c..70907510afe 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { api project(':testcontainers') - testImplementation 'org.apache.kafka:kafka-clients:3.2.1' + testImplementation 'org.apache.kafka:kafka-clients:3.3.0' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' } From d5fe8813f043eda38a5e257f3066bd3520e91314 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 01:03:39 +0000 Subject: [PATCH 2270/4969] Bump cucumber-java from 7.6.0 to 7.8.0 in /examples Bumps [cucumber-java](https://github.com/cucumber/cucumber-jvm) from 7.6.0 to 7.8.0. - [Release notes](https://github.com/cucumber/cucumber-jvm/releases) - [Changelog](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/cucumber-jvm/compare/v7.6.0...v7.8.0) --- updated-dependencies: - dependency-name: io.cucumber:cucumber-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- examples/cucumber/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 9d0da7a5e33..1b9fe04efd8 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'org.seleniumhq.selenium:selenium-remote-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-firefox-driver:3.141.59' implementation 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59' - testImplementation 'io.cucumber:cucumber-java:7.6.0' + testImplementation 'io.cucumber:cucumber-java:7.8.0' testImplementation 'io.cucumber:cucumber-junit:7.8.0' testImplementation 'org.testcontainers:selenium' } From 499f2ce17917e4ac181d08c748fab929014c7912 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 01:03:45 +0000 Subject: [PATCH 2271/4969] Bump google-cloud-spanner from 6.29.0 to 6.31.0 in /modules/gcloud Bumps [google-cloud-spanner](https://github.com/googleapis/java-spanner) from 6.29.0 to 6.31.0. - [Release notes](https://github.com/googleapis/java-spanner/releases) - [Changelog](https://github.com/googleapis/java-spanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-spanner/compare/v6.29.0...v6.31.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-spanner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 30c11325653..8be3aab89a5 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-datastore:2.11.4' testImplementation 'com.google.cloud:google-cloud-firestore:3.4.2' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.18' - testImplementation 'com.google.cloud:google-cloud-spanner:6.29.0' + testImplementation 'com.google.cloud:google-cloud-spanner:6.31.0' testImplementation 'com.google.cloud:google-cloud-bigtable:2.11.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From 3aa35988d5e83628846e27f3197b568bde58c5ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 03:52:29 +0000 Subject: [PATCH 2272/4969] Bump google-cloud-bigtable from 2.11.1 to 2.13.0 in /modules/gcloud Bumps [google-cloud-bigtable](https://github.com/googleapis/java-bigtable) from 2.11.1 to 2.13.0. - [Release notes](https://github.com/googleapis/java-bigtable/releases) - [Changelog](https://github.com/googleapis/java-bigtable/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-bigtable/compare/v2.11.1...v2.13.0) --- updated-dependencies: - dependency-name: com.google.cloud:google-cloud-bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/gcloud/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index 3258063f5dd..a5a72db0982 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -7,6 +7,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-firestore:3.5.0' testImplementation 'com.google.cloud:google-cloud-pubsub:1.120.18' testImplementation 'com.google.cloud:google-cloud-spanner:6.31.0' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.11.1' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.13.0' testImplementation 'org.assertj:assertj-core:3.23.1' } From bd6abf933eb383b0d82a805ca49091fb6fdd2f24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:00:34 +0000 Subject: [PATCH 2273/4969] Bump aws-java-sdk-s3 from 1.12.313 to 1.12.314 in /modules/localstack Bumps [aws-java-sdk-s3](https://github.com/aws/aws-sdk-java) from 1.12.313 to 1.12.314. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.313...1.12.314) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index b042ee575da..7d263e3e492 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.313' + compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.314' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.313' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.314' testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.313' From 554ec64d4aea8aa6ca50fa0bc654ced8057ab195 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:00:37 +0000 Subject: [PATCH 2274/4969] Bump aws-java-sdk-dynamodb in /modules/dynalite Bumps [aws-java-sdk-dynamodb](https://github.com/aws/aws-sdk-java) from 1.12.313 to 1.12.314. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.313...1.12.314) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-dynamodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/dynalite/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index e9cd2111f82..18ec4a61ac6 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.313' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.295' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.314' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.314' testImplementation 'org.assertj:assertj-core:3.23.1' } From f04648425bbc4a7fcf2d26d933e71e30a7886f18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:00:39 +0000 Subject: [PATCH 2275/4969] Bump aws-java-sdk-logs from 1.12.313 to 1.12.314 in /modules/localstack Bumps [aws-java-sdk-logs](https://github.com/aws/aws-sdk-java) from 1.12.313 to 1.12.314. - [Release notes](https://github.com/aws/aws-sdk-java/releases) - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.313...1.12.314) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-logs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/localstack/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index b042ee575da..d632c57cbfb 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly 'com.amazonaws:aws-java-sdk-s3:1.12.313' testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.313' testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.314' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.313' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.314' testImplementation 'software.amazon.awssdk:s3:2.17.285' testImplementation 'org.assertj:assertj-core:3.23.1' } From a3889d18f8cd33e40d73bf65b11fd44c8364bdee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:01:00 +0000 Subject: [PATCH 2276/4969] Bump actions/cache from 3.0.8 to 3.0.9 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.8 to 3.0.9. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.8...v3.0.9) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 2cdc9f8ed69..527c2eccfeb 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -25,7 +25,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.8 + uses: actions/cache@v3.0.9 continue-on-error: true with: path: ~/.gradle/caches @@ -53,7 +53,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.8 + uses: actions/cache@v3.0.9 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80f20fb0c0c..f55a5355c4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.8 + uses: actions/cache@v3.0.9 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -51,7 +51,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.8 + uses: actions/cache@v3.0.9 continue-on-error: true with: path: ~/.gradle/caches From d4c8de272e7a9c358e9066baed82cab097164b42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:01:07 +0000 Subject: [PATCH 2277/4969] Bump slf4j-api from 2.0.0 to 2.0.3 in /examples Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 2.0.0 to 2.0.3. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/compare/v_2.0.0...v_2.0.3) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/immudb/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/immudb/build.gradle b/examples/immudb/build.gradle index 5ff55a2205a..1d1940cb85b 100644 --- a/examples/immudb/build.gradle +++ b/examples/immudb/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.0' + compileOnly 'org.slf4j:slf4j-api:2.0.3' implementation 'io.codenotary:immudb4j:0.9.10.2' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.assertj:assertj-core:3.23.1' diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index fe230f3a22e..50e38518d39 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { mavenCentral() } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.0' + compileOnly 'org.slf4j:slf4j-api:2.0.3' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220924' testImplementation 'org.postgresql:postgresql:42.5.0' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 799f3f89925..c19dd3a012f 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.0' + compileOnly 'org.slf4j:slf4j-api:2.0.3' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 1d840f11871..82197ddc9b5 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.0' + compileOnly 'org.slf4j:slf4j-api:2.0.3' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index d540a8386ab..9c56d53faa3 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:2.0.0' + compileOnly 'org.slf4j:slf4j-api:2.0.3' testImplementation 'ch.qos.logback:logback-classic:1.2.11' testImplementation 'org.testcontainers:testcontainers' From 38e6cc18d77d4cc7b58da1842508142539955795 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:04:24 +0000 Subject: [PATCH 2278/4969] Bump azure-cosmos from 4.36.0 to 4.37.0 in /modules/azure Bumps [azure-cosmos](https://github.com/Azure/azure-sdk-for-java) from 4.36.0 to 4.37.0. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-cosmos_4.36.0...azure-cosmos_4.37.0) --- updated-dependencies: - dependency-name: com.azure:azure-cosmos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/azure/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 43280db4a88..78c6500d856 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:4.10.0' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'com.azure:azure-cosmos:4.36.0' + testImplementation 'com.azure:azure-cosmos:4.37.0' } From 2798d3403b9099b9bc4253f71ed2f4840a966e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 3 Oct 2022 09:23:22 -0500 Subject: [PATCH 2279/4969] Bump kotlin plugins version to 1.7.20 (#5945) --- examples/spring-boot-kotlin-redis/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index 6a98573172c..c0ec19f203c 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { id("org.springframework.boot") version "2.7.4" - id("org.jetbrains.kotlin.jvm") version "1.7.10" - id("org.jetbrains.kotlin.plugin.spring") version "1.7.10" + id("org.jetbrains.kotlin.jvm") version "1.7.20" + id("org.jetbrains.kotlin.plugin.spring") version "1.7.20" } apply plugin: 'io.spring.dependency-management' From 318bfc6833482c39f663cdbb0cceaecf46b87202 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Oct 2022 14:31:09 +0000 Subject: [PATCH 2280/4969] Bump javassist from 3.29.0-GA to 3.29.2-GA in /modules/hivemq Bumps [javassist](https://github.com/jboss-javassist/javassist) from 3.29.0-GA to 3.29.2-GA. - [Release notes](https://github.com/jboss-javassist/javassist/releases) - [Changelog](https://github.com/jboss-javassist/javassist/blob/master/Changes.md) - [Commits](https://github.com/jboss-javassist/javassist/commits) --- updated-dependencies: - dependency-name: org.javassist:javassist dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index a12b3866e4d..1da5ce69645 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -6,7 +6,7 @@ dependencies { shaded("org.apache.commons:commons-lang3:3.12.0") shaded("commons-io:commons-io:2.11.0") - shaded("org.javassist:javassist:3.29.0-GA") + shaded("org.javassist:javassist:3.29.2-GA") shaded("org.jboss.shrinkwrap:shrinkwrap-api:1.2.6") shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") shaded("net.lingala.zip4j:zip4j:2.11.2") From 03de1ce271fab9f4499097a9ed81cdee5e575450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Mon, 3 Oct 2022 12:44:00 -0500 Subject: [PATCH 2281/4969] Fix example docs links --- docs/examples.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index cd85226e4be..e7578c8b375 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -2,15 +2,15 @@ Examples of different use cases provided by Testcontainers can be found below: -- [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/kafka-cluster) -- [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/master/examples/linked-container) -- [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/master/examples/neo4j-container) -- [Redis](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache) -- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/master/examples/selenium-container) -- [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/master/examples/cucumber) -- [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/master/examples/singleton-container) -- [Solr](https://github.com/testcontainers/testcontainers-java/tree/master/examples/solr-container) -- [Spring Boot](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot) -- [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/master/examples/spring-boot-kotlin-redis) -- [TestNG](https://github.com/testcontainers/testcontainers-java/tree/master/examples/redis-backed-cache-testng) -- [ImmuDb](https://github.com/testcontainers/testcontainers-java/tree/master/examples/immudb) +- [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/kafka-cluster) +- [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/linked-container) +- [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/main/examples/neo4j-container) +- [Redis](https://github.com/testcontainers/testcontainers-java/tree/main/examples/redis-backed-cache) +- [Selenium](https://github.com/testcontainers/testcontainers-java/tree/main/examples/selenium-container) +- [Selenium Module with Cucumber](https://github.com/testcontainers/testcontainers-java/tree/main/examples/cucumber) +- [Singleton Container Pattern](https://github.com/testcontainers/testcontainers-java/tree/main/examples/singleton-container) +- [Solr](https://github.com/testcontainers/testcontainers-java/tree/main/examples/solr-container) +- [Spring Boot](https://github.com/testcontainers/testcontainers-java/tree/main/examples/spring-boot) +- [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/main/examples/spring-boot-kotlin-redis) +- [TestNG](https://github.com/testcontainers/testcontainers-java/tree/main/examples/redis-backed-cache-testng) +- [ImmuDb](https://github.com/testcontainers/testcontainers-java/tree/main/examples/immudb) From a8ec3e6da1c236b25bfba8d071c27ebbe57e938a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Mon, 3 Oct 2022 12:47:25 -0500 Subject: [PATCH 2282/4969] Fix main branch name in ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f55a5355c4e..b406f256ae2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: pull_request: {} - push: { branches: [ maing ] } + push: { branches: [ main ] } permissions: contents: read From c2a741d3b77531fe196025b559d0ad2fb655993e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 3 Oct 2022 13:35:08 -0500 Subject: [PATCH 2283/4969] Bump logback-classic versions (#5948) `ch.qos.logback:logback-classic` 1.3.x is compatible with slf4j 2.x. Currently, logs are not displayed. --- build.gradle | 2 +- docs/examples/spock/redis/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- modules/hivemq/build.gradle | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index a53bd19298d..9e6aa6020e4 100644 --- a/build.gradle +++ b/build.gradle @@ -125,7 +125,7 @@ subprojects { } dependencies { - testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.3' } spotless { diff --git a/docs/examples/spock/redis/build.gradle b/docs/examples/spock/redis/build.gradle index 1bff637a7fb..6699788d026 100644 --- a/docs/examples/spock/redis/build.gradle +++ b/docs/examples/spock/redis/build.gradle @@ -7,5 +7,5 @@ dependencies { api "io.lettuce:lettuce-core:5.2.0.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' testImplementation project(":spock") - testImplementation 'ch.qos.logback:logback-classic:1.2.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.3' } diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 08d3734a956..5212bc33fa9 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:3.3.0' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' + testImplementation 'ch.qos.logback:logback-classic:1.3.3' } diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 50e38518d39..297bcb5143f 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220924' testImplementation 'org.postgresql:postgresql:42.5.0' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' + testImplementation 'ch.qos.logback:logback-classic:1.3.3' testImplementation 'org.testcontainers:postgresql' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index c19dd3a012f..8e3394723ba 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' + testImplementation 'ch.qos.logback:logback-classic:1.3.3' testImplementation 'org.testng:testng:7.5' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index 82197ddc9b5..ed794088790 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -13,6 +13,6 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' + testImplementation 'ch.qos.logback:logback-classic:1.3.3' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 9c56d53faa3..3ef81b866d4 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:2.0.3' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' + testImplementation 'ch.qos.logback:logback-classic:1.3.3' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index a12b3866e4d..3d6b653f6d1 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation("com.hivemq:hivemq-extension-sdk:4.9.0") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") - testImplementation("ch.qos.logback:logback-classic:1.4.1") + testImplementation("ch.qos.logback:logback-classic:1.4.3") testImplementation 'org.assertj:assertj-core:3.23.1' testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.1") } From abf87abcae037e4ddf124c888c21e2a8a65180a8 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 4 Oct 2022 16:23:50 +0200 Subject: [PATCH 2284/4969] Rollback back to slf4j-api 1.7.36 (#5951) Reverts #5794, #5942, #5875, #5848, #5794, #5791 --- core/build.gradle | 2 +- examples/immudb/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- test-support/build.gradle | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index c20ebc1d9b0..2967b35d4ff 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -61,7 +61,7 @@ configurations.all { dependencies { api 'junit:junit:4.13.2' - api 'org.slf4j:slf4j-api:2.0.3' + api 'org.slf4j:slf4j-api:1.7.36' compileOnly 'org.jetbrains:annotations:23.0.0' testCompileOnly 'org.jetbrains:annotations:23.0.0' api 'org.apache.commons:commons-compress:1.21' diff --git a/examples/immudb/build.gradle b/examples/immudb/build.gradle index 1d1940cb85b..b2e6fcdba43 100644 --- a/examples/immudb/build.gradle +++ b/examples/immudb/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.3' + compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'io.codenotary:immudb4j:0.9.10.2' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.assertj:assertj-core:3.23.1' diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index 297bcb5143f..cf3a3331cc3 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -6,7 +6,7 @@ repositories { mavenCentral() } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.3' + compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220924' testImplementation 'org.postgresql:postgresql:42.5.0' diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 8e3394723ba..2e4bda4fa74 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.3' + compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index ed794088790..eb684158731 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -7,7 +7,7 @@ repositories { } dependencies { - compileOnly 'org.slf4j:slf4j-api:2.0.3' + compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 3ef81b866d4..449fd9ae8e6 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'redis.clients:jedis:4.2.3' implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' - compileOnly 'org.slf4j:slf4j-api:2.0.3' + compileOnly 'org.slf4j:slf4j-api:1.7.36' testImplementation 'ch.qos.logback:logback-classic:1.3.3' testImplementation 'org.testcontainers:testcontainers' diff --git a/test-support/build.gradle b/test-support/build.gradle index 2fae2344a89..8247f97dbf4 100644 --- a/test-support/build.gradle +++ b/test-support/build.gradle @@ -1,5 +1,5 @@ dependencies { implementation 'junit:junit:4.13.2' - implementation 'org.slf4j:slf4j-api:2.0.0' + implementation 'org.slf4j:slf4j-api:1.7.36' testImplementation 'org.assertj:assertj-core:3.23.1' } From 320a6203227f93ed138ea905105fa422346c80fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 4 Oct 2022 11:14:25 -0500 Subject: [PATCH 2285/4969] Ignore dependencies in specific modules (#5946) Some dependencies require Java 11, 17 or have a breaking change such as r2dbc. --- .github/dependabot.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4c270ef762c..87ce5c86463 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,6 +11,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "org.slf4j:slf4j-api" + update-types: [ "version-update:semver-major" ] - package-ecosystem: "gradle" directory: "/" allow: @@ -32,6 +35,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "io.dropwizard.metrics:metrics-core" + update-types: [ "version-update:semver-major" ] - package-ecosystem: "gradle" directory: "/modules/clickhouse" schedule: @@ -97,6 +103,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "org.apache.tomcat:tomcat-jdbc" + update-types: [ "version-update:semver-minor" ] - package-ecosystem: "gradle" directory: "/modules/junit-jupiter" schedule: @@ -107,6 +116,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" + update-types: [ "version-update:semver-minor" ] - package-ecosystem: "gradle" directory: "/modules/kafka" schedule: @@ -122,6 +134,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "org.mariadb:r2dbc-mariadb" + update-types: [ "version-update:semver-minor" ] - package-ecosystem: "gradle" directory: "/modules/mockserver" schedule: @@ -147,6 +162,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "org.neo4j.driver:neo4j-java-driver" + update-types: [ "version-update:semver-major" ] - package-ecosystem: "gradle" directory: "/modules/nginx" schedule: @@ -182,6 +200,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "io.r2dbc:r2dbc-spi" + versions: ["0.8.x"] - package-ecosystem: "gradle" directory: "/modules/rabbitmq" schedule: @@ -202,6 +223,9 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "org.apache.solr:solr-solrj" + update-types: [ "version-update:semver-major" ] - package-ecosystem: "gradle" directory: "/modules/spock" schedule: @@ -234,6 +258,17 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "ch.qos.logback:logback-classic" + update-types: [ "version-update:semver-minor" ] + - dependency-name: "org.apache.solr:solr-solrj" + update-types: [ "version-update:semver-major" ] + - dependency-name: "org.neo4j.driver:neo4j-java-driver" + update-types: [ "version-update:semver-major" ] + - dependency-name: "org.testng:testng" + update-types: [ "version-update:semver-minor" ] + - dependency-name: "org.slf4j:slf4j-api" + update-types: [ "version-update:semver-major" ] # GitHub Actions - package-ecosystem: "github-actions" From a6ceeba0b15d66e2f2b901ac56b43fc84e9815ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:14:55 +0000 Subject: [PATCH 2286/4969] Bump metrics-core from 3.2.4 to 3.2.6 in /modules/cassandra Bumps [metrics-core](https://github.com/dropwizard/metrics) from 3.2.4 to 3.2.6. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v3.2.4...v3.2.6) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cassandra/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cassandra/build.gradle b/modules/cassandra/build.gradle index ae115c92a71..7f9ab53c71b 100644 --- a/modules/cassandra/build.gradle +++ b/modules/cassandra/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: Cassandra" configurations.all { resolutionStrategy { - force 'io.dropwizard.metrics:metrics-core:3.2.4' + force 'io.dropwizard.metrics:metrics-core:3.2.6' } } From 461c23d6c65b769f42b5d18077e9b38130dde0bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:14:56 +0000 Subject: [PATCH 2287/4969] Bump mongodb-driver-sync from 4.7.1 to 4.7.2 in /modules/mongodb Bumps [mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 4.7.1 to 4.7.2. - [Release notes](https://github.com/mongodb/mongo-java-driver/releases) - [Commits](https://github.com/mongodb/mongo-java-driver/compare/r4.7.1...r4.7.2) --- updated-dependencies: - dependency-name: org.mongodb:mongodb-driver-sync dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mongodb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index 6e4b5208298..cc4a9288373 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: MongoDB" dependencies { api project(':testcontainers') - testImplementation("org.mongodb:mongodb-driver-sync:4.7.1") + testImplementation("org.mongodb:mongodb-driver-sync:4.7.2") testImplementation 'org.assertj:assertj-core:3.23.1' } From c4658989068d3c555fdff9b398c490d300a9a5d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:16:06 +0000 Subject: [PATCH 2288/4969] Bump solr-solrj from 8.11.1 to 8.11.2 in /modules/solr Bumps solr-solrj from 8.11.1 to 8.11.2. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/solr/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index 72ab2997dea..8d053fa4169 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:4.10.0' - testImplementation 'org.apache.solr:solr-solrj:8.11.1' + testImplementation 'org.apache.solr:solr-solrj:8.11.2' testImplementation 'org.assertj:assertj-core:3.23.1' } From c0758a2bf6c1f1ccf7154c9c337fc5aa1cdc9a52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:16:08 +0000 Subject: [PATCH 2289/4969] Bump solr-solrj from 8.11.1 to 8.11.2 in /examples Bumps solr-solrj from 8.11.1 to 8.11.2. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 56fd297cf5e..dd0f7007689 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.24" annotationProcessor "org.projectlombok:lombok:1.18.24" - implementation 'org.apache.solr:solr-solrj:8.11.1' + implementation 'org.apache.solr:solr-solrj:8.11.2' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From c65fc31df0620347e7e4236e8714b18ba52c14d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Tue, 4 Oct 2022 13:43:29 -0500 Subject: [PATCH 2290/4969] Update latest version in mkdocs.yml --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index ab57aeb11d6..3a802d4ec91 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -108,4 +108,4 @@ nav: - contributing_docs.md - bounty.md extra: - latest_version: 1.17.4 + latest_version: 1.17.5 From b1fa4ece54a4d13e67d20a3db123c98230451f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Tue, 4 Oct 2022 13:44:04 -0500 Subject: [PATCH 2291/4969] Upgrade testcontainers version to 1.17.5 in japicmp --- gradle/japicmp.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/japicmp.gradle b/gradle/japicmp.gradle index 6d769bf9286..ed4223324ab 100644 --- a/gradle/japicmp.gradle +++ b/gradle/japicmp.gradle @@ -3,7 +3,7 @@ configurations { } dependencies { - baseline "org.testcontainers:${project.name}:1.17.4", { + baseline "org.testcontainers:${project.name}:1.17.5", { exclude group: "*", module: "*" } } From f5e79b9aab308acc0211fca4bd0d00ab9b57cbd6 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Dolling Date: Tue, 4 Oct 2022 22:08:46 +0200 Subject: [PATCH 2292/4969] Remove unnecessary configuration from simple tests (#5973) * Remove mysql configuration from simple test * mysql custom ini file test also runs on Windows Co-authored-by: Kevin Wittek --- .../java/org/testcontainers/junit/mysql/SimpleMySQLTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java index f60712e7123..e39c55b85a9 100644 --- a/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java @@ -1,6 +1,5 @@ package org.testcontainers.junit.mysql; -import org.apache.commons.lang3.SystemUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +20,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import static org.junit.Assume.assumeFalse; public class SimpleMySQLTest extends AbstractContainerDatabaseTest { @@ -48,7 +46,6 @@ public class SimpleMySQLTest extends AbstractContainerDatabaseTest { public void testSimple() throws SQLException { try ( MySQLContainer mysql = new MySQLContainer<>(MySQLTestImages.MYSQL_57_IMAGE) - .withConfigurationOverride("somepath/mysql_conf_override") .withLogConsumer(new Slf4jLogConsumer(logger)) ) { mysql.start(); @@ -81,8 +78,6 @@ public void testSpecificVersion() throws SQLException { @Test public void testMySQLWithCustomIniFile() throws SQLException { - assumeFalse(SystemUtils.IS_OS_WINDOWS); - try ( MySQLContainer mysqlCustomConfig = new MySQLContainer<>(MySQLTestImages.MYSQL_56_IMAGE) .withConfigurationOverride("somepath/mysql_conf_override") From 2de82d96b38bb163941b64326f6286e8a4dce02d Mon Sep 17 00:00:00 2001 From: "K. Siva Prasad Reddy" Date: Wed, 5 Oct 2022 05:47:34 +0530 Subject: [PATCH 2293/4969] Update MockServer Tests to use mockserver/mockserver image with 5.14.0 version (#5977) Fixes #5975 --- modules/mockserver/build.gradle | 2 +- .../containers/MockServerContainerRuleTest.java | 6 ++++-- .../testcontainers/containers/MockServerContainerTest.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/mockserver/build.gradle b/modules/mockserver/build.gradle index df46295df21..85e7aaa181e 100644 --- a/modules/mockserver/build.gradle +++ b/modules/mockserver/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: MockServer" dependencies { api project(':testcontainers') - testImplementation 'org.mock-server:mockserver-client-java:5.13.2' + testImplementation 'org.mock-server:mockserver-client-java:5.14.0' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java index 0e4fa102b2e..7fdacd7c580 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerRuleTest.java @@ -12,12 +12,14 @@ public class MockServerContainerRuleTest { public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse( - "jamesdbloom/mockserver:mockserver-5.13.2" + "mockserver/mockserver:mockserver-5.14.0" ); // creatingProxy { @Rule - public MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE); + public MockServerContainer mockServer = new MockServerContainer( + MOCKSERVER_IMAGE.withTag("mockserver-" + MockServerClient.class.getPackage().getImplementationVersion()) + ); // } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index 6ddce4b6cbf..b59f14cc27b 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -11,7 +11,7 @@ public class MockServerContainerTest { public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse( - "jamesdbloom/mockserver:mockserver-5.5.4" + "mockserver/mockserver:mockserver-5.14.0" ); @Test @@ -40,7 +40,7 @@ public void shouldCallActualMockserverVersion() throws Exception { @Test public void newVersionStartsWithDefaultWaitStrategy() { - DockerImageName dockerImageName = DockerImageName.parse("mockserver/mockserver:mockserver-5.11.2"); + DockerImageName dockerImageName = DockerImageName.parse("mockserver/mockserver:mockserver-5.14.0"); try (MockServerContainer mockServer = new MockServerContainer(dockerImageName)) { mockServer.start(); } From 478b0492ea1526a2941ef714f9c9c7c4bcbb57a9 Mon Sep 17 00:00:00 2001 From: Etienne Dysli Metref Date: Thu, 6 Oct 2022 01:54:39 +0200 Subject: [PATCH 2294/4969] Update docs about logging configuration (#5976) * Recommend disabling Apache HTTP client wire logging * Recommend enabling debug logging only for org.testcontainers Fixes #4913 Co-authored-by: Kevin Wittek --- docs/supported_docker_environment/logging_config.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/supported_docker_environment/logging_config.md b/docs/supported_docker_environment/logging_config.md index 5c7abcd211c..3e4660e85ae 100644 --- a/docs/supported_docker_environment/logging_config.md +++ b/docs/supported_docker_environment/logging_config.md @@ -18,5 +18,14 @@ should be included in your classpath to show a reasonable level of log output: + ``` + +In order to troubleshoot issues with Testcontainers, increase the logging level of `org.testcontainers` to `DEBUG`: + +```xml + +``` + +Avoid changing the root logger's level to `DEBUG`, because this turns on debug logging for every package whose level isn't explicitly configured here, resulting in a large amount of log data. From 09c42a488b2ee1fb010213976fe9621c17d461c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 6 Oct 2022 13:13:13 -0500 Subject: [PATCH 2295/4969] Add reference to supported languages (#5979) Co-authored-by: Kevin Wittek --- docs/supported_languages.md | 9 +++++++++ mkdocs.yml | 1 + 2 files changed, 10 insertions(+) create mode 100644 docs/supported_languages.md diff --git a/docs/supported_languages.md b/docs/supported_languages.md new file mode 100644 index 00000000000..4990559f0e7 --- /dev/null +++ b/docs/supported_languages.md @@ -0,0 +1,9 @@ +# Other Supported Languages + +Besides *Testcontainers for Java,* you can find Testcontainers implementations for many other languages. +Please note that not all features that are available in *Testcontainers for Java* might be available in the implementations for other languages yet. + +* [Go](https://golang.testcontainers.org/) +* [.Net](https://github.com/testcontainers/testcontainers-dotnet) +* [Python](https://testcontainers-python.readthedocs.io/) +* [JavaScript/NodeJS](https://github.com/testcontainers/testcontainers-node) diff --git a/mkdocs.yml b/mkdocs.yml index 3a802d4ec91..70421761e02 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -102,6 +102,7 @@ nav: - supported_docker_environment/windows.md - supported_docker_environment/logging_config.md - supported_docker_environment/image_registry_rate_limiting.md + - Other Supported Languages: supported_languages.md - Getting help: getting_help.md - Contributing: - contributing.md From 914769f56a1b5b9c66d4419e6b1ca0e178cef399 Mon Sep 17 00:00:00 2001 From: Priyambada Roul <75459506+roulpriya@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:06:01 +0530 Subject: [PATCH 2296/4969] Do not allow empty env vars (#5983) Fixes #5026 Signed-off-by: Priyambada Roul --- .../utility/TestcontainersConfiguration.java | 5 ++++- .../utility/TestcontainersConfigurationTest.java | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index e647a8d50b3..f3bb8f8319a 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -230,7 +230,10 @@ private String getConfigurable( } if (environment.containsKey(envVarName)) { - return environment.get(envVarName); + String value = environment.get(envVarName); + if (!value.isEmpty()) { + return value; + } } for (final Properties properties : propertiesSources) { diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index d51bc89348c..fcc0a654ef5 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -126,6 +126,14 @@ public void shouldReadDockerSettingsFromUserProperties() { .isEqualTo("some value"); } + @Test + public void shouldNotReadSettingIfCorrespondingEnvironmentVarIsEmptyString() { + environment.put("DOCKER_FOO", ""); + assertThat(newConfig().getEnvVarOrUserProperty("docker.foo", "default")) + .as("reads unprefixed env vars for docker. settings") + .isEqualTo("default"); + } + @Test public void shouldNotReadDockerClientStrategyFromClasspathProperties() { String currentValue = newConfig().getDockerClientStrategyClassName(); From 75ac1d1ff5e14a0306f981288d5736d275970d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Tue, 11 Oct 2022 20:56:26 -0500 Subject: [PATCH 2297/4969] Upgrade python version to 3.8 --- docker-compose.yml | 2 +- docs/contributing_docs.md | 2 +- runtime.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1ce5532d0bd..bfb6bdc35fe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.7" services: docs: - image: python:3.7 + image: python:3.8 command: sh -c "pip install -r requirements.txt && mkdocs serve -a 0.0.0.0:8000" working_dir: /docs volumes: diff --git a/docs/contributing_docs.md b/docs/contributing_docs.md index 2d706dfe407..c303fe6b06c 100644 --- a/docs/contributing_docs.md +++ b/docs/contributing_docs.md @@ -15,7 +15,7 @@ The root of the project contains a `docker-compose.yml` file. Simply run `docker ### Using Python locally -* Ensure that you have Python 3.7.0 or higher. +* Ensure that you have Python 3.8.0 or higher. * Set up a virtualenv and run `pip install -r requirements.txt` in the `testcontainers-java` root directory. * Once Python dependencies have been installed, run `mkdocs serve` to start a local auto-updating MkDocs server. diff --git a/runtime.txt b/runtime.txt index 475ba515c04..cc1923a40b1 100644 --- a/runtime.txt +++ b/runtime.txt @@ -1 +1 @@ -3.7 +3.8 From 2da2675c1b9b13d7fde985c00001105b800a84ce Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Wed, 12 Oct 2022 11:50:26 +0200 Subject: [PATCH 2298/4969] Add paragraph about Docker requirements to docs (#5987) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- docs/supported_docker_environment/index.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/supported_docker_environment/index.md b/docs/supported_docker_environment/index.md index debca47e574..885325545ff 100644 --- a/docs/supported_docker_environment/index.md +++ b/docs/supported_docker_environment/index.md @@ -2,6 +2,15 @@ ## Overview +Testcontainers requires a Docker-API compatible container runtime. +During development, Testcontainers is actively tested against recent versions of Docker on Linux, as well as against Docker Desktop on Mac and Windows. +These Docker environments are automatically detected and used by Testcontainers without any additional configuration being necessary. + +It is possible to configure Testcontainers to work for other Docker setups, such as a remote Docker host or Docker alternatives. +However, these are not actively tested in the main development workflow, so not all Testcontainers features might be available and additional manual configuration might be necessary. +If you have further questions about configuration details for your setup or whether it supports running Testcontainers-based tests, +please contact the Testcontainers team and other users from the Testcontainers community on [Slack](https://slack.testcontainers.org/). + | Host Operating System / Environment | Minimum recommended docker versions | Known issues / tips | |-------------------------------------|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Linux - general | Docker v17.09 | After docker installation, follow [post-installation steps](https://docs.docker.com/engine/install/linux-postinstall/). | From 96acaf02721c5dbf543ff2b166366a190df57cfa Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Fri, 14 Oct 2022 08:59:59 -0700 Subject: [PATCH 2299/4969] Catch and ignore more errors when reflecting into container subclass (#5990) With #2830 we added support for 4.x of the Cassandra driver. It was done in a way to allow a user to use either the 3.x or 4.x driver while excluding the other one. However if using 4.x and excluding 3.x, GenericContainer#canBeReused throws an exception during reflection since the Cluster class returned by CassandraContainer#getCluster is missing. This PR works around that issue by catching and ignoring the thrown NoClassDefFoundError. --- .../java/org/testcontainers/containers/GenericContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 7163ea40a93..bc65cb22040 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -360,7 +360,7 @@ protected boolean canBeReused() { logger().warn("{} can't be reused because it overrides {}", getClass(), method.getName()); return false; } - } catch (NoSuchMethodException e) { + } catch (NoSuchMethodException | NoClassDefFoundError e) { // ignore } } From 00c5e88562e50f3337d43a3d193669a5fdbac61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 18 Oct 2022 08:12:30 -0500 Subject: [PATCH 2300/4969] Remove Transferable#of(java.lang.String,int) for japicmp (#5992) `Transferable#of(java.lang.String,int)` was introduced in version 1.17.4. Current builds will check against 1.17.5 and binary compatibility will be fine. --- core/build.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 2967b35d4ff..364f51b6b70 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -113,9 +113,3 @@ tasks.generatePomFileForMavenJavaPublication.finalizedBy( ] } ) - -tasks.japicmp { - methodExcludes = [ - "org.testcontainers.images.builder.Transferable#of(java.lang.String,int)" - ] -} From 077c84405486e061a31d585b8ffa5c2d3ea0b7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 19 Oct 2022 02:27:21 -0500 Subject: [PATCH 2301/4969] Deprecate `setCustomContent` and `withCustomContent` at `NginxContainer` (#5997) In order to make `NginxContainer` friendly with remote environments, we should avoid the use of `addFileSystemBind`. Example has been updated in order to show how to do it. --- .../java/org/testcontainers/containers/NginxContainer.java | 2 ++ .../test/java/org/testcontainers/junit/SimpleNginxTest.java | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java index b97992a5684..1bf951af7c8 100644 --- a/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java +++ b/modules/nginx/src/main/java/org/testcontainers/containers/NginxContainer.java @@ -56,10 +56,12 @@ public URL getBaseUrl(String scheme, int port) throws MalformedURLException { return new URL(scheme + "://" + getHost() + ":" + getMappedPort(port)); } + @Deprecated public void setCustomContent(String htmlContentPath) { addFileSystemBind(htmlContentPath, "/usr/share/nginx/html", BindMode.READ_ONLY); } + @Deprecated public SELF withCustomContent(String htmlContentPath) { this.setCustomContent(htmlContentPath); return self(); diff --git a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java index abfbb663207..d338ebf180b 100644 --- a/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java +++ b/modules/nginx/src/test/java/org/testcontainers/junit/SimpleNginxTest.java @@ -7,6 +7,7 @@ import org.testcontainers.containers.NginxContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; import java.io.*; import java.net.URL; @@ -26,7 +27,7 @@ public class SimpleNginxTest { // creatingContainer { @Rule public NginxContainer nginx = new NginxContainer<>(NGINX_IMAGE) - .withCustomContent(tmpDirectory) + .withCopyFileToContainer(MountableFile.forHostPath(tmpDirectory), "/usr/share/nginx/html") .waitingFor(new HttpWaitStrategy()); // } From 0b0e559141c5b83eaeb8ee89b143b5d28cbc3136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 19 Oct 2022 02:27:36 -0500 Subject: [PATCH 2302/4969] Update toxiproxy image to ghcr.io/shopify/toxiproxy (#5996) `shopify/toxiproxy` has moved to `ghcr.io/shopify/toxiproxy`. Currently, our tests are using the prior and is display as part of the documentation. In order to keep our tests and docs up-to-date with latest images we are updating the image. Also, we are adding the proper configuration for logging in this module. --- .../testcontainers/containers/ToxiproxyTest.java | 2 +- .../src/test/resources/logback-test.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 modules/toxiproxy/src/test/resources/logback-test.xml diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index bfe488eaac1..25a0feccc48 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -35,7 +35,7 @@ public class ToxiproxyTest { .withExposedPorts(6379) .withNetwork(network); - private static final DockerImageName TOXIPROXY_IMAGE = DockerImageName.parse("shopify/toxiproxy:2.1.0"); + private static final DockerImageName TOXIPROXY_IMAGE = DockerImageName.parse("ghcr.io/shopify/toxiproxy:2.5.0"); // Toxiproxy container, which will be used as a TCP proxy @Rule diff --git a/modules/toxiproxy/src/test/resources/logback-test.xml b/modules/toxiproxy/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/toxiproxy/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From d1864a466b294296bca00368fd904d78c3a78057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 20 Oct 2022 07:54:15 -0500 Subject: [PATCH 2303/4969] Fix dependabot.yml ignore section (#5999) --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 87ce5c86463..46c7046300d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -118,7 +118,7 @@ updates: open-pull-requests-limit: 10 ignore: - dependency-name: "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" - update-types: [ "version-update:semver-minor" ] + update-types: [ "version-update:semver-minor", "version-update:semver-patch" ] - package-ecosystem: "gradle" directory: "/modules/kafka" schedule: @@ -202,7 +202,7 @@ updates: open-pull-requests-limit: 10 ignore: - dependency-name: "io.r2dbc:r2dbc-spi" - versions: ["0.8.x"] + update-types: [ "version-update:semver-major", "version-update:semver-minor" ] - package-ecosystem: "gradle" directory: "/modules/rabbitmq" schedule: From cf1573e4ffab1f302141d5bda20d23ecaba5b148 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:49 +0000 Subject: [PATCH 2304/4969] Bump tomcat-jdbc from 10.0.23 to 10.0.27 in /modules/jdbc-test Bumps tomcat-jdbc from 10.0.23 to 10.0.27. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc-test/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc-test/build.gradle b/modules/jdbc-test/build.gradle index f8b55d01bc5..798508ffa22 100644 --- a/modules/jdbc-test/build.gradle +++ b/modules/jdbc-test/build.gradle @@ -11,7 +11,7 @@ dependencies { api 'org.assertj:assertj-core:3.23.1' - api 'org.apache.tomcat:tomcat-jdbc:10.0.23' + api 'org.apache.tomcat:tomcat-jdbc:10.0.27' api 'org.vibur:vibur-dbcp:25.0' api 'mysql:mysql-connector-java:8.0.30' } From 5ee6fd38cf3b4a2940cd399d4a3a662f3d5ec3e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:49 +0000 Subject: [PATCH 2305/4969] Bump mysql-connector-java from 8.0.30 to 8.0.31 in /modules/mysql Bumps mysql-connector-java from 8.0.30 to 8.0.31. --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/mysql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 87887384973..a18941ab9f7 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.30' + testImplementation 'mysql:mysql-connector-java:8.0.31' testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' From c8ec550ec6278d28cb3e5abcaf376292d2e9920c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:49 +0000 Subject: [PATCH 2306/4969] Bump tomcat-jdbc from 10.1.0 to 10.1.1 in /modules/jdbc Bumps tomcat-jdbc from 10.1.0 to 10.1.1. --- updated-dependencies: - dependency-name: org.apache.tomcat:tomcat-jdbc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/jdbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 7a0fbf03fc1..92f72287fa2 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -7,7 +7,7 @@ dependencies { compileOnly 'org.jetbrains:annotations:23.0.0' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.1.0' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.1.1' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation ('org.mockito:mockito-core:4.8.0') { From ceee70954ad8f32252925ff415e6f616b0f3aff3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:51 +0000 Subject: [PATCH 2307/4969] Bump reactor-core from 3.4.23 to 3.4.24 in /modules/r2dbc Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.23 to 3.4.24. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.4.23...v3.4.24) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/r2dbc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index 9126ff0a347..952c9f5b982 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.4.23' + testFixturesImplementation 'io.projectreactor:reactor-core:3.4.24' testFixturesImplementation 'org.assertj:assertj-core:3.23.1' } From d47b1ca51898e01d3002e76ac6fd6a2f2c6a6502 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:51 +0000 Subject: [PATCH 2308/4969] Bump mysql-connector-java from 8.0.30 to 8.0.31 in /modules/spock Bumps mysql-connector-java from 8.0.30 to 8.0.31. --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index a13a7049e13..e202b07f411 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testRuntimeOnly 'org.postgresql:postgresql:42.5.0' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.31' testCompileOnly 'org.jetbrains:annotations:23.0.0' } From b260332e1221363aa5b2bd3139460f6b65485ce0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:51 +0000 Subject: [PATCH 2309/4969] Bump jedis from 4.2.3 to 4.3.1 in /modules/junit-jupiter Bumps [jedis](https://github.com/redis/jedis) from 4.2.3 to 4.3.1. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v4.2.3...v4.3.1) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index e801e54ab83..496c273fbde 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:4.2.3' + testImplementation 'redis.clients:jedis:4.3.1' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' testImplementation ('org.mockito:mockito-core:4.8.0') { exclude(module: 'hamcrest-core') From 46a4edc16b065f9693a5c754670376e9e5d34467 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:52 +0000 Subject: [PATCH 2310/4969] Bump mysql-connector-java in /modules/junit-jupiter Bumps mysql-connector-java from 8.0.30 to 8.0.31. --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index e801e54ab83..2819985921d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1' testRuntimeOnly 'org.postgresql:postgresql:42.5.0' - testRuntimeOnly 'mysql:mysql-connector-java:8.0.30' + testRuntimeOnly 'mysql:mysql-connector-java:8.0.31' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.1' } From 5e23c5e8e680b6ddbda496d4b102bae08f7092ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:52 +0000 Subject: [PATCH 2311/4969] Bump pulsar-client-admin from 2.10.1 to 2.10.2 in /modules/pulsar Bumps [pulsar-client-admin](https://github.com/apache/pulsar) from 2.10.1 to 2.10.2. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.10.1...v2.10.2) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client-admin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 8bc139a3a93..c15fc32730e 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.10.1' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.23.1' - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.10.1' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.10.2' } From aa597b8ed501b6dbda20c06fbe0b42c0b5264b89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:54 +0000 Subject: [PATCH 2312/4969] Bump mysql-connector-java from 8.0.30 to 8.0.31 in /modules/tidb Bumps mysql-connector-java from 8.0.30 to 8.0.31. --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/tidb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/tidb/build.gradle b/modules/tidb/build.gradle index 36f6acfe806..92f4aa408d3 100644 --- a/modules/tidb/build.gradle +++ b/modules/tidb/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'mysql:mysql-connector-java:8.0.30' + testImplementation 'mysql:mysql-connector-java:8.0.31' compileOnly 'org.jetbrains:annotations:23.0.0' } From 070f670a0f7f9c1c4a61c6c1974e42cea41e15c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:58 +0000 Subject: [PATCH 2313/4969] Bump mysql-connector-java from 8.0.21 to 8.0.31 in /examples Bumps mysql-connector-java from 8.0.21 to 8.0.31. --- updated-dependencies: - dependency-name: mysql:mysql-connector-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/examples/junit4/generic/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle index da4697a4543..9c3edd6fe27 100644 --- a/docs/examples/junit4/generic/build.gradle +++ b/docs/examples/junit4/generic/build.gradle @@ -6,7 +6,7 @@ dependencies { testImplementation project(":selenium") testImplementation project(":mysql") - testImplementation 'mysql:mysql-connector-java:8.0.21' + testImplementation 'mysql:mysql-connector-java:8.0.31' testImplementation "org.seleniumhq.selenium:selenium-api:3.141.59" testImplementation 'org.assertj:assertj-core:3.15.0' } From 852ed7838b1a2d49bca12b6eaf3fcefd7bb82ad8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:54:59 +0000 Subject: [PATCH 2314/4969] Bump pulsar-client from 2.10.1 to 2.10.2 in /modules/pulsar Bumps [pulsar-client](https://github.com/apache/pulsar) from 2.10.1 to 2.10.2. - [Release notes](https://github.com/apache/pulsar/releases) - [Commits](https://github.com/apache/pulsar/compare/v2.10.1...v2.10.2) --- updated-dependencies: - dependency-name: org.apache.pulsar:pulsar-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/pulsar/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index 8bc139a3a93..fd015a9121f 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { api project(':testcontainers') - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.10.1' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.10.2' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.23.1' testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.10.1' } From 5e090c2984fb461fa26d76e14f54f46254dc7b6d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:55:00 +0000 Subject: [PATCH 2315/4969] Bump actions/cache from 3.0.9 to 3.0.11 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.9 to 3.0.11. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.9...v3.0.11) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-examples.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 527c2eccfeb..16b6d5249c7 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -25,7 +25,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.9 + uses: actions/cache@v3.0.11 continue-on-error: true with: path: ~/.gradle/caches @@ -53,7 +53,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.9 + uses: actions/cache@v3.0.11 continue-on-error: true with: path: ~/.gradle/caches diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b406f256ae2..25723b20ef0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.9 + uses: actions/cache@v3.0.11 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} @@ -51,7 +51,7 @@ jobs: java-version: '8.0.302' distribution: temurin - name: Cache Gradle Home files - uses: actions/cache@v3.0.9 + uses: actions/cache@v3.0.11 continue-on-error: true with: path: ~/.gradle/caches From c745c8f7256ca3852165b631e7919009bb926c5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:55:03 +0000 Subject: [PATCH 2316/4969] Bump peter-evans/create-pull-request from 4.1.3 to 4.2.0 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.1.3 to 4.2.0. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/671dc9c9e0c2d73f07fa45a3eb0220e1622f0c5f...b4d51739f96fca8047ad065eccef63442d8e99f7) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/update-docs-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index f40b5f41483..53ac0ae9b9a 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -23,7 +23,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@671dc9c9e0c2d73f07fa45a3eb0220e1622f0c5f # v3.10.1 + uses: peter-evans/create-pull-request@b4d51739f96fca8047ad065eccef63442d8e99f7 # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | From 7f39a39147eff17b5daed4f29419104cf21321b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 13:55:48 +0000 Subject: [PATCH 2317/4969] Bump release-drafter/release-drafter from 5.21.0 to 5.21.1 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.21.0 to 5.21.1. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/df69d584deac33d8569990cb6413f82447181076...6df64e4ba4842c203c604c1f45246c5863410adb) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index fca7465637f..df1a05c8441 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -18,6 +18,6 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@df69d584deac33d8569990cb6413f82447181076 # v5.19.0 + - uses: release-drafter/release-drafter@6df64e4ba4842c203c604c1f45246c5863410adb # v5.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 64bb21083001d41bb13b1c73fd2df4f44718a529 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 14:22:42 +0000 Subject: [PATCH 2318/4969] Bump junit-jupiter-params from 5.4.2 to 5.9.1 in /examples Bumps [junit-jupiter-params](https://github.com/junit-team/junit5) from 5.4.2 to 5.9.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.4.2...r5.9.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- docs/examples/junit5/redis/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/junit5/redis/build.gradle b/docs/examples/junit5/redis/build.gradle index 72b943adc23..3701d9699e9 100644 --- a/docs/examples/junit5/redis/build.gradle +++ b/docs/examples/junit5/redis/build.gradle @@ -4,7 +4,7 @@ dependencies { api "io.lettuce:lettuce-core:5.1.1.RELEASE" testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.2" - testImplementation "org.junit.jupiter:junit-jupiter-params:5.4.2" + testImplementation "org.junit.jupiter:junit-jupiter-params:5.9.1" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.2" testImplementation project(":testcontainers") testImplementation project(":junit-jupiter") From f9edf87f7a02926c6ceaa1cf2ce05ac30842b195 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Fri, 21 Oct 2022 18:14:44 +0200 Subject: [PATCH 2319/4969] Remove unused Pipfiles (#6046) --- Pipfile | 15 --- Pipfile.lock | 314 --------------------------------------------------- 2 files changed, 329 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 2236de86daf..00000000000 --- a/Pipfile +++ /dev/null @@ -1,15 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] -mkdocs = "*" -mkdocs-codeinclude-plugin = "*" -mkdocs-material = "*" -mkdocs-markdownextradata-plugin = "*" - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 7dad511e377..00000000000 --- a/Pipfile.lock +++ /dev/null @@ -1,314 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "d3830267ea93391a077a2ba5b93aa8218c0a38002694b404b56df11498da3e56" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "click": { - "hashes": [ - "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", - "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" - ], - "markers": "python_version >= '3.6'", - "version": "==8.0.3" - }, - "ghp-import": { - "hashes": [ - "sha256:5f8962b30b20652cdffa9c5a9812f7de6bcb56ec475acac579807719bf242c46", - "sha256:947b3771f11be850c852c64b561c600fdddf794bab363060854c1ee7ad05e071" - ], - "version": "==2.0.2" - }, - "importlib-metadata": { - "hashes": [ - "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100", - "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb" - ], - "markers": "python_version >= '3.6'", - "version": "==4.8.2" - }, - "jinja2": { - "hashes": [ - "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", - "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" - ], - "markers": "python_version >= '3.6'", - "version": "==3.0.3" - }, - "markdown": { - "hashes": [ - "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006", - "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3" - ], - "markers": "python_version >= '3.6'", - "version": "==3.3.6" - }, - "markupsafe": { - "hashes": [ - "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", - "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", - "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", - "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", - "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", - "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", - "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", - "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", - "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", - "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", - "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", - "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", - "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", - "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", - "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", - "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", - "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", - "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", - "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", - "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", - "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", - "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", - "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", - "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", - "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", - "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", - "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", - "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", - "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", - "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", - "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", - "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", - "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", - "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", - "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", - "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", - "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", - "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", - "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", - "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", - "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", - "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", - "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", - "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", - "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", - "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", - "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", - "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", - "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", - "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", - "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", - "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", - "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", - "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", - "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", - "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", - "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", - "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", - "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", - "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", - "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", - "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", - "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", - "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", - "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", - "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", - "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", - "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", - "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" - ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" - }, - "mergedeep": { - "hashes": [ - "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", - "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307" - ], - "markers": "python_version >= '3.6'", - "version": "==1.3.4" - }, - "mkdocs": { - "hashes": [ - "sha256:89f5a094764381cda656af4298727c9f53dc3e602983087e1fe96ea1df24f4c1", - "sha256:a1fa8c2d0c1305d7fc2b9d9f607c71778572a8b110fb26642aa00296c9e6d072" - ], - "index": "pypi", - "version": "==1.2.3" - }, - "mkdocs-codeinclude-plugin": { - "hashes": [ - "sha256:5d74bd4c1be8e64d71137c1ef1d27a0f9822d3d9ecb2af658d2af7664568a923", - "sha256:a94be142e27ef4a70d8ecc702c21d9596304e06d382d86b39a10ffe8b0375887" - ], - "index": "pypi", - "version": "==0.2.0" - }, - "mkdocs-markdownextradata-plugin": { - "hashes": [ - "sha256:64d1c966b288d653f51f7531c03204eb988d0d77e56055c9d703d99105259a36" - ], - "index": "pypi", - "version": "==0.0.5" - }, - "mkdocs-material": { - "hashes": [ - "sha256:524debb6ee8ee89cee08886f2a67c3c3875c0ee9579c598d7448cbd2607cd3b7", - "sha256:62ae84082fa9f077c86b7db63e7bedf392005041b451defc850f8d0887a11e91" - ], - "index": "pypi", - "version": "==3.2.0" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "markers": "python_version >= '3.6'", - "version": "==21.3" - }, - "pygments": { - "hashes": [ - "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380", - "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" - ], - "markers": "python_version >= '3.5'", - "version": "==2.10.0" - }, - "pymdown-extensions": { - "hashes": [ - "sha256:74247f2c80f1d9e3c7242abe1c16317da36c6f26c7ad4b8a7f457f0ec20f0365", - "sha256:b03e66f91f33af4a6e7a0e20c740313522995f69a03d86316b1449766c473d0e" - ], - "markers": "python_version >= '3.6'", - "version": "==9.1" - }, - "pyparsing": { - "hashes": [ - "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", - "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" - ], - "markers": "python_version >= '3.6'", - "version": "==3.0.6" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "pyyaml": { - "hashes": [ - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0" - }, - "pyyaml-env-tag": { - "hashes": [ - "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", - "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069" - ], - "markers": "python_version >= '3.6'", - "version": "==0.1" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "typing-extensions": { - "hashes": [ - "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", - "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" - ], - "markers": "python_version < '3.8'", - "version": "==4.0.1" - }, - "watchdog": { - "hashes": [ - "sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685", - "sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04", - "sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb", - "sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542", - "sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6", - "sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b", - "sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660", - "sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3", - "sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923", - "sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7", - "sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b", - "sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669", - "sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2", - "sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3", - "sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604", - "sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8", - "sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5", - "sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0", - "sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6", - "sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65", - "sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d", - "sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15", - "sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.6" - }, - "zipp": { - "hashes": [ - "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", - "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc" - ], - "markers": "python_version >= '3.6'", - "version": "==3.6.0" - } - }, - "develop": {} -} From 643b815a1adb825b948dc5d97906123d90d4eefd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Wangryn?= Date: Fri, 21 Oct 2022 18:49:33 +0200 Subject: [PATCH 2320/4969] Add QuestDB module (#5995) Introduce Testcontainers implementation for `QuestDB`, `QuestDBContainer`. --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 ++ .github/labeler.yml | 2 + docs/modules/databases/questdb.md | 29 ++++++ mkdocs.yml | 1 + modules/questdb/build.gradle | 13 +++ .../containers/QuestDBContainer.java | 88 +++++++++++++++++++ .../containers/QuestDBProvider.java | 14 +++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../org/testcontainers/QuestDBTestImages.java | 7 ++ .../jdbc/questdb/QuestDBJDBCDriverTest.java | 19 ++++ .../junit/questdb/SimpleQuestDBTest.java | 71 +++++++++++++++ 14 files changed, 253 insertions(+) create mode 100644 docs/modules/databases/questdb.md create mode 100644 modules/questdb/build.gradle create mode 100644 modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java create mode 100644 modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java create mode 100644 modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java create mode 100644 modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java create mode 100644 modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 8196451e88f..37609ce1424 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -41,6 +41,7 @@ body: - PostgreSQL - Presto - Pulsar + - QuestDB - RabbitMQ - Redpanda - Selenium diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 9d65e1f12b8..2bbca5db3ae 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -41,6 +41,7 @@ body: - PostgreSQL - Presto - Pulsar + - QuestDB - RabbitMQ - Redpanda - Selenium diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 581870d976d..d29d0178c39 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -39,6 +39,7 @@ body: - Oracle-XE - OrientDB - PostgreSQL + - QuestDB - Presto - Pulsar - RabbitMQ diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 46c7046300d..2e3afe8fa8a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -195,6 +195,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/questdb" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/r2dbc" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 85144b7d7f9..bda614305fa 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -65,6 +65,8 @@ - modules/presto/* "modules/pulsar": - modules/pulsar/* +"modules/questdb": + - modules/questdb/* "modules/r2dbc": - modules/r2dbc/* "modules/rabbitmq": diff --git a/docs/modules/databases/questdb.md b/docs/modules/databases/questdb.md new file mode 100644 index 00000000000..8783dd4b757 --- /dev/null +++ b/docs/modules/databases/questdb.md @@ -0,0 +1,29 @@ +# QuestDB Module + +Testcontainers module for [QuestDB](https://github.com/questdb/questdb). QuestDB is a high-performance, open-source SQL +database for applications in financial services, IoT, machine learning, DevOps and observability. + +See [Database containers](./index.md) for documentation and usage that is common to all relational database container +types. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + +```groovy +testImplementation "org.testcontainers:questdb:{{latest_version}}" +``` + +=== "Maven" + +```xml + + + org.testcontainers + questdb + {{latest_version}} + test + +``` diff --git a/mkdocs.yml b/mkdocs.yml index 70421761e02..8871267cace 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -63,6 +63,7 @@ nav: - modules/databases/orientdb.md - modules/databases/postgres.md - modules/databases/presto.md + - modules/databases/questdb.md - modules/databases/tidb.md - modules/databases/trino.md - modules/azure.md diff --git a/modules/questdb/build.gradle b/modules/questdb/build.gradle new file mode 100644 index 00000000000..79fc0793879 --- /dev/null +++ b/modules/questdb/build.gradle @@ -0,0 +1,13 @@ +description = "Testcontainers :: QuestDB" + +dependencies { + api project(':testcontainers') + api project(':jdbc') + + testImplementation 'org.postgresql:postgresql:42.5.0' + testImplementation project(':jdbc-test') + testImplementation 'org.assertj:assertj-core:3.23.1' + testImplementation 'org.questdb:questdb:6.4.3-jdk8' + testImplementation 'org.awaitility:awaitility:4.2.0' + testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' +} diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java new file mode 100644 index 00000000000..dd933dd6c95 --- /dev/null +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -0,0 +1,88 @@ +package org.testcontainers.containers; + +import lombok.NonNull; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +/** + * Testcontainers implementation for QuestDB. + * + * @author vangreen + * @author jerrinot + */ +public class QuestDBContainer extends JdbcDatabaseContainer { + + static final String DATABASE_PROVIDER = "postgresql"; + + private static final String DEFAULT_DATABASE_NAME = "qdb"; + + private static final int DEFAULT_COMMIT_LAG_MS = 1000; + + private static final String DEFAULT_USERNAME = "admin"; + + private static final String DEFAULT_PASSWORD = "quest"; + + private static final Integer POSTGRES_PORT = 8812; + + private static final Integer REST_PORT = 9000; + + private static final Integer ILP_PORT = 9009; + + static final String TEST_QUERY = "SELECT 1"; + + static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("questdb/questdb"); + + public QuestDBContainer(@NonNull String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public QuestDBContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(POSTGRES_PORT, REST_PORT, ILP_PORT); + addEnv("QDB_CAIRO_COMMIT_LAG", String.valueOf(DEFAULT_COMMIT_LAG_MS)); + waitingFor(Wait.forLogMessage("(?i).*A server-main enjoy.*", 1)); + } + + @Override + public String getDriverClassName() { + return "org.postgresql.Driver"; + } + + @Override + public String getJdbcUrl() { + return String.format("jdbc:postgresql://%s:%d/%s", getHost(), getMappedPort(8812), getDefaultDatabaseName()); + } + + @Override + public String getUsername() { + return DEFAULT_USERNAME; + } + + @Override + public String getPassword() { + return DEFAULT_PASSWORD; + } + + @Override + public String getTestQueryString() { + return TEST_QUERY; + } + + @Override + protected void waitUntilContainerStarted() { + getWaitStrategy().waitUntilReady(this); + } + + public String getDefaultDatabaseName() { + return DEFAULT_DATABASE_NAME; + } + + public String getIlpUrl() { + return getHost() + ":" + getMappedPort(ILP_PORT); + } + + public String getHttpUrl() { + return "http://" + getHost() + ":" + getMappedPort(REST_PORT); + } +} diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java new file mode 100644 index 00000000000..0d4e9c6eeeb --- /dev/null +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java @@ -0,0 +1,14 @@ +package org.testcontainers.containers; + +public class QuestDBProvider extends JdbcDatabaseContainerProvider { + + @Override + public boolean supports(String databaseType) { + return databaseType.equals(QuestDBContainer.DATABASE_PROVIDER); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new QuestDBContainer(QuestDBContainer.DEFAULT_IMAGE_NAME.withTag(tag)); + } +} diff --git a/modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..922a12a1328 --- /dev/null +++ b/modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.containers.QuestDBProvider diff --git a/modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java b/modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java new file mode 100644 index 00000000000..555b56f172c --- /dev/null +++ b/modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface QuestDBTestImages { + DockerImageName QUESTDB_IMAGE = DockerImageName.parse("questdb/questdb:6.5.3"); +} diff --git a/modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java b/modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java new file mode 100644 index 00000000000..b19c2acc5fd --- /dev/null +++ b/modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java @@ -0,0 +1,19 @@ +package org.testcontainers.jdbc.questdb; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.Arrays; +import java.util.EnumSet; + +@RunWith(Parameterized.class) +public class QuestDBJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return Arrays.asList( + new Object[][] { { "jdbc:tc:postgresql://hostname/databasename", EnumSet.of(Options.PmdKnownBroken) } } + ); + } +} diff --git a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java new file mode 100644 index 00000000000..c38524018c3 --- /dev/null +++ b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java @@ -0,0 +1,71 @@ +package org.testcontainers.junit.questdb; + +import io.questdb.client.Sender; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; +import org.testcontainers.QuestDBTestImages; +import org.testcontainers.containers.QuestDBContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class SimpleQuestDBTest extends AbstractContainerDatabaseTest { + + private static final String TABLE_NAME = "mytable"; + + @Test + public void testSimple() throws SQLException { + try (QuestDBContainer questDB = new QuestDBContainer(QuestDBTestImages.QUESTDB_IMAGE)) { + questDB.start(); + + ResultSet resultSet = performQuery(questDB, questDB.getTestQueryString()); + + int resultSetInt = resultSet.getInt(1); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + } + } + + @Test + public void testRest() throws IOException { + try (QuestDBContainer questdb = new QuestDBContainer(QuestDBTestImages.QUESTDB_IMAGE)) { + questdb.start(); + populateByInfluxLineProtocol(questdb, 1_000); + try (CloseableHttpClient client = HttpClientBuilder.create().build()) { + String encodedSql = URLEncoder.encode("select * from " + TABLE_NAME, "UTF-8"); + HttpGet httpGet = new HttpGet(questdb.getHttpUrl() + "/exec?query=" + encodedSql); + await() + .untilAsserted(() -> { + try (CloseableHttpResponse response = client.execute(httpGet)) { + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + assertThat(json.contains("\"count\":1000")).isTrue(); + } + }); + } + } + } + + private static void populateByInfluxLineProtocol(QuestDBContainer questdb, int rowCount) { + try (Sender sender = Sender.builder().address(questdb.getIlpUrl()).build()) { + for (int i = 0; i < rowCount; i++) { + sender + .table(TABLE_NAME) + .symbol("sym", "sym1" + i) + .stringColumn("str", "str1" + i) + .longColumn("long", i) + .atNow(); + } + } + } +} From 323ddc00e0db862e156c7a3e75e02be46c615c49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Oct 2022 16:50:10 +0000 Subject: [PATCH 2321/4969] Bump client-java from 16.0.0 to 16.0.1 in /modules/k3s Bumps [client-java](https://github.com/kubernetes-client/java) from 16.0.0 to 16.0.1. - [Release notes](https://github.com/kubernetes-client/java/releases) - [Changelog](https://github.com/kubernetes-client/java/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes-client/java/compare/v16.0.0...v16.0.1) --- updated-dependencies: - dependency-name: io.kubernetes:client-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/k3s/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index 0778419a3e2..e5fdb9f148b 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -9,6 +9,6 @@ dependencies { shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' testImplementation 'io.fabric8:kubernetes-client:6.1.1' - testImplementation 'io.kubernetes:client-java:16.0.0' + testImplementation 'io.kubernetes:client-java:16.0.1' testImplementation 'org.assertj:assertj-core:3.23.1' } From dc341029aeb226891070e7a3a8c0681bbc6ce8c1 Mon Sep 17 00:00:00 2001 From: DanielHabenicht Date: Fri, 21 Oct 2022 23:05:19 +0200 Subject: [PATCH 2322/4969] Fix edit link in documentation (#6055) Previously, the edit links always showed a 404 as the `master` branch is not used anymore. Now, the link is updated to use the current `main` branch. --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 8871267cace..e8f2a1918b0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -109,5 +109,6 @@ nav: - contributing.md - contributing_docs.md - bounty.md +edit_uri: edit/main/docs/ extra: latest_version: 1.17.5 From fa9b6b97fa76b2e951b8f8df8b559205a06c30e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Fri, 21 Oct 2022 17:53:45 -0500 Subject: [PATCH 2323/4969] Fix typo in tekton docs --- .../continuous_integration/tekton.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/continuous_integration/tekton.md b/docs/supported_docker_environment/continuous_integration/tekton.md index f8c6fb96adc..82c9f1d9a71 100644 --- a/docs/supported_docker_environment/continuous_integration/tekton.md +++ b/docs/supported_docker_environment/continuous_integration/tekton.md @@ -1,6 +1,6 @@ # Tekton -o enable access to Docker in Tekton, a dind sidecar needs to be added. An example of it can be found +To enable access to Docker in Tekton, a dind sidecar needs to be added. An example of it can be found [here](https://github.com/tektoncd/pipeline/blob/main/examples/v1beta1/taskruns/dind-sidecar.yaml) This is an example From 263282b52900746e00b338f40dc9d32b502c2690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 21 Oct 2022 18:58:00 -0500 Subject: [PATCH 2324/4969] Add travis minimal configuration (#6056) Fixes #4373 --- .../continuous_integration/travis.md | 14 +++++++++++++- mkdocs.yml | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/continuous_integration/travis.md b/docs/supported_docker_environment/continuous_integration/travis.md index 860c07f675d..f4ea31abaea 100644 --- a/docs/supported_docker_environment/continuous_integration/travis.md +++ b/docs/supported_docker_environment/continuous_integration/travis.md @@ -1,3 +1,15 @@ # Travis -> TODO +To run Testcontainers on TravisCI, docker needs to be installed. The configuration below +is the minimal required config. + +```yaml +language: java +jdk: +- openjdk8 + +services: +- docker + +script: ./mvnw verify +``` diff --git a/mkdocs.yml b/mkdocs.yml index e8f2a1918b0..47b000c89fb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -100,6 +100,7 @@ nav: - supported_docker_environment/continuous_integration/gitlab_ci.md - supported_docker_environment/continuous_integration/bitbucket_pipelines.md - supported_docker_environment/continuous_integration/tekton.md + - supported_docker_environment/continuous_integration/travis.md - supported_docker_environment/windows.md - supported_docker_environment/logging_config.md - supported_docker_environment/image_registry_rate_limiting.md From 77f71b855d7684930fde15d515d76a5840c2f00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 24 Oct 2022 10:23:32 -0500 Subject: [PATCH 2325/4969] Add support for flags in DatastoreEmulatorContainer (#5993) Datastore can start with additional flags such as `--consistency 1.0` which is recommended for testing. --- .../DatastoreEmulatorContainer.java | 23 +++++++++++-- .../DatastoreEmulatorContainerTest.java | 32 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java index b0716829875..db01001d5ec 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/DatastoreEmulatorContainer.java @@ -21,13 +21,32 @@ public class DatastoreEmulatorContainer extends GenericContainer e.contains("--consistency 1.0")); + assertThat(emulator.execInContainer("ls", "/root/.config/").getStdout()).contains("gcloud"); + } + } + + @Test + public void testWithMultipleFlags() throws IOException, InterruptedException { + try ( + DatastoreEmulatorContainer emulator = new DatastoreEmulatorContainer( + "gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators" + ) + .withFlags("--consistency 1.0 --data-dir /root/.config/test-gcloud") + ) { + emulator.start(); + + assertThat(emulator.getContainerInfo().getConfig().getCmd()).anyMatch(e -> e.contains("--consistency 1.0")); + assertThat(emulator.execInContainer("ls", "/root/.config/").getStdout()).contains("test-gcloud"); + } + } } From e97b58b65fcfca4628b996f3b120587346d19739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 25 Oct 2022 08:51:58 -0500 Subject: [PATCH 2326/4969] Update set-output command in workflows (#6058) `set-output` command has been deprecated and warning messages are printed within the logs. See more [here](https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/) --- .github/workflows/ci-examples.yml | 2 +- .github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-examples.yml b/.github/workflows/ci-examples.yml index 527c2eccfeb..425e9ebd970 100644 --- a/.github/workflows/ci-examples.yml +++ b/.github/workflows/ci-examples.yml @@ -39,7 +39,7 @@ jobs: run: | TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) echo $TASKS - echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" + echo "matrix={\"gradle_args\":$TASKS}" >> $GITHUB_OUTPUT check: needs: find_gradle_jobs strategy: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b406f256ae2..d240ca2ea79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: run: | TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) echo $TASKS - echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" + echo "matrix={\"gradle_args\":$TASKS}" >> $GITHUB_OUTPUT check: needs: [find_gradle_jobs] strategy: From 84b1ad4efd55d53c068328fa823c1b02390831b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 25 Oct 2022 08:52:40 -0500 Subject: [PATCH 2327/4969] Apply spotless and checkstyle to examples (#6061) Currently, spotless and checkstyle has been applied to the core modules. Now, both will execute to core modules and examples. --- build.gradle | 24 +---- examples/build.gradle | 11 +++ examples/cucumber/build.gradle | 1 + .../testcontainers/examples/CucumberTest.java | 7 +- .../org/testcontainers/examples/Stepdefs.java | 36 +++---- examples/immudb/src/test/java/ImmuDbTest.java | 20 ++-- .../kafkacluster/KafkaContainerCluster.java | 93 ++++++++++--------- .../KafkaContainerClusterTest.java | 54 ++++++----- .../linkedcontainer/RedmineClient.java | 5 +- .../linkedcontainer/RedmineClientTest.java | 21 +++-- .../linkedcontainer/RedmineContainer.java | 4 +- .../containers/Neo4jExampleTest.java | 28 +++--- .../main/java/com/mycompany/cache/Cache.java | 3 +- .../com/mycompany/cache/RedisBackedCache.java | 2 + .../src/test/java/RedisBackedCacheTest.java | 13 ++- .../main/java/com/mycompany/cache/Cache.java | 3 +- .../com/mycompany/cache/RedisBackedCache.java | 2 + .../src/test/java/RedisBackedCacheTest.java | 11 ++- .../java/com/example/DemoApplication.java | 1 - .../src/test/java/SeleniumContainerTest.java | 18 ++-- .../main/java/com/example/cache/Cache.java | 3 +- .../com/example/cache/RedisBackedCache.java | 2 + .../com/example/AbstractIntegrationTest.java | 2 +- .../com/example/BarConcreteTestClass.java | 5 +- .../com/example/FooConcreteTestClass.java | 4 +- .../main/java/com/example/SearchEngine.java | 1 - .../main/java/com/example/SearchResult.java | 6 +- .../java/com/example/SolrSearchEngine.java | 14 +-- .../test/java/com/example/SolrQueryTest.java | 48 ++++++---- .../java/com/example/DemoApplication.java | 7 +- .../main/java/com/example/DemoController.java | 1 + .../src/main/java/com/example/DemoEntity.java | 1 - .../main/java/com/example/DemoRepository.java | 4 +- .../main/java/com/example/DemoService.java | 5 +- .../com/example/AbstractIntegrationTest.java | 8 +- .../java/com/example/DemoControllerTest.java | 1 - gradle/spotless.gradle | 23 +++++ 37 files changed, 268 insertions(+), 224 deletions(-) create mode 100644 gradle/spotless.gradle diff --git a/build.gradle b/build.gradle index 9e6aa6020e4..7405154491b 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ subprojects { apply plugin: 'idea' apply plugin: 'io.franzbecker.gradle-lombok' apply from: "$rootDir/gradle/shading.gradle" - apply plugin: 'com.diffplug.spotless' + apply from: "$rootDir/gradle/spotless.gradle" apply plugin: 'checkstyle' apply plugin: 'org.gradle.test-retry' @@ -128,28 +128,6 @@ subprojects { testImplementation 'ch.qos.logback:logback-classic:1.3.3' } - spotless { - java { - toggleOffOn() - removeUnusedImports() - trimTrailingWhitespace() - endWithNewline() - - prettier(['prettier': '2.5.1', 'prettier-plugin-java': '1.6.1']) - .config([ - 'parser' : 'java', - 'tabWidth' : 4, - 'printWidth': 120 - ]) - - importOrder('', 'java', 'javax', '\\#') - } - groovyGradle { - target '**/*.groovy' - greclipse('4.19.0') - } - } - checkstyle { toolVersion = "9.3" configFile = rootProject.file('config/checkstyle/checkstyle.xml') diff --git a/examples/build.gradle b/examples/build.gradle index d340e297d33..b1c31a29c7f 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -1,10 +1,21 @@ // empty build.gradle for dependabot +plugins { + id 'com.diffplug.spotless' version '6.8.0' apply false +} + apply from: "$rootDir/../gradle/ci-support.gradle" subprojects { apply plugin:"java" + apply from: "$rootDir/../gradle/spotless.gradle" + apply plugin: 'checkstyle' repositories { mavenCentral() } + + checkstyle { + toolVersion = "9.3" + configFile = rootProject.file('../config/checkstyle/checkstyle.xml') + } } diff --git a/examples/cucumber/build.gradle b/examples/cucumber/build.gradle index 1b9fe04efd8..49dbd831cf5 100644 --- a/examples/cucumber/build.gradle +++ b/examples/cucumber/build.gradle @@ -13,4 +13,5 @@ dependencies { testImplementation 'io.cucumber:cucumber-java:7.8.0' testImplementation 'io.cucumber:cucumber-junit:7.8.0' testImplementation 'org.testcontainers:selenium' + testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/cucumber/src/test/java/org/testcontainers/examples/CucumberTest.java b/examples/cucumber/src/test/java/org/testcontainers/examples/CucumberTest.java index f55919c0fe6..717c42351a8 100644 --- a/examples/cucumber/src/test/java/org/testcontainers/examples/CucumberTest.java +++ b/examples/cucumber/src/test/java/org/testcontainers/examples/CucumberTest.java @@ -5,8 +5,5 @@ import org.junit.runner.RunWith; @RunWith(Cucumber.class) -@CucumberOptions(plugin = {"pretty"}) -public class CucumberTest { - - -} +@CucumberOptions(plugin = { "pretty" }) +public class CucumberTest {} diff --git a/examples/cucumber/src/test/java/org/testcontainers/examples/Stepdefs.java b/examples/cucumber/src/test/java/org/testcontainers/examples/Stepdefs.java index e1b9c7e81ef..1378100f959 100644 --- a/examples/cucumber/src/test/java/org/testcontainers/examples/Stepdefs.java +++ b/examples/cucumber/src/test/java/org/testcontainers/examples/Stepdefs.java @@ -10,22 +10,23 @@ import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode; import org.testcontainers.lifecycle.TestDescription; import java.io.File; import java.util.List; import java.util.Optional; -import static junit.framework.TestCase.assertEquals; -import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; +import static org.assertj.core.api.Assertions.assertThat; public class Stepdefs { private BrowserWebDriverContainer container = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, new File("build")); + .withCapabilities(new ChromeOptions()) + .withRecordingMode(VncRecordingMode.RECORD_ALL, new File("build")); private String location; + private String answer; @Before @@ -35,17 +36,20 @@ public void beforeScenario() { @After public void afterScenario(Scenario scenario) { - container.afterTest(new TestDescription() { - @Override - public String getTestId() { - return scenario.getId(); - } + container.afterTest( + new TestDescription() { + @Override + public String getTestId() { + return scenario.getId(); + } - @Override - public String getFilesystemFriendlyName() { - return scenario.getName(); - } - }, Optional.of(scenario).filter(Scenario::isFailed).map(__ -> new RuntimeException())); + @Override + public String getFilesystemFriendlyName() { + return scenario.getName(); + } + }, + Optional.of(scenario).filter(Scenario::isFailed).map(__ -> new RuntimeException()) + ); } @Given("^location is \"([^\"]*)\"$") @@ -63,8 +67,6 @@ public void iAskIsItPossibleToSearchHere() throws Exception { @Then("^I should be told \"([^\"]*)\"$") public void iShouldBeTold(String expected) throws Exception { - assertEquals(expected, answer); + assertThat(answer).isEqualTo(expected); } - - } diff --git a/examples/immudb/src/test/java/ImmuDbTest.java b/examples/immudb/src/test/java/ImmuDbTest.java index fd515ddd4aa..f8c208a1073 100644 --- a/examples/immudb/src/test/java/ImmuDbTest.java +++ b/examples/immudb/src/test/java/ImmuDbTest.java @@ -8,6 +8,7 @@ import org.junit.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -17,28 +18,33 @@ public class ImmuDbTest { // Default port for the ImmuDb server private static final int IMMUDB_PORT = 3322; + // Default username for the ImmuDb server private final String IMMUDB_USER = "immudb"; + // Default password for the ImmuDb server private final String IMMUDB_PASSWORD = "immudb"; + // Default database name for the ImmuDb server private final String IMMUDB_DATABASE = "defaultdb"; // Test container for the ImmuDb database, with the latest version of the image and exposed port @ClassRule public static final GenericContainer immuDbContainer = new GenericContainer<>("codenotary/immudb:1.3") - .withExposedPorts(IMMUDB_PORT).waitingFor( - Wait.forLogMessage(".*Web API server enabled.*", 1) - ); + .withExposedPorts(IMMUDB_PORT) + .waitingFor(Wait.forLogMessage(".*Web API server enabled.*", 1)); + // ImmuClient used to interact with the DB private ImmuClient immuClient; @Before public void setUp() { - this.immuClient = ImmuClient.newBuilder() - .withServerUrl(immuDbContainer.getHost()) - .withServerPort(immuDbContainer.getMappedPort(IMMUDB_PORT)) - .build(); + this.immuClient = + ImmuClient + .newBuilder() + .withServerUrl(immuDbContainer.getHost()) + .withServerPort(immuDbContainer.getMappedPort(IMMUDB_PORT)) + .build(); this.immuClient.login(IMMUDB_USER, IMMUDB_PASSWORD); this.immuClient.useDatabase(IMMUDB_DATABASE); } diff --git a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java index 398488fe3f9..9ab3f25e0ff 100644 --- a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java +++ b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerCluster.java @@ -4,10 +4,9 @@ import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.KafkaContainer; import org.testcontainers.containers.Network; import org.testcontainers.lifecycle.Startable; -import org.testcontainers.lifecycle.Startables; -import org.testcontainers.containers.KafkaContainer; import org.testcontainers.utility.DockerImageName; import java.time.Duration; @@ -17,16 +16,17 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -import static java.util.concurrent.TimeUnit.SECONDS; - /** * Provides an easy way to launch a Kafka cluster with multiple brokers. */ public class KafkaContainerCluster implements Startable { private final int brokersNum; + private final Network network; + private final GenericContainer zookeeper; + private final Collection brokers; public KafkaContainerCluster(String confluentPlatformVersion, int brokersNum, int internalTopicsRf) { @@ -34,33 +34,39 @@ public KafkaContainerCluster(String confluentPlatformVersion, int brokersNum, in throw new IllegalArgumentException("brokersNum '" + brokersNum + "' must be greater than 0"); } if (internalTopicsRf < 0 || internalTopicsRf > brokersNum) { - throw new IllegalArgumentException("internalTopicsRf '" + internalTopicsRf + "' must be less than brokersNum and greater than 0"); + throw new IllegalArgumentException( + "internalTopicsRf '" + internalTopicsRf + "' must be less than brokersNum and greater than 0" + ); } this.brokersNum = brokersNum; this.network = Network.newNetwork(); - this.zookeeper = new GenericContainer<>(DockerImageName.parse("confluentinc/cp-zookeeper").withTag(confluentPlatformVersion)) - .withNetwork(network) - .withNetworkAliases("zookeeper") - .withEnv("ZOOKEEPER_CLIENT_PORT", String.valueOf(KafkaContainer.ZOOKEEPER_PORT)); - - this.brokers = IntStream - .range(0, this.brokersNum) - .mapToObj(brokerNum -> { - return new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka").withTag(confluentPlatformVersion)) - .withNetwork(this.network) - .withNetworkAliases("broker-" + brokerNum) - .dependsOn(this.zookeeper) - .withExternalZookeeper("zookeeper:" + KafkaContainer.ZOOKEEPER_PORT) - .withEnv("KAFKA_BROKER_ID", brokerNum + "") - .withEnv("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR", internalTopicsRf + "") - .withEnv("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS", internalTopicsRf + "") - .withEnv("KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR", internalTopicsRf + "") - .withEnv("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR", internalTopicsRf + "") - .withStartupTimeout(Duration.ofMinutes(1)); - }) - .collect(Collectors.toList()); + this.zookeeper = + new GenericContainer<>(DockerImageName.parse("confluentinc/cp-zookeeper").withTag(confluentPlatformVersion)) + .withNetwork(network) + .withNetworkAliases("zookeeper") + .withEnv("ZOOKEEPER_CLIENT_PORT", String.valueOf(KafkaContainer.ZOOKEEPER_PORT)); + + this.brokers = + IntStream + .range(0, this.brokersNum) + .mapToObj(brokerNum -> { + return new KafkaContainer( + DockerImageName.parse("confluentinc/cp-kafka").withTag(confluentPlatformVersion) + ) + .withNetwork(this.network) + .withNetworkAliases("broker-" + brokerNum) + .dependsOn(this.zookeeper) + .withExternalZookeeper("zookeeper:" + KafkaContainer.ZOOKEEPER_PORT) + .withEnv("KAFKA_BROKER_ID", brokerNum + "") + .withEnv("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR", internalTopicsRf + "") + .withEnv("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS", internalTopicsRf + "") + .withEnv("KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR", internalTopicsRf + "") + .withEnv("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR", internalTopicsRf + "") + .withStartupTimeout(Duration.ofMinutes(1)); + }) + .collect(Collectors.toList()); } public Collection getBrokers() { @@ -68,16 +74,11 @@ public Collection getBrokers() { } public String getBootstrapServers() { - return brokers.stream() - .map(KafkaContainer::getBootstrapServers) - .collect(Collectors.joining(",")); + return brokers.stream().map(KafkaContainer::getBootstrapServers).collect(Collectors.joining(",")); } private Stream> allContainers() { - return Stream.concat( - this.brokers.stream(), - Stream.of(this.zookeeper) - ); + return Stream.concat(this.brokers.stream(), Stream.of(this.zookeeper)); } @Override @@ -86,15 +87,23 @@ public void start() { // sequential start to avoid resource contention on CI systems with weaker hardware brokers.forEach(GenericContainer::start); - Unreliables.retryUntilTrue(30, TimeUnit.SECONDS, () -> { - Container.ExecResult result = this.zookeeper.execInContainer( - "sh", "-c", - "zookeeper-shell zookeeper:" + KafkaContainer.ZOOKEEPER_PORT + " ls /brokers/ids | tail -n 1" - ); - String brokers = result.getStdout(); - - return brokers != null && brokers.split(",").length == this.brokersNum; - }); + Unreliables.retryUntilTrue( + 30, + TimeUnit.SECONDS, + () -> { + Container.ExecResult result = + this.zookeeper.execInContainer( + "sh", + "-c", + "zookeeper-shell zookeeper:" + + KafkaContainer.ZOOKEEPER_PORT + + " ls /brokers/ids | tail -n 1" + ); + String brokers = result.getStdout(); + + return brokers != null && brokers.split(",").length == this.brokersNum; + } + ); } @Override diff --git a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java index a431c14bba3..63253f4b309 100644 --- a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java +++ b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java @@ -29,9 +29,7 @@ public class KafkaContainerClusterTest { @Test public void testKafkaContainerCluster() throws Exception { - try ( - KafkaContainerCluster cluster = new KafkaContainerCluster("6.2.1", 3, 2) - ) { + try (KafkaContainerCluster cluster = new KafkaContainerCluster("6.2.1", 3, 2)) { cluster.start(); String bootstrapServers = cluster.getBootstrapServers(); @@ -43,24 +41,27 @@ public void testKafkaContainerCluster() throws Exception { protected void testKafkaFunctionality(String bootstrapServers, int partitions, int rf) throws Exception { try ( - AdminClient adminClient = AdminClient.create(ImmutableMap.of( - AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers - )); - + AdminClient adminClient = AdminClient.create( + ImmutableMap.of(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers) + ); KafkaProducer producer = new KafkaProducer<>( ImmutableMap.of( - ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, - ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString() + ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ProducerConfig.CLIENT_ID_CONFIG, + UUID.randomUUID().toString() ), new StringSerializer(), new StringSerializer() ); - KafkaConsumer consumer = new KafkaConsumer<>( ImmutableMap.of( - ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, - ConsumerConfig.GROUP_ID_CONFIG, "tc-" + UUID.randomUUID(), - ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest" + ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ConsumerConfig.GROUP_ID_CONFIG, + "tc-" + UUID.randomUUID(), + ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, + "earliest" ), new StringDeserializer(), new StringDeserializer() @@ -75,23 +76,26 @@ protected void testKafkaFunctionality(String bootstrapServers, int partitions, i producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); - Unreliables.retryUntilTrue(10, TimeUnit.SECONDS, () -> { - ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + Unreliables.retryUntilTrue( + 10, + TimeUnit.SECONDS, + () -> { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); - if (records.isEmpty()) { - return false; - } + if (records.isEmpty()) { + return false; + } - assertThat(records) - .hasSize(1) - .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) - .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + assertThat(records) + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); - return true; - }); + return true; + } + ); consumer.unsubscribe(); } } - } diff --git a/examples/linked-container/src/main/java/com/example/linkedcontainer/RedmineClient.java b/examples/linked-container/src/main/java/com/example/linkedcontainer/RedmineClient.java index be62d932971..c95ec133e2f 100644 --- a/examples/linked-container/src/main/java/com/example/linkedcontainer/RedmineClient.java +++ b/examples/linked-container/src/main/java/com/example/linkedcontainer/RedmineClient.java @@ -13,6 +13,7 @@ public class RedmineClient { private String url; + private OkHttpClient client; public RedmineClient(String url) { @@ -21,9 +22,7 @@ public RedmineClient(String url) { } public int getIssueCount() throws IOException { - Request request = new Request.Builder() - .url(url + "/issues.json") - .build(); + Request request = new Request.Builder().url(url + "/issues.json").build(); Response response = client.newCall(request).execute(); JSONObject jsonObject = new JSONObject(response.body().string()); diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java index 6e4186698e7..721c00835c9 100644 --- a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineClientTest.java @@ -13,25 +13,26 @@ public class RedmineClientTest { private static final String POSTGRES_USERNAME = "redmine"; + private static final String POSTGRES_PASSWORD = "secret"; - private PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer<>(LinkedContainerTestImages.POSTGRES_TEST_IMAGE) - .withUsername(POSTGRES_USERNAME) - .withPassword(POSTGRES_PASSWORD); + private PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer<>( + LinkedContainerTestImages.POSTGRES_TEST_IMAGE + ) + .withUsername(POSTGRES_USERNAME) + .withPassword(POSTGRES_PASSWORD); private RedmineContainer redmineContainer = new RedmineContainer(LinkedContainerTestImages.REDMINE_TEST_IMAGE) - .withLinkToContainer(postgreSQLContainer, "postgres") - .withEnv("POSTGRES_ENV_POSTGRES_USER", POSTGRES_USERNAME) - .withEnv("POSTGRES_ENV_POSTGRES_PASSWORD", POSTGRES_PASSWORD); + .withLinkToContainer(postgreSQLContainer, "postgres") + .withEnv("POSTGRES_ENV_POSTGRES_USER", POSTGRES_USERNAME) + .withEnv("POSTGRES_ENV_POSTGRES_PASSWORD", POSTGRES_PASSWORD); @Rule - public RuleChain chain = RuleChain.outerRule(postgreSQLContainer) - .around(redmineContainer); + public RuleChain chain = RuleChain.outerRule(postgreSQLContainer).around(redmineContainer); @Test public void canGetIssueCount() throws Exception { - RedmineClient redmineClient = new RedmineClient( - redmineContainer.getRedmineUrl()); + RedmineClient redmineClient = new RedmineClient(redmineContainer.getRedmineUrl()); assertThat(redmineClient.getIssueCount()).as("The issue count can be retrieved.").isZero(); } diff --git a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java index 4303bbee682..0f0bea36c1a 100644 --- a/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java +++ b/examples/linked-container/src/test/java/com/example/linkedcontainer/RedmineContainer.java @@ -28,8 +28,6 @@ public RedmineContainer withLinkToContainer(LinkableContainer otherContainer, St } public String getRedmineUrl() { - return String.format("http://%s:%d", - this.getHost(), - this.getMappedPort(REDMINE_PORT)); + return String.format("http://%s:%d", this.getHost(), this.getMappedPort(REDMINE_PORT)); } } diff --git a/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java index bc7aeed10bd..9ce3a3f078c 100644 --- a/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java +++ b/examples/neo4j-container/src/test/java/org/testcontainers/containers/Neo4jExampleTest.java @@ -1,5 +1,14 @@ package org.testcontainers.containers; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Session; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -10,15 +19,6 @@ import java.util.Collections; import java.util.stream.Collectors; -import org.junit.jupiter.api.Test; -import org.neo4j.driver.AuthTokens; -import org.neo4j.driver.Driver; -import org.neo4j.driver.GraphDatabase; -import org.neo4j.driver.Session; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -27,19 +27,14 @@ class Neo4jExampleTest { @Container - private static Neo4jContainer neo4jContainer = - new Neo4jContainer<>(DockerImageName.parse("neo4j:4.4")) + private static Neo4jContainer neo4jContainer = new Neo4jContainer<>(DockerImageName.parse("neo4j:4.4")) .withAdminPassword(null); // Disable password @Test void testSomethingUsingBolt() { - // Retrieve the Bolt URL from the container String boltUrl = neo4jContainer.getBoltUrl(); - try ( - Driver driver = GraphDatabase.driver(boltUrl, AuthTokens.none()); - Session session = driver.session() - ) { + try (Driver driver = GraphDatabase.driver(boltUrl, AuthTokens.none()); Session session = driver.session()) { long one = session.run("RETURN 1", Collections.emptyMap()).next().get(0).asLong(); assertThat(one).isEqualTo(1L); } catch (Exception e) { @@ -49,7 +44,6 @@ void testSomethingUsingBolt() { @Test void testSomethingUsingHttp() throws IOException { - // Retrieve the HTTP URL from the container String httpUrl = neo4jContainer.getHttpUrl(); diff --git a/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/Cache.java b/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/Cache.java index 996c31ecac7..f0c7710b355 100644 --- a/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/Cache.java +++ b/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/Cache.java @@ -6,7 +6,6 @@ * Cache, for storing data associated with keys. */ public interface Cache { - /** * Store a value object in the cache with no specific expiry time. The object may be evicted by the cache any time, * if necessary. @@ -24,4 +23,4 @@ public interface Cache { * @return the object if it was in the cache, or an empty Optional if not found. */ Optional get(String key, Class expectedClass); -} \ No newline at end of file +} diff --git a/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/RedisBackedCache.java b/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/RedisBackedCache.java index 2c80818c150..8349de77869 100644 --- a/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/RedisBackedCache.java +++ b/examples/redis-backed-cache-testng/src/main/java/com/mycompany/cache/RedisBackedCache.java @@ -11,7 +11,9 @@ public class RedisBackedCache implements Cache { private final Jedis jedis; + private final String cacheName; + private final Gson gson; public RedisBackedCache(Jedis jedis, String cacheName) { diff --git a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java index e02b271f290..45c482c098e 100644 --- a/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache-testng/src/test/java/RedisBackedCacheTest.java @@ -17,13 +17,14 @@ */ public class RedisBackedCacheTest { - private static GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3.0.6")).withExposedPorts(6379); + private static GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3.0.6")) + .withExposedPorts(6379); private Cache cache; @BeforeClass public static void startContainer() { - redis.start(); + redis.start(); } @AfterClass @@ -44,13 +45,17 @@ public void testFindingAnInsertedValue() { Optional foundObject = cache.get("foo", String.class); assertThat(foundObject).as("When an object in the cache is retrieved, it can be found").isPresent(); - assertThat(foundObject).as("When we put a String in to the cache and retrieve it, the value is the same").contains("FOO"); + assertThat(foundObject) + .as("When we put a String in to the cache and retrieve it, the value is the same") + .contains("FOO"); } @Test public void testNotFindingAValueThatWasNotInserted() { Optional foundObject = cache.get("bar", String.class); - assertThat(foundObject).as("When an object that's not in the cache is retrieved, nothing is found").isNotPresent(); + assertThat(foundObject) + .as("When an object that's not in the cache is retrieved, nothing is found") + .isNotPresent(); } } diff --git a/examples/redis-backed-cache/src/main/java/com/mycompany/cache/Cache.java b/examples/redis-backed-cache/src/main/java/com/mycompany/cache/Cache.java index 996c31ecac7..f0c7710b355 100644 --- a/examples/redis-backed-cache/src/main/java/com/mycompany/cache/Cache.java +++ b/examples/redis-backed-cache/src/main/java/com/mycompany/cache/Cache.java @@ -6,7 +6,6 @@ * Cache, for storing data associated with keys. */ public interface Cache { - /** * Store a value object in the cache with no specific expiry time. The object may be evicted by the cache any time, * if necessary. @@ -24,4 +23,4 @@ public interface Cache { * @return the object if it was in the cache, or an empty Optional if not found. */ Optional get(String key, Class expectedClass); -} \ No newline at end of file +} diff --git a/examples/redis-backed-cache/src/main/java/com/mycompany/cache/RedisBackedCache.java b/examples/redis-backed-cache/src/main/java/com/mycompany/cache/RedisBackedCache.java index 2c80818c150..8349de77869 100644 --- a/examples/redis-backed-cache/src/main/java/com/mycompany/cache/RedisBackedCache.java +++ b/examples/redis-backed-cache/src/main/java/com/mycompany/cache/RedisBackedCache.java @@ -11,7 +11,9 @@ public class RedisBackedCache implements Cache { private final Jedis jedis; + private final String cacheName; + private final Gson gson; public RedisBackedCache(Jedis jedis, String cacheName) { diff --git a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java index 24a21723b15..e820646a0da 100644 --- a/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java +++ b/examples/redis-backed-cache/src/test/java/RedisBackedCacheTest.java @@ -18,7 +18,8 @@ public class RedisBackedCacheTest { @Rule public GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3.0.6")) - .withExposedPorts(6379); + .withExposedPorts(6379); + private Cache cache; @Before @@ -34,13 +35,17 @@ public void testFindingAnInsertedValue() { Optional foundObject = cache.get("foo", String.class); assertThat(foundObject.isPresent()).as("When an object in the cache is retrieved, it can be found").isTrue(); - assertThat(foundObject.get()).as("When we put a String in to the cache and retrieve it, the value is the same").isEqualTo("FOO"); + assertThat(foundObject.get()) + .as("When we put a String in to the cache and retrieve it, the value is the same") + .isEqualTo("FOO"); } @Test public void testNotFindingAValueThatWasNotInserted() { Optional foundObject = cache.get("bar", String.class); - assertThat(foundObject.isPresent()).as("When an object that's not in the cache is retrieved, nothing is found").isFalse(); + assertThat(foundObject.isPresent()) + .as("When an object that's not in the cache is retrieved, nothing is found") + .isFalse(); } } diff --git a/examples/selenium-container/src/main/java/com/example/DemoApplication.java b/examples/selenium-container/src/main/java/com/example/DemoApplication.java index 909a1ec36e1..6c42baef27d 100644 --- a/examples/selenium-container/src/main/java/com/example/DemoApplication.java +++ b/examples/selenium-container/src/main/java/com/example/DemoApplication.java @@ -9,5 +9,4 @@ public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } - } diff --git a/examples/selenium-container/src/test/java/SeleniumContainerTest.java b/examples/selenium-container/src/test/java/SeleniumContainerTest.java index c28c9bc54cb..52871c4f37e 100644 --- a/examples/selenium-container/src/test/java/SeleniumContainerTest.java +++ b/examples/selenium-container/src/test/java/SeleniumContainerTest.java @@ -7,8 +7,8 @@ import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; @@ -16,12 +16,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.testcontainers.Testcontainers; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode; import java.io.File; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; /** * Simple example of plain Selenium usage. @@ -36,8 +36,8 @@ public class SeleniumContainerTest { @Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() - .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, new File("build")); + .withCapabilities(new ChromeOptions()) + .withRecordingMode(VncRecordingMode.RECORD_ALL, new File("build")); @Test public void simplePlainSeleniumTest() { @@ -50,12 +50,14 @@ public void simplePlainSeleniumTest() { } public static class Initializer implements ApplicationContextInitializer { + @Override public void initialize(ConfigurableApplicationContext applicationContext) { - applicationContext.addApplicationListener((ApplicationListener) event -> { - Testcontainers.exposeHostPorts(event.getWebServer().getPort()); - }); + applicationContext.addApplicationListener( + (ApplicationListener) event -> { + Testcontainers.exposeHostPorts(event.getWebServer().getPort()); + } + ); } } - } diff --git a/examples/singleton-container/src/main/java/com/example/cache/Cache.java b/examples/singleton-container/src/main/java/com/example/cache/Cache.java index 986838d20f9..8a0c5776d80 100644 --- a/examples/singleton-container/src/main/java/com/example/cache/Cache.java +++ b/examples/singleton-container/src/main/java/com/example/cache/Cache.java @@ -3,8 +3,7 @@ import java.util.Optional; public interface Cache { - void put(String key, Object value); Optional get(String key, Class expectedClass); -} \ No newline at end of file +} diff --git a/examples/singleton-container/src/main/java/com/example/cache/RedisBackedCache.java b/examples/singleton-container/src/main/java/com/example/cache/RedisBackedCache.java index 34553dde1f4..430afb2b1f5 100644 --- a/examples/singleton-container/src/main/java/com/example/cache/RedisBackedCache.java +++ b/examples/singleton-container/src/main/java/com/example/cache/RedisBackedCache.java @@ -8,7 +8,9 @@ public class RedisBackedCache implements Cache { private final Jedis jedis; + private final String cacheName; + private final Gson gson; public RedisBackedCache(Jedis jedis, String cacheName) { diff --git a/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java b/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java index d152540fb1c..729e9fb124d 100644 --- a/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java +++ b/examples/singleton-container/src/test/java/com/example/AbstractIntegrationTest.java @@ -6,7 +6,7 @@ public abstract class AbstractIntegrationTest { public static final GenericContainer redis = new GenericContainer<>(DockerImageName.parse("redis:3.0.6")) - .withExposedPorts(6379); + .withExposedPorts(6379); static { redis.start(); diff --git a/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java b/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java index fff6e1a4a3a..6b9050be277 100644 --- a/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java +++ b/examples/singleton-container/src/test/java/com/example/BarConcreteTestClass.java @@ -27,7 +27,8 @@ public void testInsertValue() { Optional foundObject = cache.get("bar", String.class); assertThat(foundObject).as("When inserting an object into the cache, it can be retrieved").isPresent(); - assertThat(foundObject).as("When accessing the value of a retrieved object, the value must be the same").contains("BAR"); + assertThat(foundObject) + .as("When accessing the value of a retrieved object, the value must be the same") + .contains("BAR"); } - } diff --git a/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java b/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java index 11ad98a0580..ea071202dcd 100644 --- a/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java +++ b/examples/singleton-container/src/test/java/com/example/FooConcreteTestClass.java @@ -27,6 +27,8 @@ public void testInsertValue() { Optional foundObject = cache.get("foo", String.class); assertThat(foundObject).as("When inserting an object into the cache, it can be retrieved").isPresent(); - assertThat(foundObject).as("When accessing the value of a retrieved object, the value must be the same").contains("FOO"); + assertThat(foundObject) + .as("When accessing the value of a retrieved object, the value must be the same") + .contains("FOO"); } } diff --git a/examples/solr-container/src/main/java/com/example/SearchEngine.java b/examples/solr-container/src/main/java/com/example/SearchEngine.java index c05bc23aad2..397327fe369 100644 --- a/examples/solr-container/src/main/java/com/example/SearchEngine.java +++ b/examples/solr-container/src/main/java/com/example/SearchEngine.java @@ -1,6 +1,5 @@ package com.example; public interface SearchEngine { - public SearchResult search(String term); } diff --git a/examples/solr-container/src/main/java/com/example/SearchResult.java b/examples/solr-container/src/main/java/com/example/SearchResult.java index 06544f0ba34..89722d1a5a4 100644 --- a/examples/solr-container/src/main/java/com/example/SearchResult.java +++ b/examples/solr-container/src/main/java/com/example/SearchResult.java @@ -1,13 +1,13 @@ package com.example; -import java.util.List; -import java.util.Map; - import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; +import java.util.Map; + @Data @Builder @NoArgsConstructor diff --git a/examples/solr-container/src/main/java/com/example/SolrSearchEngine.java b/examples/solr-container/src/main/java/com/example/SolrSearchEngine.java index 8a7f38e455d..3be96f76690 100644 --- a/examples/solr-container/src/main/java/com/example/SolrSearchEngine.java +++ b/examples/solr-container/src/main/java/com/example/SolrSearchEngine.java @@ -1,16 +1,15 @@ package com.example; -import java.util.stream.Collectors; - import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; - import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.client.solrj.util.ClientUtils; import org.apache.solr.common.SolrDocument; +import java.util.stream.Collectors; + @RequiredArgsConstructor public class SolrSearchEngine implements SearchEngine { @@ -20,7 +19,6 @@ public class SolrSearchEngine implements SearchEngine { @SneakyThrows public SearchResult search(String term) { - SolrQuery query = new SolrQuery(); query.setQuery("title:" + ClientUtils.escapeQueryChars(term)); QueryResponse response = client.query(COLLECTION_NAME, query); @@ -28,12 +26,10 @@ public SearchResult search(String term) { } private SearchResult createResult(QueryResponse response) { - return SearchResult.builder() + return SearchResult + .builder() .totalHits(response.getResults().getNumFound()) - .results(response.getResults() - .stream() - .map(SolrDocument::getFieldValueMap) - .collect(Collectors.toList())) + .results(response.getResults().stream().map(SolrDocument::getFieldValueMap).collect(Collectors.toList())) .build(); } } diff --git a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java index 6443a19b869..e65504c0276 100644 --- a/examples/solr-container/src/test/java/com/example/SolrQueryTest.java +++ b/examples/solr-container/src/test/java/com/example/SolrQueryTest.java @@ -15,7 +15,6 @@ import java.util.HashMap; import java.util.Map; -import static com.example.SolrSearchEngine.COLLECTION_NAME; import static org.assertj.core.api.Assertions.assertThat; public class SolrQueryTest { @@ -23,31 +22,44 @@ public class SolrQueryTest { private static final DockerImageName SOLR_IMAGE = DockerImageName.parse("solr:8.3.0"); public static final SolrContainer solrContainer = new SolrContainer(SOLR_IMAGE) - .withCollection(COLLECTION_NAME); + .withCollection(SolrSearchEngine.COLLECTION_NAME); private static SolrClient solrClient; @BeforeClass public static void setUp() throws IOException, SolrServerException { solrContainer.start(); - solrClient = new Http2SolrClient.Builder("http://" + solrContainer.getHost() + ":" + solrContainer.getSolrPort() + "/solr").build(); + solrClient = + new Http2SolrClient.Builder( + "http://" + solrContainer.getHost() + ":" + solrContainer.getSolrPort() + "/solr" + ) + .build(); // Add Sample Data - solrClient.add(COLLECTION_NAME, Collections.singletonList( - new SolrInputDocument(createMap( - "id", createInputField("id", "1"), - "title", createInputField("title", "old skool - trainers - shoes") - )) - )); - - solrClient.add(COLLECTION_NAME, Collections.singletonList( - new SolrInputDocument(createMap( - "id", createInputField("id", "2"), - "title", createInputField("title", "print t-shirt") - )) - )); - - solrClient.commit(COLLECTION_NAME); + solrClient.add( + SolrSearchEngine.COLLECTION_NAME, + Collections.singletonList( + new SolrInputDocument( + createMap( + "id", + createInputField("id", "1"), + "title", + createInputField("title", "old skool - trainers - shoes") + ) + ) + ) + ); + + solrClient.add( + SolrSearchEngine.COLLECTION_NAME, + Collections.singletonList( + new SolrInputDocument( + createMap("id", createInputField("id", "2"), "title", createInputField("title", "print t-shirt")) + ) + ) + ); + + solrClient.commit(SolrSearchEngine.COLLECTION_NAME); } @Test diff --git a/examples/spring-boot/src/main/java/com/example/DemoApplication.java b/examples/spring-boot/src/main/java/com/example/DemoApplication.java index c968eb42b78..af96419ad6a 100644 --- a/examples/spring-boot/src/main/java/com/example/DemoApplication.java +++ b/examples/spring-boot/src/main/java/com/example/DemoApplication.java @@ -8,8 +8,7 @@ @EnableJpaRepositories public class DemoApplication { - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } - + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } } diff --git a/examples/spring-boot/src/main/java/com/example/DemoController.java b/examples/spring-boot/src/main/java/com/example/DemoController.java index 79f48711cad..90cea36804e 100644 --- a/examples/spring-boot/src/main/java/com/example/DemoController.java +++ b/examples/spring-boot/src/main/java/com/example/DemoController.java @@ -7,6 +7,7 @@ public class DemoController { private final StringRedisTemplate stringRedisTemplate; + private final DemoService demoService; public DemoController(StringRedisTemplate stringRedisTemplate, DemoService demoService) { diff --git a/examples/spring-boot/src/main/java/com/example/DemoEntity.java b/examples/spring-boot/src/main/java/com/example/DemoEntity.java index 47c0fa94f75..71fceb2c8e8 100644 --- a/examples/spring-boot/src/main/java/com/example/DemoEntity.java +++ b/examples/spring-boot/src/main/java/com/example/DemoEntity.java @@ -7,7 +7,6 @@ import javax.persistence.GeneratedValue; import javax.persistence.Id; - @Data @Entity public class DemoEntity { diff --git a/examples/spring-boot/src/main/java/com/example/DemoRepository.java b/examples/spring-boot/src/main/java/com/example/DemoRepository.java index 89f3775deb0..8ed3216cc18 100644 --- a/examples/spring-boot/src/main/java/com/example/DemoRepository.java +++ b/examples/spring-boot/src/main/java/com/example/DemoRepository.java @@ -1,7 +1,5 @@ package com.example; - import org.springframework.data.jpa.repository.JpaRepository; -public interface DemoRepository extends JpaRepository { -} +public interface DemoRepository extends JpaRepository {} diff --git a/examples/spring-boot/src/main/java/com/example/DemoService.java b/examples/spring-boot/src/main/java/com/example/DemoService.java index 18e8690a99f..78e8c41e907 100644 --- a/examples/spring-boot/src/main/java/com/example/DemoService.java +++ b/examples/spring-boot/src/main/java/com/example/DemoService.java @@ -4,15 +4,14 @@ @Service public class DemoService { + private final DemoRepository demoRepository; public DemoService(DemoRepository demoRepository) { this.demoRepository = demoRepository; } - public DemoEntity getDemoEntity(Long id) { - return demoRepository.findById(id) - .orElseThrow(() ->new RuntimeException("Entity not found")); + return demoRepository.findById(id).orElseThrow(() -> new RuntimeException("Entity not found")); } } diff --git a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java index dd1b7b6fb5a..8a1a508c0b3 100644 --- a/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java +++ b/examples/spring-boot/src/test/java/com/example/AbstractIntegrationTest.java @@ -11,9 +11,11 @@ import org.testcontainers.utility.DockerImageName; @RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT, properties = { - "spring.datasource.url=jdbc:tc:postgresql:11-alpine:///databasename", -}) +@SpringBootTest( + classes = DemoApplication.class, + webEnvironment = WebEnvironment.RANDOM_PORT, + properties = { "spring.datasource.url=jdbc:tc:postgresql:11-alpine:///databasename" } +) @ActiveProfiles("test") public abstract class AbstractIntegrationTest { diff --git a/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java b/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java index c305ae67811..4282920b37c 100644 --- a/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java +++ b/examples/spring-boot/src/test/java/com/example/DemoControllerTest.java @@ -33,5 +33,4 @@ public void simpleJPATest() { assertThat(result.getValue()).as("value is set").isEqualTo("Some value"); } - } diff --git a/gradle/spotless.gradle b/gradle/spotless.gradle new file mode 100644 index 00000000000..ce71829331e --- /dev/null +++ b/gradle/spotless.gradle @@ -0,0 +1,23 @@ +apply plugin: 'com.diffplug.spotless' + +spotless { + java { + toggleOffOn() + removeUnusedImports() + trimTrailingWhitespace() + endWithNewline() + + prettier(['prettier': '2.5.1', 'prettier-plugin-java': '1.6.1']) + .config([ + 'parser' : 'java', + 'tabWidth' : 4, + 'printWidth': 120 + ]) + + importOrder('', 'java', 'javax', '\\#') + } + groovyGradle { + target '**/*.groovy' + greclipse('4.19.0') + } +} From b9f48abdee62fea8e94ca39ff5f18016646be9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 25 Oct 2022 10:23:05 -0500 Subject: [PATCH 2328/4969] Add zookeeper example (#6059) Demonstrate how to use Apache Zookeeper along with `GenericContainer`. Fixes #1514 --- docs/examples.md | 1 + examples/settings.gradle | 1 + examples/zookeeper/build.gradle | 14 +++++++ .../com/example/ZookeeperContainerTest.java | 41 +++++++++++++++++++ .../src/test/resources/logback-test.xml | 16 ++++++++ 5 files changed, 73 insertions(+) create mode 100644 examples/zookeeper/build.gradle create mode 100644 examples/zookeeper/src/test/java/com/example/ZookeeperContainerTest.java create mode 100644 examples/zookeeper/src/test/resources/logback-test.xml diff --git a/docs/examples.md b/docs/examples.md index e7578c8b375..b7b96ee52bb 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -14,3 +14,4 @@ Examples of different use cases provided by Testcontainers can be found below: - [Spring Boot with Kotlin](https://github.com/testcontainers/testcontainers-java/tree/main/examples/spring-boot-kotlin-redis) - [TestNG](https://github.com/testcontainers/testcontainers-java/tree/main/examples/redis-backed-cache-testng) - [ImmuDb](https://github.com/testcontainers/testcontainers-java/tree/main/examples/immudb) +- [Zookeeper](https://github.com/testcontainers/testcontainers-java/tree/main/examples/zookeper) diff --git a/examples/settings.gradle b/examples/settings.gradle index d26ecef5a98..35b79454204 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -31,6 +31,7 @@ include 'spring-boot' include 'cucumber' include 'spring-boot-kotlin-redis' include 'immudb' +include 'zookeeper' ext.isCI = System.getenv("CI") != null diff --git a/examples/zookeeper/build.gradle b/examples/zookeeper/build.gradle new file mode 100644 index 00000000000..f2c92eb3b1d --- /dev/null +++ b/examples/zookeeper/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.apache.curator:curator-framework:5.3.0' + testImplementation 'org.testcontainers:testcontainers' + testImplementation 'org.assertj:assertj-core:3.23.1' + testImplementation 'ch.qos.logback:logback-classic:1.2.11' +} diff --git a/examples/zookeeper/src/test/java/com/example/ZookeeperContainerTest.java b/examples/zookeeper/src/test/java/com/example/ZookeeperContainerTest.java new file mode 100644 index 00000000000..a8aad36d201 --- /dev/null +++ b/examples/zookeeper/src/test/java/com/example/ZookeeperContainerTest.java @@ -0,0 +1,41 @@ +package com.example; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.RetryOneTime; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; + +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ZookeeperContainerTest { + + private static final int ZOOKEEPER_PORT = 2181; + + @Test + public void test() throws Exception { + String path = "/messages/zk-tc"; + String content = "Running Zookeeper with Testcontainers"; + try ( + GenericContainer zookeeper = new GenericContainer<>("zookeeper:3.8.0").withExposedPorts(ZOOKEEPER_PORT) + ) { + zookeeper.start(); + + String connectionString = zookeeper.getHost() + ":" + zookeeper.getMappedPort(ZOOKEEPER_PORT); + CuratorFramework curatorFramework = CuratorFrameworkFactory + .builder() + .connectString(connectionString) + .retryPolicy(new RetryOneTime(100)) + .build(); + curatorFramework.start(); + curatorFramework.create().creatingParentsIfNeeded().forPath(path, content.getBytes()); + + byte[] bytes = curatorFramework.getData().forPath(path); + curatorFramework.close(); + + assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(content); + } + } +} diff --git a/examples/zookeeper/src/test/resources/logback-test.xml b/examples/zookeeper/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/examples/zookeeper/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 0b617b4247f098ad538b58c3f012026c1558d59b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 15:24:44 +0000 Subject: [PATCH 2329/4969] Bump logback-classic from 1.4.3 to 1.4.4 in /modules/hivemq Bumps [logback-classic](https://github.com/qos-ch/logback) from 1.4.3 to 1.4.4. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.3...v_1.4.4) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 3d6b653f6d1..796099b3a62 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation("com.hivemq:hivemq-extension-sdk:4.9.0") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") - testImplementation("ch.qos.logback:logback-classic:1.4.3") + testImplementation("ch.qos.logback:logback-classic:1.4.4") testImplementation 'org.assertj:assertj-core:3.23.1' testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.1") } From 50ec3f9b1b2111388e9879bb973761f6a2a02330 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 15:25:10 +0000 Subject: [PATCH 2330/4969] Bump logback-classic from 1.3.3 to 1.3.4 in /examples Bumps [logback-classic](https://github.com/qos-ch/logback) from 1.3.3 to 1.3.4. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.3.3...v_1.3.4) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- docs/examples/spock/redis/build.gradle | 2 +- examples/kafka-cluster/build.gradle | 2 +- examples/linked-container/build.gradle | 2 +- examples/redis-backed-cache-testng/build.gradle | 2 +- examples/redis-backed-cache/build.gradle | 2 +- examples/singleton-container/build.gradle | 2 +- examples/zookeeper/build.gradle | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 7405154491b..6c2b6a81c7b 100644 --- a/build.gradle +++ b/build.gradle @@ -125,7 +125,7 @@ subprojects { } dependencies { - testImplementation 'ch.qos.logback:logback-classic:1.3.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' } checkstyle { diff --git a/docs/examples/spock/redis/build.gradle b/docs/examples/spock/redis/build.gradle index 6699788d026..390bc06be79 100644 --- a/docs/examples/spock/redis/build.gradle +++ b/docs/examples/spock/redis/build.gradle @@ -7,5 +7,5 @@ dependencies { api "io.lettuce:lettuce-core:5.2.0.RELEASE" testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5' testImplementation project(":spock") - testImplementation 'ch.qos.logback:logback-classic:1.3.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' } diff --git a/examples/kafka-cluster/build.gradle b/examples/kafka-cluster/build.gradle index 5212bc33fa9..46c562bac84 100644 --- a/examples/kafka-cluster/build.gradle +++ b/examples/kafka-cluster/build.gradle @@ -13,5 +13,5 @@ dependencies { testImplementation 'org.apache.kafka:kafka-clients:3.3.0' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.google.guava:guava:23.0' - testImplementation 'ch.qos.logback:logback-classic:1.3.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' } diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index cf3a3331cc3..08376fd9d3f 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20220924' testImplementation 'org.postgresql:postgresql:42.5.0' - testImplementation 'ch.qos.logback:logback-classic:1.3.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' testImplementation 'org.testcontainers:postgresql' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 2e4bda4fa74..5dba21e1c26 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.9.1' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'ch.qos.logback:logback-classic:1.3.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' testImplementation 'org.testng:testng:7.5' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index eb684158731..0d19207f4ba 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -13,6 +13,6 @@ dependencies { implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'junit:junit:4.13.2' - testImplementation 'ch.qos.logback:logback-classic:1.3.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index 449fd9ae8e6..8ebce1bfb77 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.36' - testImplementation 'ch.qos.logback:logback-classic:1.3.3' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.assertj:assertj-core:3.23.1' } diff --git a/examples/zookeeper/build.gradle b/examples/zookeeper/build.gradle index f2c92eb3b1d..d18be942ff0 100644 --- a/examples/zookeeper/build.gradle +++ b/examples/zookeeper/build.gradle @@ -10,5 +10,5 @@ dependencies { testImplementation 'org.apache.curator:curator-framework:5.3.0' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' } From 46b6cd9bf357a96e01d8e48cf241250c816bb1f3 Mon Sep 17 00:00:00 2001 From: Benjamin Manifold Date: Wed, 26 Oct 2022 06:50:12 -0400 Subject: [PATCH 2331/4969] Update gitlab_ci.md (#6063) Clarity around the port number for unencrypted docker host connections, as most gitlab DinD examples recommend 2736 without explaining why. --- .../continuous_integration/gitlab_ci.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md index b4571403654..f2226f2d34f 100644 --- a/docs/supported_docker_environment/continuous_integration/gitlab_ci.md +++ b/docs/supported_docker_environment/continuous_integration/gitlab_ci.md @@ -46,7 +46,7 @@ services: command: ["--tls=false"] variables: - # Instruct Testcontainers to use the daemon of DinD. + # Instruct Testcontainers to use the daemon of DinD, use port 2735 for non-tls connections. DOCKER_HOST: "tcp://docker:2375" # Instruct Docker not to start over TLS. DOCKER_TLS_CERTDIR: "" From b0af2f41f98a65f06cb0245a1d7d431db1b7a22b Mon Sep 17 00:00:00 2001 From: Leo Date: Thu, 27 Oct 2022 12:22:53 +0100 Subject: [PATCH 2332/4969] Add language links to docs index (#6067) --- docs/css/extra.css | 39 ++++++++++++++++++++ docs/index.md | 16 +++++++- docs/language-logos/dotnet.svg | 7 ++++ docs/language-logos/go.svg | 10 +++++ docs/language-logos/java.svg | 17 +++++++++ docs/language-logos/javascript.svg | 4 ++ docs/language-logos/python.svg | 8 ++++ docs/language-logos/rust.svg | 57 +++++++++++++++++++++++++++++ docs/logo.png | Bin 84934 -> 67366 bytes 9 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 docs/language-logos/dotnet.svg create mode 100644 docs/language-logos/go.svg create mode 100644 docs/language-logos/java.svg create mode 100644 docs/language-logos/javascript.svg create mode 100644 docs/language-logos/python.svg create mode 100644 docs/language-logos/rust.svg diff --git a/docs/css/extra.css b/docs/css/extra.css index e97480c5341..a89eebc9b24 100644 --- a/docs/css/extra.css +++ b/docs/css/extra.css @@ -9,3 +9,42 @@ h1, h2, h3, h4, h5, h6 { --md-accent-fg-color: #291A3F; --md-typeset-a-color: #0C94AA; } + +.card-grid { + display: grid; + gap: 10px; +} + +@media (min-width: 680px) { + .card-grid { + grid-template-columns: repeat(3, 1fr); + } +} + +body .card-grid-item { + display: flex; + align-items: center; + gap: 20px; + border: 1px solid #C3BEDE; + border-radius: 6px; + padding: 16px; + font-weight: 600; + color: #9991B5; + background: #F2F4FE; +} + +body .card-grid-item:hover, +body .card-grid-item:focus { + color: #9991B5; +} + +.card-grid-item[href] { + color: var(--md-primary-fg-color); + background: transparent; +} + +.card-grid-item[href]:hover, +.card-grid-item[href]:focus { + background: #F2F4FE; + color: var(--md-primary-fg-color); +} \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 383f42c0245..ed365b2acf3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,21 @@ # Testcontainers -Testcontainers logo +Testcontainers logo + +## Test dependencies as code for your entire stack +Get lightweight and throwaway containers during your tests that let you test against any container image (database, broker, browser, etc..) using one of the several supported languages. + + +

Select your language

+ ## About diff --git a/docs/language-logos/dotnet.svg b/docs/language-logos/dotnet.svg new file mode 100644 index 00000000000..2fb163d4d40 --- /dev/null +++ b/docs/language-logos/dotnet.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/docs/language-logos/go.svg b/docs/language-logos/go.svg new file mode 100644 index 00000000000..bfcca48ceda --- /dev/null +++ b/docs/language-logos/go.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/docs/language-logos/java.svg b/docs/language-logos/java.svg new file mode 100644 index 00000000000..986704918f5 --- /dev/null +++ b/docs/language-logos/java.svg @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/docs/language-logos/javascript.svg b/docs/language-logos/javascript.svg new file mode 100644 index 00000000000..4c808b1bf68 --- /dev/null +++ b/docs/language-logos/javascript.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs/language-logos/python.svg b/docs/language-logos/python.svg new file mode 100644 index 00000000000..d06a313c96b --- /dev/null +++ b/docs/language-logos/python.svg @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/docs/language-logos/rust.svg b/docs/language-logos/rust.svg new file mode 100644 index 00000000000..89039333533 --- /dev/null +++ b/docs/language-logos/rust.svg @@ -0,0 +1,57 @@ + + + \ No newline at end of file diff --git a/docs/logo.png b/docs/logo.png index 3d8f03fa0cf0fb98578e83d9b2ff71de3ead11c0..88961b3e3f0c0520a48e91b06e353a73fce35594 100644 GIT binary patch literal 67366 zcmbTe2|SeT`!+tdP_h$A!&sA@Y{d|=B}5XHeJ5+#XU38xd&-`%)1s21q$~+#Us@5_ z8ZCqo#w`Eq9_s1&{=UEWeLw%_^XZ|Cxv%@auJb&P^Ei%klFUyS?B2O|CkzJLZDgo- z5(c9O-_qnW(Sk4g8!N5B7iNFMGeI!eE-vT~4J^Nq4+dj+;b~=jkb`2JCa&`B-pov&~+KdqLbkRhdK4dCy>aXkS;b|Bi=xP~$ z!pb?^+gaTOfz%Q@5~=~-z}Gd{Q7F{c=R%N1s3wB?z8c_r=%3{fLe!T8dut+epbHAw zn3@ae`UScQsmsdCILph+3#qEhDyS+rE2_FVI!OyD$}1|$$*ajJsK_WPYA7AjP*xDy z{tp2z80g}raZ>Nt_T|9eG!Y)b!TuU@av>ohvLQ;ceu3_C3hL_Wa`K9Dii$Ge6*56# z7lIu_WiAAX{C)>L*C6LWPyb*~zY9XpJ32b~T@2PlfW>azg|Gjgx4jUw{iMJ%lM8k9 zms60Hhwh5{LKo*huk*hc=tI4@i?f`okE^fih2S9YT7^Ha_4n`#_6zdx`(NJr&yW9g z0q}H9P5)fuzplmC_s=DQg7q(f+t_{}|Mk^DR$>0GawlDb{4NGMyXs#8%M^j`#$Q7> z(A6>6FVM=*&*%4Eng3q0kfO4zypW`+qqFA)=q3*Q^((G=j=`>)2x#AA6y#+TRjm{h zG!)e|6qF9iD{9EgZ@tvi&&AU%?7zKKNnS%q-|k@RZ9_aAXIS*Mnl7Fq^DyQ zTKN50SfSv{iz<;{`)*_o^ce1yF%+S38g7#+VenybsxxBY^KY7DAa*>>w3j&Hq&uaS z%oU1smZ%l$v|_btS@o(ZO+ff2ht;vGhaFBoK{3-A5naz7*ZcTbHQ+1r zCH^0UPFF=OlG@wN?J_x7<4BY3eWD}#LJCJUag#9i&ePM$eB)_cUHk48Oy3SX%OCyo zR6^L|dLZL_v>;>gGcC{K!*P3+m!5Y$5JQKJf5@=utTOL5+Ls59YsZ&HF$MfY&9ev_ zKlm9N%krv&&7zl|zm3>pqPLQ@92;kQdH%qL&V}$Mz3&OQxbDx4OI6m(v7zB7<3&fL z2*Ly{5u_f2VPaofhVe`%!Jj!Y+QN42RD$k_9 zE$Z<|OE3=kO#INdtK$!gDK;g$nxExx;QP}9-q)say&Dh66{87F9H$Tx29R_MttAte zI!~EK?poNDpcd`MxX+$7?O^ae%;2N?+SQw;<@}rU9}dMb7uzJ6pQe@1XVR}z*g@K` zFhpE4zb!+f_r@!Rd@{-WsP7=L_@QE^d4Yw{)M3e*fp*R%R6=E9f)_9ARD;EXq)?kG zJjy(}soL%HJ)_ezof@-W7?Ums^A5n_6$ccIf)TKchp-yDcXnWc`A006pojk1D71&QjdOo|8B;)s@!MGwdOnlfMwGWnIkiL#b$r z3g%u_UdmoO?8lP=u^Ym}Zc;SdvK+ifnsU`RBT;LQC$9NET-t_pq2W!Uns|d%rZ>F3 zY`2EFZuUyDFCi+BSvFUDYfd;1VBh&jPrZ77)Y>B)fxP#GgH-%r$uGjm*j;ji6*j~~ zP^@*9!edcd4|M5CC$FLv@AG}F#E=D#wM#RwPqTWzbj%DJ=pBtq7?5vH*X6_YpWXTF z(mp@U$x<{gAt6E|SbcJwy;{f8F6yNBFntemo{A-Nv47J2b!H&}T~53DO2yr`3`TVJ z%*+~i#*nM$j&2AG;L^SNXfxgENE=%Di2b)d?C)c9>vFrBY&>JIYRLEC16!jSQe9kJ z523={0Bh0mP#HnDR_Br*zjynJE`7;OZq?A!^(M-ty8gT4E&`I-v)uD;T**j$OalFcN5pmA|9`s$pG;KT6zmX^yLZNN#^8`UN5)3>b+{rk^?(`$w-GV2Fn_!pPUzyP z$(L5YPw0%yG7kC1hP;XS<+8{IV2U0PG@C>Jl@ymu zKbOzdB=RZ3Fz~2+U+0vtr#}Ysa;<%FenLU0Bo+Odv2*~dFjW@$^ND7#nmK;aIN$ag z*T(|!U2a;-+wmYxBa|dBpqsCT1WRSCg&XUvF*4(^neZ$6Ym8417A(metgq@-4mp>J zU36}MzqXjNRG8A|h1uk=R8yub6g2$<2(irpUx!Q3c}C*4DJy12PbcJb6l+VAziEww zP2PCAdR}S0NPYmBVcyQh@X;Z8a_S*S^rZ&>+)Pm~wkFiFM?+CROmlrmesX(D!% z`H}ug?2sot^P?-nTurJ5YhN}!u7p;*4HlmqASoDKXow72jnyxNpBsR48A()zSLbNg zNfXRQPnJ;d`QU%Sw}x$I2AlowaB;*RAjW;;4NC|_F$KN)^7SWfB8p=dN&P{F?jDIx zr`oj9Fprz5o__gbC%s>41y=T2(XvY%bsn(qvtHuDwEI{QTi9O74BPZw{A{PcmJSzF zE@vi)AS!tBZJgA*GyP5_nVk(1A(Tih&EGU7nv-dTcuDDe@w>8jdk&)AMkw5udMzn8 z5(k*mTLzFz6Y8ySP0S`Y>F`*KB!2C~;g*G2OAWT=0sBrGPE_0J;=Y@ibH6HIIp=pc zV^#l2S}x9pPTg;U=Ut3hM=N_c6hw=1J|o4U2pP@@?nxP`1URu8jB?lTR8GA_X!lesbA?SEs7SHBRUckC1nSs@3&2;>lVc0=(;26j5p`Nc=cudZ! z8XkLO7yg#?kv;g++7!?G5j*kNa($iL*GLw7q-Yu;dUQRcRkPt6oXH4A(hZ#JgPH$? z%ZJh4fk%_uX@pQoX0#`6r0hS9^`aX`_H$yNh__8iVDRzsM$}|k!;CS;YopHxfnu4w zV%f)u&3yq9>BBR<8?Q1K(!X-tdNj%gj+L1&;bEEu#;}Jz?zM}Y4sk;L2ZEOWsuKax zdo?SiL2@Nwx4CM`qON8vha-M5jxxP^Q8>cJ^5>QD)iuKU-WXSH80o|2j{O7)vdFWu z_{E#Si!92iHD(ul^An#S{ytmP4ux1Er?$~NnJC%A_9Ot6qJw^(4%O}YgoXaK+NTdI z?skE%Tg$2$Vq<4&rRJrbvtA$}g^eX%!y)OuHvde|l9wLJ`8@qtyWpL1Oi?sf%sI4m z3EPw|Zh~#iXNNg#vv>8qpx1WVFh_hHlI?MQ!mP?Mf322gSCUSnNG`8|0`Cf zwMFua#2pnIj)x<*hrbR#8YZ=#rIkDjo%4*`RAa= z@8*1UxkNZue?q9rBnI}HD@GgLc9fEFRO(LVTp9syp)x>HqLz=TRP-p9wo1Ho>1J8D zp5U@E%)?u|FC8i)vS1~PmM0pK4~{DFY*=U>eROG)ntx8ksakN2>AF|~PgGy`V zaA+L9R8^G7C>3pZ8Xy3>?+JkeV1MSi;Eig-D%mOWlw86p`=BcQTcA+fH< zU#?u4Pfwn`NulRb%o#4BC}(jqopTU;vJcBwm~qs2jcv0v+QI$fQqBDa+V`ATlp~6e zFE4n6nK@^@T>NM`I^=k&a(a!~{^1dhP38w)e-@?^FIw+o>bln|y*l<3b1@AR@6N&K zm)DaXTb`OyvaY!be=Mi10zITyet;tZBrp&SN9;FLAET+RqFH`We3lTHudg@64s{g+ z&AIF(17@|G8%WTcPAG{bs(r`Svs^@l_=KTM=jH0p!QwiH~gD zieo~&t(#c^d_!!yt4ow`>mz74dwAN$w;h+P%70R-D}OCPoejfg7qzqTPm)*dOQ$9g zPGLEtMgN;JcBUD7xcJRrM&WT@$#aaRh1ebCo89kUi%uEwzfNC}bG*$RjAph2h($N8 zL8C5_c+nGYmT}tim{EP(Ny>P~R3M?qlAZNC6Jd?v^V$)@TG(OK7Z^@SQ0U=3w(ksh zqZU?}^1EXIINDlFDH$|2r^xtjBY%})QpqGU>|N}8sd{*D0P3|7KtLe*JQD_8$gL-z ziN#4PmOC4fiBV~UlKoBB>auqXX04MSKkgbqO9ZOR3Y8vs5zuxKdG1W{EBh1c*84hz zQ!)oSniI%*o%jbiV}sv!)6B(TOxEtD-VU)2rtIT_4z5bPGPu;4sXB098QK*7jaGnB z5w(pV*-15`?|h73(N#B&oa5c#=*9bL9&>%5lV`%5Gc1j`8ee@T=X*SPb;>G!07)zR zESdN&K6{kyn3^c}P2HztvdKd2S@y5IBOAh>Q_(xuTPMhCi;Vk%D84mjd+m_V|0ABU z@arJOah=J4aqjk9)`6IMr_BrkKZOA8E@Qk+gw%4Bws=;WIO7oYV%752e;+<+&9^$LZy{UAgb&y!*% zJ?*vd?pBxk=>|BlT=`}LCjbC8um+Es^|A?!v(93P4k_AjeAt0msKXqE0#(310DuUa zzQ7qfakk)wriT?{_iiqcK!U-KND%{+t`IK@r={~BJZ$`cCxfu~bB_WZ&K|0U?>9c< z+xkvA_+ZOY9*N#@)qI~>=|eJ3kWQmr@G~q!d}wSiGKMFZlJYx^{1vUbpE+S})$dUQ z`fI1pmLwhKNm;-S)|`0m`tsMqylf%`Pc6OOh|lg3mu+-?ZooM&lg&j; zYfQ5`-llg}VI7rnVWnO_PQ+a{gLO%2a`0LyUQnMWFN1ik_ds=}F7$i9r6&z)jj_qA zW{V(=EdfJebN-{^EnfbUJCQC&+hz*hh-uXd=Z$@xvAb1$^*$_vVRq=BQ`k})vdCtE7^GGRhSdh$1_Y5p8h?N;h=&e5nGR z!7~}xr2c*LuV zZs2j4&@WxEM;RhtI{ENlHXY&vpS}TEb0vzJN8bNPxYb@&WoE}ER%Udotf^8S`_WXCPv zBgh$$&-5ChE`5nk&Ik_9Z<5yr14ddh=Xs$UN2anU55cTzFW2EF^Zg`7F|8LnZ}_7V zuA-ZCSk6r>8WDM7UR+;W+5`L47QL=YFF8IDG4~EvSv&o0*hg~dX6k}p#5R7T=j=^g zv7|zSe9-EH+lS&ujG=6ECI68A5v#g5c;Gbg{Y=7d440~pIvzB{k5RTCB34rle1C08 zDZ@>)Mj(>u9a;`EH`3@+SVdL`(H_&-S(2rzXy`3JdHw{}UE{J2I5KP!O6T{?Zi6J5 z%an|TJx~zs@ST-j%JZg`%!UUKk^ppFuo@(dy8)1NrX=qQ@$VDSCNOwEMXKq^aI!Rv zY1!CESVqGvnast_amP*y5BD5wwmqvovxk{I!=GrhewY;Z46S`;Q)_RZ>bUf~*8SDce=n=7t!-;@fLfubXDFfLw>hZN)f$mH| zye&INNlW>9N-vk?%lwK}Z$v5@+dFYyROH>@Srik$EPjcmIF0NaJ~@SFL{E=YX;Yj; z_DizGEj4+~EDC7gx@U0gUlK$INV=NOcw(m44>Hcx!%9-%3Gz97xJ8(@UDVKf!nKZ) zO_8f7he)a7ut6UH(X8tH%~2IHy<#w{bn`#Fp{dZ6o;tO)b@e$VrZqjHQVPE_N8Iks zLX)0!!8ayXC$BuTec~xuOi_NX>HM{si=(5Mfe7bJDsta2+#cF$?v-7jlLA)ikcS5G&@>mA7m42=&)Kh$TV z$%+d(dbl)uL#bKRtpG#5QNC8fdrnlFn~>0`aK8u<+PJgWfL`9(ta!vRo1K+zDK=X4 z@o5;V+M%J5Ps*Mkb9|TRy2XDSX7T6}wTA}btGCuk6e_7VhAEUuuf^&IqxDJ|3C^6! zQU(7|d;9{KqcRg`Nf}1ka|Lez1LzQPS=F)qcAc$d3FTpqPx#!PtM-wFeXA+!3GJZ6 ziHUH?p%Fd0=KgJMQ&Q{bs&FepIP{KR?k>HYT{WhH)A?10l*cE2K`Bf~K_HWQ{|uKT zFl`$;T+{@5)Az`BrzPfdJ!^qY{nJ-v-i@%{K$<6gO()(t5e`xh0|O!b>7-se>!)`~ zOyj5b5!Muaq6$YbSE>}u`FaabBV9cJpEwWZ9pU=K$-H5!U zvY-xowKK4i+@1GXg8wDHCxV8+$aH<(g@9?cgHJ~JNvD6GN6^L`~PZoVdS8?bRTQcL`|t;H1bTq5Rp0ki52#VHTK zWBG{lHbH`Q*A)o;g#x2d?WA(FbqAb=x))IXZFMe4h>U2G*EFGW^t zvHDOxzxif{5%gfgJ{(ZBF*uY=YB3oyKv|_5*4Vb+4mwIh$dTvd7dosrV3tWprwNbr zFPES(e)M^;nM?2`XYAPOQS)D&3~Qnfzrc_EA`8M2)W)u21mApAE_tR^A+>bVp_)b= znU9eEXz-m8Wq2X4vJlE*)i`p|$K!7|0KaqZgH3x@?WybQ<${V!x~HawEpPwq?0wo^ zr7c4PtFF?))4$;=`*dBrdXH0xbs;Nhc$dZT^dHik->U?5D8jxhE)tFhWgo8b?2v?) zUPPVs97t6|VKKxPV+Z|hy*g9xnbkdPcUPyjc7J0sU2%*PDDdNG`Xu=?R-nH;b$iCY z;EAkMCj5RcUz3PUbKj*3-f+o^v+EI-M*$#Xr{_eI;wKxk{>MgT}#w#J#u@Oo4Uk{_K&%zJ-Ha z#~gra3L7!%21}8t*z8V``a_edA!iL?msfNz6auysyBN#=x{J*s8YI={>EnNs>Pih= z=^k&nm&|*UP}SYXB>?=nXVlv`ape1nw#C}P;MgJ##X@-7uT~W@zh;Shgo53AD_!e8 z`_%3q0kl!lf|8;8a_P)P9tEu4{9&5KfDN7Lb)cP$cwYz|kwiCVfc?srrI*ftQ=*1U zta3L+w7+q4?h?-~i<9vUM&Hd+=sM_ru)*&66R<(Q+hDFOWQKS|0DGiAT$@LLJA`l$ zLPC=r8_^i@lSQ5C-1J=}=D=6?KJyo{unrT9=n0J7ES&)@p1%3=&%+uoH6n9OATb1B zkUy=IWgoN%?v#alkB@ShNV}^qgRGY1UH^)04vOVp?d48gUiDRTb~j#e3*~KW;bN{V zbg4^GZWB+UZfxd@=bw=Dk{Grc#(l+aq9q@@Gj0~b_k2j`-f$Mviq=|sSFstQZ00B4 z`57zpyT~4-ae#!5e~=*CYuNd<2Q4izu7^xJzqMeQZfXB$0bB3gHRY z8T;2(dEOeWtk2DNzUdGi?yuhxhW-tg3u^iUWWXJ z^&L*^-20;H{h7AT*L$xnz{-zOl6DIs24c^pq4*0$WzK$)Z0(E^9NBQR=Hn>e|F(5Z z*54I1ZWjNZD{M-xZ1`EKc7BJ7=>`11+44DjbiWO4hDlsgyE(*qJ}dwPS|FfUAkCAS z+E${NAgKwJx0X-arD%C!pMW1^`1lj3f0^6>`Lu{NF0?7l9>CM zLS*-~4nhT%1LiZ%>&Gu${k63bsq)ohC7WgE1{g3sVztUVg5{|u?%(e-)++COxVsZ31e!IL@;4s z*{*wNR2RUm_vb#IJUs)x{zw3Hj|itGl);MxKpRt@7D}YW6vsP#e>xQRgzLL$VfcQM zLBq<;dmBas^kwbu0YS8m^n^`KT^1B8f$L|YrZirH{TPM3pmlHHu*PvO!PR-7qb&6o z{pqQJ?xiSSzNG>H;g2Ip9eUb;bOWtXZS{k^+Ag`e3CI7H>uyiG584{<4i@1M7*M_1 z<5@XyB{>|8=oH?BJwc#vxNbI1o@S z-3CJ2mqT_ffhp23=@K${9D+>;A4ocsARpo6&k2T$5gp`&zH>PK8k4IbEFy`?fdnJ% z?@I}K#*wrw)b!17{hRZqM#h6gNCUa((L#?&1so*L_=IJFQTz1fwXB8oI|FzdmgM~Xu5|W6AcEN|S5~oA`_j&IlBrpj`;0*2AVN9CM zs`R912N?QE6|=-7zwVN5=3ntJm>OuJomNt=EMT4gmbVHxF=qiYX{U_524oq-JE#ox ziCdi5S}%b98jI0=Nk${DY-Ub3<>WHpJAL&@#TmIo23XQ!dh#%wm}^os|1Thbcg zlSnU=p9;wS^w(J+BClkFqsmxuJt@w%fYVWBQ;-^sYSjP@R@HNWCi_2-mw8Q8gT}Yd z4T{4YD#3=dz%> zuo(l=m**_3pC)u9l1k7aCPjM6b+`%rZwu`MjheF8Bv|kXlNWJk9JKI^7>h^sOT7{g zGp47IKF3UjX}bQD&y4o$nw!UCp~KKcZ!V3*m2QsaGfl@sgudSyeN<88K_%n&pgrX7 z{fnwT!c|`-2D&4&bF91clwD%Tv5a9Hi<)=o^(oh4;5?R^NBkKZ!`Ol|Cqta&qpEdt zIpRRY0AzlWa)>h4|EzChk3{cXPh(i*Ka|E_JrO7mM9C6iO`slvbsWEA9S~l6;$Lr4ItI#yKP+f zw1l61x{6^H##^-YINC4jj(jXgQ?-~H{&N@<1VCV3#k1yoeDH>zq+n4(h2=>r&QXYz zozl&3UR~^>GSa1+owsB(fKs)^`ACCg?dz@{UK-wG!+=jef0X7K3xO@H|5=L;T8cFl z!5%|qKhn^RhCk5xu-S8}&4)5Px`SqXVo!sL>Aus84@=wKsR-^PXNf+ucAGUImCWDL zV?20o_4Y$HlX{7^>Xv2TVE~jzht~x)qz6diF$-)?SXGsAY$iPd&x%R0Ze@>Q%AAnq z?@C?C3PPkj@BhCcDNa<^l@%_IpTODiQlyxiAYmr#5Xz?$-l!kL4(hZI zak!Ofd?KnF6VbSTvKW287e2C4a*)ZEyZTtZ##f1lDyB1)*DeC~bA7+cKLRtc8mz03 zvpqu`Il~AnP%2_aK?d4VOL=#1C&g~n(@2~4jX?&ILZ-3Pl-Rro@|Hol^`34E1%)Nf zBg+znG>MYe6uJx2$ghZ9FQaPMuVJ;<+*i5S2#mL3I|!R5mj_zy=M>Hh;};i}67FOa z@5en3uVVghaH{MejpTx)097;uyq0@5QyEoZ0y{F5FEB_|l55)F?;I|xCSSN%nL^BD zfZaWRogkM)t}T*XjQ=+0|M~_D7u#&skGt5W$t=|WYngY4sNPx?uOK5V&3o@V3*_L= zM)a}&;!7$K=ECTsON46L&h!AC0q2dIqnE&IP#)1jC3I_cXn*Ns%@{TO_Xpx*a_tX zr1-1UAFpC@L4S_YcA&Mv#{*I50g9TBzsc+L}u#y}R!^MdUTjWMUS?t zB}2B)tVm32#RRr(L(CAs=RBy812@jA*>$$f`hanylStsx*@D|tFB%Ar#$K<+W+xDw zrCsUiw1&knBXf%2oMvlHc-Hj2Vlge|R&^xV+waS#sN6mBn*{u$susbcxwT|X8h|p* z!*+Z9Se@>CQ}r@(=6JzPYP(A%udeHLd7lb+3|c%uicwF&v9*3_u#W80D$@nMVp_eB zQ6?3~czd3lE81XpqXU7g{7`ClV=n^v9L8=z;lF^6ab$YSaHr9*q7TP&>`ZmLgyy`- z(Hk!`b*rME`J&=ireSK@e&PdX zwrAsiWt_n;f6u6foq;7*Q!Mc5akgg1L(ATmJ=+&7*jkK!*e=0FiV`+kTN5ieyrax; z^Ko|HUzdZ3^r*cGG~9iV3YQ|@hT8<_oyW#>&474QVk+8LXb3nIdU-cX_64I)xJWM_ z{AALDnEG5_iZVAo-lWI9v0 zn%--6oA7uMkxoJ^C>As4cc^0Dzg4!FQ%bJ}+~rH-KlU+;-Zq_$>-7(hKnr>e6sots z^!RxGR|5bwEmyz&_1bM-1YKGJ+yHKy6G^z@#f`pTtscF+K+U+td6;mkx5VSG?AbFf zo-^gF$NhY7p42~Zvh}IpWQyN{k6->t5nxmqiQj1kx}*+-w0LdeilrDPS2%l9hiiO- z04)HBg#~X4vHMIS_X2xlJ=9=DIGt2*2?IIVCM^=KnTZ6xR|Cr6nhmnD0QrvnVuD`y zgA|ItD_kP-1V-!^d&&YF!4$1KRkVJ%QssHshMvhhS+VR2c3Wkrb@i4SE(Si4y^1v4 z-E07$uS6+B`bKXd{HclEEhrhs2^WwCFk68aeeFe1*;aES8q@4G!^R8aBZR~x_e5~= z9+P-cjJ{w_e~)YJXnDJY39OXFSHyN{XitpYj?7f_qQ0Q5czxkn2aq_bJd(_T!c{1y zRl!*j_fd+bJ>|g|+Zi!T^+##i%s%MWtv>YF%;bDnl;05+*4u$-UPX0@3a!YzYZo0f z0=$vl_e5}WlC^KC^~vtW*#shv%vlc@cHjX8$!{iftAiQs z3moCvc#;1t*lJ&KdMTQdueBJN!QSV7k6wTx?8rxW`uc{y+1h?s+k91QlrXal+dg-n zsMn7P4<8HzW2q;V)Io1jun%^GXX3Sa38Vm5WydBHH1sJJ2b`szqDPb8yfL&1HE^IHR(=3%6U4yqZbs*nrvo`G)Ark$w0V){lo~zc$aD$v-g_ObCuXC} zCFq0=MsRJwFp1z^3*Bw6LaGIuwa`@S_@0HfLHWYm-u$?U?mQ?Ws9xaz$rV=?BY{Z} zpYxww@gbYfy&waFOnggSI&nX3nhs^5I%B|52jzc2w1T3MxyynRJ#!H@Pj>=Izblp< zFR>6s*Xik<2J42HIFD}j>Cn385Ar0}zoigcX)(30FX7i#!|;o8yiB*T7k*@!+n?^b z#4H0=~dy z@A;tXFsFE%g@h(f%)@^+0$5T10}bhiitxP!3GzAHT-?}&jjK3*7-t>}4NQm$&(^$K z^L5TM9`+;e-`x;A-8~`9Axy*A7F^7P4{71I{FXZqSy~Z{&a-%F_FHfLQnin{#S3YZ z4HISYG>$V&AG>gIZ!9?y8#n}v`@pfcPfRN)nV9HC^|LJNIu8I8oymX^C4`*44RF^i zcm1&w-#9r-H+9$5{O<1;vgk9rMzl<@$g(|gK>k0hl405F(vc9_Xdm{bh8kWdh}mw= zIC5`nQ(!%Wd&=O;<(okW$S{3#{hwGnSWuA;D$=p<2_8H`^=54y$W#o+3FPNu9 zhJ!a&@SD9Wc1|E8#%o~20;^T8r9ZWj`uGo%xy9=0z5Gn|R*XXp+I>-)c7dU5f43pN z%en_}|Asr%U?bswGGJbmh9o|}#P=2b*w5p|Cpf#*JQsc`hwmCOcAN|5zmKuwZB@!W zvxb-jtOXTiTGO@w4g|8Yt-9>Bf;RWq2VnK(#I*h?wUAKfCbhgxA8s?bdM_aMM%RVK zb&e5;b)QZ==UV9dw97yDa|tK*1a6oioyoa~Fe^g#k4AS2_c&udq*4aUqlT(2LC^oY z6a5SD)Qe$UEU31*DZHMhVp3=^XJYVnM5V8k$$@bkpqO4+zeOyxwzsAWW$Dxlx zS?xzL$-p=V&@j@0jf7}&3oM*+mF|3IF)rY|Mn^1QGIPDZ8&uISGMVgd>MK+?>r5cvZm_pgU#tignsRJm2J-UeId*|6LeEOpIv7l%Z+EkaUvuN+tGnTZULNeD^WYUe%%3f z6{7);&qNr_74nUr3~PsU=L6gmku3)U&0x8-I%(5tzNT5?%Ki7REyyX|THo&aw^JAZ zvYT8On;Kx9d?$nci-h~fo_ItRG6;jAD8#xzG7y#4<<1LkYFt)FTH$sCOwolh8Imo+ z({&BkF>Sj{AM*#Ag4NzF%$}aHslo659*m(#EhvJ$r~J_n~8`6LBAvs zcy^6jv)^3rUALx+rdM-~jn?|rLAU@v%yv3lqU)LAwI7sf65A+Ybqrp3?x2-^dJ-Ea zTN{jKs-d^}iZ-9h(jx%Y5S$vma{>pKHjcfew&O?7F}HXixc`kp0EZm_+_;=Px}5*w zPOY=xz>0Fb4os3zUBth(%}9txb2e$~k|ibhO#9d77f^{un51b*t!SKFqDf?Yga+&3 z_5?CLV2Or1-&TpEANu4|J3tQ(@U-IeHxo(JnUQNs5cbqJgUum|Qe^&&lD)2Nci$cu zIki5$_s&nZ)tbH?H9zO9X%I~KHD&)z!g)qsLIi?yil~>fJB`lyn_W6l%zElb6nqg0TD=*ID&AbcupF?3_~?x262KU97=7k~Y|bx4 zG2HR;|M>B#8pU6D0>I0vQ9#WCi8ZIz6(EVO4kR6c)Gt7>u@9kVBRvz?Wjdf(8`hCq znKqN2tpjMbE7u{h@;~Kdt7`haG`su`*FP&NCfAD?xKD!!1PL*_sDu0VKL;zIQz$I^dRYZglQM6+|{}WCdY;t zyKnueWAnQmuZ{trGzWSZmIDlsj2;2S{ym=#a4YV2+#-k>fIAr$vG$hTCbPz+4P1_c zWN>J+WWPTO_a4`3kA1fo0<-=qe`9{RCE#PexS3Cp)Ks$5u|*Ri-)xEBQV% zb%?wjsAd+r$>t^rjdp_K2_V7n*hPI55Qb5b21)&62xKW0o+lF>(tznm>H+*K>n_r> zPg=DJ8_g5K#hZ-Z=p7cAQxMLFZ7Wr+lKQs{c%>g4bmwF>KL1edd-`+PlExvTpFBaF zs-QHkJ&7jkCY6cKN&Jfa)2pT4fR*q5&>nd0eg$xHUR2x>HtREc>A&-rZwXMN3|z`j zN!oL%%?GqM=wU52#6_v{L@d1lN)V3EV#52ySP1qGkLHUf_og-ddAyu;pXn_t)1P_1 zVmN(1zO<|~TIxluBQip%$14}Y<#izy*zF>8;}e0vRsnFcK5ESR7j*UJ z3AqocxlA!FHoU9I56s07&3fy z7bgx}xcAC}9HrNtrk_KlMAVD}x9D}L!tM(167p(Y%jdh&8+eQFOHipn~>e+|6wTSK!NKf8q5+LB~Vm z_Fk98oejA+mMo6yGOWKgCv%ve4xpn)fRV8N3$`%*@%|^(s@&7e3qE#<2Ja(&O2RS z@5xwL%wFey-(Bjv_<>TKl2*XC zsfWQ7@{5E;+vbJAPer41a%YtftSZeHp}t@DBM)bdhW|>C$lAZW9OYvS3)~u92b<7h zL=}1W-Up;TJ2=rx(7@m5%x_fQU%QMnRT7d1e(sF@3mJQ z_E+W~9gN&^7;KFt`E-rxOGHj(Cz};y?R`G6xm@}5?Y(cv$oElCJ%(mRzsMD;xE;6E zL=u11QC6qF>>#im()KiY?s^rHdY^K^B!K-QToAM@3SL0Pf!I~ZH2WS{t)jr3H`AMs zsM|_WGdYSbQp?_RM7?8~bsf*Te=Pb@-Z_q}&w(-DlP~11|9LXys`T=%g!cu0=ORDP zR$VcTA6-6o7}@Nlzc#>*_Iy>SO zGT^VzOrH^(I>0X_F%GvYnTO0<$MC=Hb~RwJeyf0H1bjk<+3}e>0gLosZvwTX#!T>? z@}nu@4Al^A#quasaP?Qg+<5Q`10rJZt&%eS-EC{>iAPE$W)VRv_C-o-jahExr=GjH zuCX&V`NhgK8k;o74{u$+^CC7mE6H$3%GFlbwuosFfB1 z9QEZ4#X(!03U$=EFlspdA_Q=Zb=(h%yb$s@8;=Y z^AZ@C=?OrO9JQ5D!H(gA(YLuuTIpLZ4gpD!<4Xca36JOJc5xd=lAXR~%RRr}Q3aAi z_u(qita{M!eil9)5^s+@w-W1z6nJJHLzNf$=!?CZMaqtgO#cK(g|i-XrFTA-4wJ%Y z+`8trCD?RM{;5NwKN2$OT^@uE$$(Lb*V*-Y9u~A2_pb|&Q!2&woCWtz8*$d|x%U@A zxg*V}iBAvdNN+!lMGku^@v!dj`8MDD4U3H=ES-kEz6xXSJ^E;4<9Db+GZp`10BO51 zP+WIxr^!33Ior+YX7Kj6NC)H5l^v&ms%v65Rp;)3OP0G6_OLIXm9lgCvl8Sb^Sl>M6OLzoAI!bcq#?t$Fi1njE}ag>L5}Q0G@b}+u*dXA{uiw(zxQZB8a(SqS263yh@Rk`_M5G49p;uBhE$B!pV zU_W0h%2N6_-?HH0JM|#DxL8}DIP5wY8RRgdj#Z|D=FZ9DvT7{YNHG3ERYX7r)iVQ@ zrBUGCpnm$W(U?k&a$@f4 zB?_l2X0P|8Ei4A2^nR7rfFQYdx<+1iEywRiZ?DN*VHmh-mEhx>-tW%Yhkbo=YTW3? zP#Fb~h$ZFBuzANIASwKx)Kz|f6k=;JM`9Q-t@P}t3M?jvXV$==j#T_7)O1rp_Ss_X zwPtTpV}$*uYhKr0L1DRFE?1U|P*ZRGB4>>j9blu}oET_M)9#_3&Ho*({ATij2^oC; zkFiI!14{mQo7K601(4HGVlk8-*d{1~KMlN<2EZ8>7f-%U*r%gd0K_yWA(TV{r z3*`xZW70tzMfD#5(C`kGP<#A^H`OgW)!xoF$OQ%gwguJpImWz|8c16JAJ+2WLcO~z zjXLS?=u!Ts2=4qI;Jb162G;&j8z;DE5WkKm8_0h@D6MNnq{W1{3FXk_jx+6jNIr+S zsH`bGLic|F6%QK_IG3n_BP_@1mjBN|Dt4;&{a)QLp}bgGAjdwstD&f*1f=@8!Si?h zQ98DNl{>-5Zl~5%pA$wZ@1BFrf$k7GO)!ZAV%wwCCz0AE<-$@;72D%EYmZ7iDj@#$%*wVe)@L``idJ zv+8(c^wFe#d!O;;mwVoF$1KQA+(mkJTvd0k)Z&x($02jHD6xw&U*w=6AE;tVZ-e|9 z;*8A{uoULhUI&zBY?2W|$K4t7xgm{5stSF~o~Iw8Q4fHU6Q4=k95ks>VjIM){c-?A zte-Bdxgdgnj?GE|T|B(+@BbVw8>V0?R>;&6n(YrxSP5}c-yi4mAKnU$YB`9=td#mtn)U4@J zbr3-F0b=95uwuMkCLDawh|6o}!(haGQbmP=cEP}>FM-bm0#d776LAFKxFfC~ZEB4w zp9E7t=)MP^;4o7UaHUxqCg20wmk<2Nbny&o=jgpbot;v#Z6U4#KU27fNkMC z8BQTL6=U1kKFvXSqWIv{Qq&#CoKit)Io|^f85bfUgIF$P8ldLlt}lSsjMe)omjIWZ zBK{OvHU@=y4(K zyG2s6bhe=UM1jdoy}H);vA?TaB@0OT+v(6sk_Q-s>qEW_+Gzt_~~`+c70kKc9GRY~!F zzm{{(eeU}{SK0xZ_~Su8#p(w8V8SaN2uNg#fwK2;fGWhZ7d9rZw93B;{#`x~H(6Cc_VEB{Q}4daI}B=oc@ISEUh{v^ z4rqC{3ma;P61_=*6I#*(M}pkEdpR3Xl$s%>g1+tljW~j^4wIbHNQUD0IAE249vVm_ zvbieWoGm@~KUm}aYcLbR=vgj9FD3@r0byiw0TKZaXg_db-Ap~6@0*|(?XGUX{SCkB z-}gkPKAUw{T6`25!i1s?g+a&5gV0roPHsjpFQUHF5lWBCr2OroC4MHj=$-hF3;z)` zim99>m$$TpfgT?O8kou5W}Uk_UHd))wXgTZM+_R4)dul@>%XwcfAwGf678Hzg6~~& zr{_YB(#flgs}Ql*jG8D{JUSY8pfd^LrLG7dz%_$T$Bo)Oc;rHOa{{BVd206J@js&h zhVxN3)58mr{s)7B*cZt4r4?%F-PPia0Pa)Y%VNYd-}+4o2_86jq`>r%nbcxe%3THX zX{+xe^xfs$^Z=QFCKI6oE|vPTDS*%|ChFq|ni)Y*AWVJ-%xZ2T)&2r+Jj6_JL8xVQ zaz0?QReK?F!Q=iS%+9L#$zSF56WK@MRi&RM5rg$9ZjCA~664@5Y$P-%YXkEHZTYnT^3bZDSuK0iPqN)*qCp3liiS~m_b;Pc&FmcH`L?|m}noD=)|+SyC#g0RSx!VVlkf0V$~Bq|m5 zO`nnUXKeUubbhJ*Y5Ro=3cB7Rznn3GTpxHRh*EFu-o8Gt&kQAB^e8%a{O&0|B%n!w zM@N?Q7vICNy%K?JjeLM+$3X_@;?dB&##gxv>FLS?hX7U0D?_|nMmfBES<>5bwa}8~ ztxraj==;_&1Zg`f%^n7Q<|#YO%IRFG(c^%QV-g2pXGANw2u%yY1*wV2_EnaS-a_Zk zbE9}+OmBYnSt6GU4Rdn+>PP<7{__nI?q83PlU>05T8CVXpSEc?nBcfh#cAm&Rn`<^ zgG(7F?>ql3H}9`}k+h__K8ri5emVMDFN31q2nq61+B`ciZ_A}ZKd(?e<3k<+78D|S z;+|$z;pr{E@LZ*}e3_YSe8>Q<6>-lrb4!(DfvuBSiYxguGI;k5*W;B-9VZzQlc*Wm z_lS}CjLjkGYhEKHZ@l}2&?w4jRJOWxMWV{BaW}OFoS4|t-u-R4E@Kr6eiF1I>%&AI zb#%L2l@V~K?#&gIe||!ivovqD!?tTg7tk4WhC8NW zK@%D7MgN-QP7UXzcT4xC$=i>o$O|7~GyZ3d#8^=u;JrtQb^%ckZ3w8Bp!5G3T-1Pv z&QSaT9io-L%5Yrb(*Jo|j#wkX{P#+;8oSjpP}J)8r4S94hJ5>a0Yw%vDJ>*C)uz2Q zO)Lw@`asaF6%xd>yZPja$Db>^HOLJD!QsX5{d1Hj41dH5b;Ld4S7#&o&Ku=l0z5;t zCe&$06>lRe`S^ZtWc+`8xlpwA*!zG&2dC9%Y*9Ls-X9Ta`y3zWA{9K2@2&gp5Bu!4 zcs%_d&%By=b0KK(2a(ZU-nR>?^1n;IqpNevjKL@R+oRDYoc**T=@zpYVD+(q8hprBXakiwxdzw^7Cj#@hAY=b@RV~D(L!-A-v9z+IQU#nhITvven(>G z*wdIwZZK$TV24LS{eEd?!qEHMuW`O}^x?ZX)C3W5r3aT6TPANvxZK|tEo)0Gyj!G- zU^L`GLHNM6ACLeb(hTh{pOB5FP`v$gxW@y(^3<1(S0&Yjy}S2Li8E>bxqNiOvau%n zmcpK(6ZGV;ZPv^6sk46?7EQJoF{ln?8V5S@r77l4{*Kz_WaS_KPp9$k4H;7^%t5o; z44GgWwX$y3688of%76VtTf}UJyT(doTI@UiC(avx0>8+gyxQzDcX4g<6A;RSGDpUi zff3lXiB~2q6p3!{z}J8|2ym#_|36s&KS<4Wmep1*OG2{E=MMF})r~*~?5fTpQ1FuG zqHwhqVdc~SxB3P)(~4E_Ed`%0(XG7x+n{A~9&Apm}(L{(R%||KeuP zUc^hr2?BQ%H779%*N1*p4!02{e_s!~e6}A~NooV=x4t!aXm8s>>@SgDa(CuCJ*enL zf7(77GV1I;E_-!uZ8Sk(BEubgJMaIR?%bc@9vOf2uTKDIV%nhH!%&@@t+9DBJ+wDU zkI>38e8ksxnriXa55?t9kW(-Xq440`MpJMEoDJ+C=ZfD)87okZ{Zpb0yU%{+_P;{V zi*CZWN*Dp;!7`f(C=9stH{}>M1Hd9sUuA)OQdcKS(CDZbbMhz5Uw4nV!;2asI0y9m z09W#s%{v7@TWd^H{B*(Ha#68F-oE&9W8vU$`g!#4N&QsaOmO5*nj_(+ zX5{ait&Jh~^X{Pp6!ud?dT2~(snDVmz)XU{1^WL1!2W9?sBz-{0$^8^a0!yF&Ol@u z&u06f^}LN}>?^is$Io2)yZYJNY{P2!gl1Ph8N5|6xfSC1z}1ymwWpDK*Irmz*c9Z* zr3ak-)o=W7t~wJ>pmZtlJPK^eTW_!243P7}66>IJY}kgQ?dYvP>@1*Sl{;#UT5mbmT|E^e_$eT&Is(FGr+a2J50#>iDrNv_n+8vDZ=l}a~f!} zUNWnt+`9sZ!od3U$Gx<=ixtMg5HBN!DV1=!U4FSh-bg@Bm7wqD&pGgY-oK3dBl)Mi zm+xf95S33jc(^JaRzqygGaQpnikl1CzyHX@PV9Yt%TX~wAvHQE9%IBFtoLFAe9c75 zN;x1<#E5?eg=|@9ispwYF^p0yETm<#2qz{D2-9ffv-tvUg+6g;-NHDEurM11!0T4X%D>z0gX<**#qe}|s|2Ki*g#-cv6j6Y z5k2yCX7iCOt>4GW3%<&}KD!590hh-iHsA4g03mHRv;WWqay!_!kr#p~8h4guVR+*05(FWWN$#q@wl zR}*)v-<=mO&N362uYhFB(0IFnxFwTt_`-#VyB=XBtih5?oImk;P0>vZ2cxiXnhRRa z#|UZG2{!mTbBlkkx-syXSsQhZ+lZT|;afJk6z2}m=+jz?S~}+V>-_&EZMeCWYwK^# zB@6g>?{#7rTG01D>kQ%vYK?x3o;4JR@m?Jg{=ih3yy1TBpBVpBa@#=>(ddb%+J?Qq zhlev;xXDLkzc&Tjv@7=LO>(nW?+>P(d1sw{aqE{%r?y#Sh{e|B`epW?Tz3e-^5agj z$)oaDJ0SqGTByBtW&&VEOIF4z@gy0?J33rxai`xUFo`MtwKOex0xg9S&W=gF6#y|b z#3q^ZO;HpYrs#%z&bfaL`gCu1Q5V0MlB1SrWB97%i`tjr%RY{3Aw4Y7W)XTo^IOA} zAtcPO78lmNQuG(Aiy$$&K-IGEuS!3seGRMNsfvha5(6zkZQwE#^UcASX9-(vBU9!; z`9iB&c-Iil;d^!JU%2Z5s?2N+`migdTo=%!WYFEj>DzWmkmgTPn;{pfayQgY3Vs;- z>s~#Qe#BxAclgYpjVb;4V}K86eL7G21LWB<{J0QvriXKEA;7g@@YOjBrJ$x{mhTMA zT`x~9(V~!bU9+LebKn`XYqvlk=ZP7s@9#gAI222J^>qmB%)$IhKLVcpLz|>9s2vyS zpo0xVTMbS*D9r2aUGaS$x;pwd^)P)INcYh-Zh1m~Q4drCZ6&?Pu(AzZ{L5!5u>